3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/pe.c
6 * PURPOSE: Loader for PE executables
8 * PROGRAMMERS: KJK::Hyperion <hackbunny@reactos.com>
11 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 #include <reactos/exeformat.h>
20 static ULONG SectionCharacteristicsToProtect
[16] =
22 PAGE_NOACCESS
, /* 0 = NONE */
23 PAGE_NOACCESS
, /* 1 = SHARED */
24 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
25 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
26 PAGE_READONLY
, /* 4 = READABLE */
27 PAGE_READONLY
, /* 5 = READABLE, SHARED */
28 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
29 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
31 * FIXME? do we really need the WriteCopy field in segments? can't we use
32 * PAGE_WRITECOPY here?
34 PAGE_READWRITE
, /* 8 = WRITABLE */
35 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
36 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
37 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
38 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
39 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
40 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
41 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
44 /* TODO: Intsafe should be made into a library, as it's generally useful */
45 static __inline BOOLEAN Intsafe_CanAddULongPtr
51 return Addend1
<= (MAXULONG_PTR
- Addend2
);
55 #define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
58 static __inline BOOLEAN Intsafe_CanAddLong64
64 return Addend1
<= (MAXLONGLONG
- Addend2
);
67 static __inline BOOLEAN Intsafe_CanAddULong32
73 return Addend1
<= (MAXULONG
- Addend2
);
76 static __inline BOOLEAN Intsafe_AddULong32
83 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
86 *Result
= Addend1
+ Addend2
;
90 static __inline BOOLEAN Intsafe_CanMulULong32
96 return Factor1
<= (MAXULONG
/ Factor2
);
99 static __inline BOOLEAN Intsafe_CanOffsetPointer
101 IN CONST VOID
* Pointer
,
105 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
106 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
109 /* TODO: these are standard DDK/PSDK macros */
110 #ifndef RTL_FIELD_SIZE
111 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
114 #ifndef RTL_SIZEOF_THROUGH_FIELD
115 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
116 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
119 #ifndef RTL_CONTAINS_FIELD
120 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
121 ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_)))
124 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
129 while((Number
% 2) == 0)
135 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
137 ASSERT(IsPowerOf2(Alignment
));
138 return Address
& (Alignment
- 1);
141 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
143 return ModPow2(Address
, Alignment
) == 0;
146 static __inline BOOLEAN AlignUp
148 OUT PULONG AlignedAddress
,
153 ULONG nExcess
= ModPow2(Address
, Alignment
);
157 *AlignedAddress
= Address
;
161 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
164 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
166 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
167 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
172 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
173 File Format Specification", revision 6.0 (February 1999)
175 NTSTATUS NTAPI PeFmtCreateSection
177 IN CONST VOID
* FileHeader
,
178 IN SIZE_T FileHeaderSize
,
180 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
182 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
183 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
187 ULONG cbFileHeaderOffsetSize
;
188 ULONG cbSectionHeadersOffset
;
189 ULONG cbSectionHeadersSize
;
190 ULONG cbSectionHeadersOffsetSize
;
191 ULONG cbOptHeaderSize
;
193 ULONG nSectionAlignment
;
194 ULONG nFileAlignment
;
195 const IMAGE_DOS_HEADER
* pidhDosHeader
;
196 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
197 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
198 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
199 PMM_SECTION_SEGMENT pssSegments
;
200 LARGE_INTEGER lnOffset
;
202 ULONG nPrevVirtualEndOfSegment
;
203 ULONG nFileSizeOfHeaders
;
207 ASSERT(FileHeaderSize
> 0);
209 ASSERT(ImageSectionObject
);
211 ASSERT(AllocateSegmentsCb
);
213 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
215 ASSERT(FileHeaderSize
>= sizeof(IMAGE_DOS_HEADER
));
216 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
218 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
221 pidhDosHeader
= FileHeader
;
224 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
226 /* no MZ signature */
227 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
228 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
230 /* not a Windows executable */
231 if(pidhDosHeader
->e_lfanew
<= 0)
232 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
235 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
237 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
238 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
240 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
245 we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
246 and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
248 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
249 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
252 ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
253 ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
254 ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
255 ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
258 the buffer doesn't contain the NT file header, or the alignment is wrong: we
259 need to read the header from the file
263 FileHeaderSize
< cbFileHeaderOffsetSize
||
264 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0
267 ULONG cbNtHeaderSize
;
271 l_ReadHeaderFromFile
:
272 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
274 /* read the header from the file */
279 sizeof(IMAGE_NT_HEADERS64
),
285 if(!NT_SUCCESS(nStatus
))
286 DIE(("ReadFile failed, status %08X\n", nStatus
));
290 ASSERT(cbReadSize
> 0);
292 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
294 /* the buffer doesn't contain the file header */
295 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
296 DIE(("The file doesn't contain the PE file header\n"));
298 pinhNtHeader
= pData
;
300 /* object still not aligned: copy it to the beginning of the buffer */
301 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
303 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
304 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
305 pinhNtHeader
= pBuffer
;
308 /* invalid NT header */
309 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
310 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
312 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
313 DIE(("The full NT header is too large\n"));
315 nStatus
= STATUS_UNSUCCESSFUL
;
317 /* the buffer doesn't contain the whole NT header */
318 if(cbReadSize
< cbNtHeaderSize
)
319 DIE(("The file doesn't contain the full NT header\n"));
323 ULONG cbOptHeaderOffsetSize
;
325 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
327 /* don't trust an invalid NT header */
328 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
329 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
331 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
332 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
334 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
335 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
337 /* the buffer doesn't contain the whole NT header: read it from the file */
338 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
339 goto l_ReadHeaderFromFile
;
342 /* read information from the NT header */
343 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
344 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
346 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
348 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
350 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
351 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
353 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
355 switch(piohOptHeader
->Magic
)
357 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
358 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
362 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
365 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
366 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
370 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
371 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
)
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
407 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
410 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
416 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
418 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
420 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
424 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
425 DIE(("ImageBase exceeds the address space\n"));
427 ImageSectionObject
->ImageBase
= pioh64OptHeader
->ImageBase
;
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
432 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
433 DIE(("SizeOfStackReserve exceeds the address space\n"));
435 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
440 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
441 DIE(("SizeOfStackCommit exceeds the address space\n"));
443 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
450 /* [1], section 3.4.2 */
451 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
452 DIE(("ImageBase is not aligned on a 64KB boundary"));
454 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
455 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
456 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
458 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
460 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
464 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
465 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
)
468 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
469 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
473 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
475 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
476 ImageSectionObject
->EntryPoint
= piohOptHeader
->AddressOfEntryPoint
;
478 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
480 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
481 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
483 ImageSectionObject
->Executable
= TRUE
;
485 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
486 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
488 /* SECTION HEADERS */
489 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
491 /* see [1], section 3.3 */
492 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
493 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
496 the additional segment is for the file's headers. They need to be present for
497 the benefit of the dynamic loader (to locate exports, defaults for thread
498 parameters, resources, etc.)
500 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
502 /* file offset for the section headers */
503 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
504 DIE(("Offset overflow\n"));
506 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
507 DIE(("Offset overflow\n"));
509 /* size of the section headers */
510 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
511 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
513 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
514 DIE(("Section headers too large\n"));
516 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
518 /* size of the executable's headers */
519 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
521 if(!IsAligned(piohOptHeader
->SizeOfHeaders
, nFileAlignment
))
522 DIE(("SizeOfHeaders is not aligned\n"));
524 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
525 DIE(("The section headers overflow SizeOfHeaders\n"));
527 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
529 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
530 DIE(("Overflow aligning the size of headers\n"));
537 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
538 /* WARNING: piohOptHeader IS NO LONGER USABLE */
539 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
541 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
542 pishSectionHeaders
= NULL
;
546 we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
547 and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
549 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
550 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
554 the buffer doesn't contain the section headers, or the alignment is wrong:
555 read the headers from the file
559 FileHeaderSize
< cbSectionHeadersOffsetSize
||
560 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0
566 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
568 /* read the header from the file */
573 cbSectionHeadersSize
,
579 if(!NT_SUCCESS(nStatus
))
580 DIE(("ReadFile failed with status %08X\n", nStatus
));
584 ASSERT(cbReadSize
> 0);
586 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
588 /* the buffer doesn't contain all the section headers */
589 if(cbReadSize
< cbSectionHeadersSize
)
590 DIE(("The file doesn't contain all of the section headers\n"));
592 pishSectionHeaders
= pData
;
594 /* object still not aligned: copy it to the beginning of the buffer */
595 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
597 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
598 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
599 pishSectionHeaders
= pBuffer
;
604 /* allocate the segments */
605 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
606 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
608 if(ImageSectionObject
->Segments
== NULL
)
609 DIE(("AllocateSegments failed\n"));
611 /* initialize the headers segment */
612 pssSegments
= ImageSectionObject
->Segments
;
614 ASSERT(IsAligned(cbHeadersSize
, nFileAlignment
));
616 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
617 DIE(("Cannot align the size of the section headers\n"));
619 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
620 DIE(("Cannot align the size of the section headers\n"));
622 pssSegments
[0].FileOffset
= 0;
623 pssSegments
[0].Protection
= PAGE_READONLY
;
624 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
625 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
626 pssSegments
[0].VirtualAddress
= 0;
627 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
628 pssSegments
[0].WriteCopy
= TRUE
;
630 /* skip the headers segment */
633 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
635 /* convert the executable sections into segments. See also [1], section 4 */
636 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
638 ULONG nCharacteristics
;
640 /* validate the alignment */
641 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
642 DIE(("VirtualAddress[%u] is not aligned\n", i
));
644 /* sections must be contiguous, ordered by base address and non-overlapping */
645 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
646 DIE(("Memory gap between section %u and the previous\n", i
));
648 /* ignore explicit BSS sections */
649 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
651 /* validate the alignment */
652 #if 0 /* Yes, this should be a multiple of FileAlignment, but there's
653 stuff out there that isn't. We can cope with that */
654 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
655 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
658 if(!IsAligned(pishSectionHeaders
[i
].PointerToRawData
, nFileAlignment
))
659 DIE(("PointerToRawData[%u] is not aligned\n", i
));
662 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
663 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
667 ASSERT(pssSegments
[i
].FileOffset
== 0);
668 ASSERT(pssSegments
[i
].RawLength
== 0);
671 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
673 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
675 /* no explicit protection */
676 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
678 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
679 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
681 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
682 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
684 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
685 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
688 /* see table above */
689 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
690 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
692 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
693 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
695 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
697 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
698 DIE(("Cannot align the virtual size of section %u\n", i
));
700 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
702 if(pssSegments
[i
].Length
== 0)
703 DIE(("Virtual size of section %u is null\n", i
));
705 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
706 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
708 /* ensure the memory image is no larger than 4GB */
709 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
710 DIE(("The image is larger than 4GB\n"));
713 /* spare our caller some work in validating the segments */
714 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
716 if(nSectionAlignment
>= PAGE_SIZE
)
717 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
720 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
& EXEFMT_LOADED_PE32
;