2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/pe.c
5 * PURPOSE: Loader for PE executables
7 * PROGRAMMERS: KJK::Hyperion <hackbunny@reactos.com>
10 /* INCLUDES *****************************************************************/
17 #include <reactos/exeformat.h>
19 static ULONG SectionCharacteristicsToProtect
[16] =
21 PAGE_NOACCESS
, /* 0 = NONE */
22 PAGE_NOACCESS
, /* 1 = SHARED */
23 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
24 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
25 PAGE_READONLY
, /* 4 = READABLE */
26 PAGE_READONLY
, /* 5 = READABLE, SHARED */
27 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
28 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
30 * FIXME? do we really need the WriteCopy field in segments? can't we use
31 * PAGE_WRITECOPY here?
33 PAGE_READWRITE
, /* 8 = WRITABLE */
34 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
35 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
36 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
37 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
38 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
39 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
40 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
43 /* TODO: Intsafe should be made into a library, as it's generally useful */
44 static __inline BOOLEAN
Intsafe_CanAddULongPtr(IN ULONG_PTR Addend1
, IN ULONG_PTR Addend2
)
46 return Addend1
<= (MAXULONG_PTR
- Addend2
);
49 static __inline BOOLEAN
Intsafe_CanAddLong64(IN LONG64 Addend1
, IN LONG64 Addend2
)
51 return Addend1
<= (MAXLONGLONG
- Addend2
);
54 static __inline BOOLEAN
Intsafe_CanAddULong32(IN ULONG Addend1
, IN ULONG Addend2
)
56 return Addend1
<= (MAXULONG
- Addend2
);
59 static __inline BOOLEAN
Intsafe_AddULong32(OUT PULONG Result
, IN ULONG Addend1
, IN ULONG Addend2
)
61 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
64 *Result
= Addend1
+ Addend2
;
68 static __inline BOOLEAN
Intsafe_CanMulULong32(IN ULONG Factor1
, IN ULONG Factor2
)
70 return Factor1
<= (MAXULONG
/ Factor2
);
73 static __inline BOOLEAN
Intsafe_CanOffsetPointer(IN CONST VOID
* Pointer
, IN SIZE_T Offset
)
75 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
76 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
79 /* TODO: these are standard DDK/PSDK macros */
80 #ifndef RTL_FIELD_SIZE
81 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
84 #ifndef RTL_SIZEOF_THROUGH_FIELD
85 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
86 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
89 #ifndef RTL_CONTAINS_FIELD
90 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
91 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
94 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
98 return (Number
& (Number
- 1)) == 0;
101 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
103 ASSERT(IsPowerOf2(Alignment
));
104 return Address
& (Alignment
- 1);
107 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
109 return ModPow2(Address
, Alignment
) == 0;
112 static __inline BOOLEAN
AlignUp(OUT PULONG AlignedAddress
, IN ULONG Address
, IN ULONG Alignment
)
114 ULONG nExcess
= ModPow2(Address
, Alignment
);
118 *AlignedAddress
= Address
;
122 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
125 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
127 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
128 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
163 // FIXME: All this whitespace is "padding" so the C_ASSERTs aren't on the same lines as asserts in other headers.
164 // This is necessary because of the way we define C_ASSERT in a gcc compatible way.
165 // This can be removed once we upgrade to gcc 4.3.x or later (which implements __COUNTER__).
194 // PeFmtCreateSection depends on the following:
196 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
197 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
199 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
200 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
201 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
203 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
204 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
205 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
206 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
207 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
208 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
209 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
210 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
211 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
215 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
216 File Format Specification", revision 6.0 (February 1999)
218 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
219 IN SIZE_T FileHeaderSize
,
221 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
223 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
224 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
227 ULONG cbFileHeaderOffsetSize
= 0;
228 ULONG cbSectionHeadersOffset
= 0;
229 ULONG cbSectionHeadersSize
;
230 ULONG cbSectionHeadersOffsetSize
= 0;
231 ULONG cbOptHeaderSize
;
232 ULONG cbHeadersSize
= 0;
233 ULONG nSectionAlignment
;
234 ULONG nFileAlignment
;
235 const IMAGE_DOS_HEADER
* pidhDosHeader
;
236 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
237 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
238 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
239 PMM_SECTION_SEGMENT pssSegments
;
240 LARGE_INTEGER lnOffset
;
242 ULONG nPrevVirtualEndOfSegment
= 0;
243 ULONG nFileSizeOfHeaders
= 0;
247 ASSERT(FileHeaderSize
> 0);
249 ASSERT(ImageSectionObject
);
251 ASSERT(AllocateSegmentsCb
);
253 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
255 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
257 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
260 pidhDosHeader
= FileHeader
;
263 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
265 /* image too small to be an MZ executable */
266 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
267 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
269 /* no MZ signature */
270 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
271 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
273 /* not a Windows executable */
274 if(pidhDosHeader
->e_lfanew
<= 0)
275 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
278 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
280 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
281 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
283 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
288 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
289 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
291 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
292 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
296 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
297 * need to read the header from the file
299 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
300 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
302 ULONG cbNtHeaderSize
;
306 l_ReadHeaderFromFile
:
308 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
310 /* read the header from the file */
311 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
313 if(!NT_SUCCESS(nStatus
))
314 DIE(("ReadFile failed, status %08X\n", nStatus
));
318 ASSERT(cbReadSize
> 0);
320 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
322 /* the buffer doesn't contain the file header */
323 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
324 DIE(("The file doesn't contain the PE file header\n"));
326 pinhNtHeader
= pData
;
328 /* object still not aligned: copy it to the beginning of the buffer */
329 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
331 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
332 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
333 pinhNtHeader
= pBuffer
;
336 /* invalid NT header */
337 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
339 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
340 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
342 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
344 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
345 DIE(("The full NT header is too large\n"));
347 /* the buffer doesn't contain the whole NT header */
348 if(cbReadSize
< cbNtHeaderSize
)
349 DIE(("The file doesn't contain the full NT header\n"));
353 ULONG cbOptHeaderOffsetSize
= 0;
355 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
357 /* don't trust an invalid NT header */
358 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
359 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
361 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
362 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
364 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
365 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
367 /* the buffer doesn't contain the whole NT header: read it from the file */
368 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
369 goto l_ReadHeaderFromFile
;
372 /* read information from the NT header */
373 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
374 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
376 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
378 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
379 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
381 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
383 switch(piohOptHeader
->Magic
)
385 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
386 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
390 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
393 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
394 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
396 /* See [1], section 3.4.2 */
397 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
399 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
400 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
402 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
403 DIE(("The section alignment is smaller than the file alignment\n"));
405 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
406 nFileAlignment
= piohOptHeader
->FileAlignment
;
408 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
409 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
413 nSectionAlignment
= PAGE_SIZE
;
414 nFileAlignment
= PAGE_SIZE
;
417 ASSERT(IsPowerOf2(nSectionAlignment
));
418 ASSERT(IsPowerOf2(nFileAlignment
));
420 switch(piohOptHeader
->Magic
)
423 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
425 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
426 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
428 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
429 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
431 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
432 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
434 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
435 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
441 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
443 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
445 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
447 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
449 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
450 DIE(("ImageBase exceeds the address space\n"));
452 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
455 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
457 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
458 DIE(("SizeOfImage exceeds the address space\n"));
460 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
463 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
465 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
466 DIE(("SizeOfStackReserve exceeds the address space\n"));
468 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
471 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
473 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
474 DIE(("SizeOfStackCommit exceeds the address space\n"));
476 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
483 /* [1], section 3.4.2 */
484 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
485 DIE(("ImageBase is not aligned on a 64KB boundary"));
487 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
489 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
491 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
492 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
494 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
495 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
499 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
501 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
502 piohOptHeader
->AddressOfEntryPoint
;
505 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
506 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
508 ImageSectionObject
->Executable
= TRUE
;
510 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
511 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
513 /* SECTION HEADERS */
514 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
516 /* see [1], section 3.3 */
517 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
518 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
521 * the additional segment is for the file's headers. They need to be present for
522 * the benefit of the dynamic loader (to locate exports, defaults for thread
523 * parameters, resources, etc.)
525 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
527 /* file offset for the section headers */
528 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
529 DIE(("Offset overflow\n"));
531 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
532 DIE(("Offset overflow\n"));
534 /* size of the section headers */
535 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
536 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
538 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
539 DIE(("Section headers too large\n"));
541 /* size of the executable's headers */
542 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
544 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
545 // DIE(("SizeOfHeaders is not aligned\n"));
547 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
548 DIE(("The section headers overflow SizeOfHeaders\n"));
550 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
552 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
553 DIE(("Overflow aligning the size of headers\n"));
560 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
561 /* WARNING: piohOptHeader IS NO LONGER USABLE */
562 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
564 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
565 pishSectionHeaders
= NULL
;
569 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
570 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
572 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
573 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
577 * the buffer doesn't contain the section headers, or the alignment is wrong:
578 * read the headers from the file
580 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
581 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
586 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
588 /* read the header from the file */
589 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
591 if(!NT_SUCCESS(nStatus
))
592 DIE(("ReadFile failed with status %08X\n", nStatus
));
596 ASSERT(cbReadSize
> 0);
598 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
600 /* the buffer doesn't contain all the section headers */
601 if(cbReadSize
< cbSectionHeadersSize
)
602 DIE(("The file doesn't contain all of the section headers\n"));
604 pishSectionHeaders
= pData
;
606 /* object still not aligned: copy it to the beginning of the buffer */
607 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
609 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
610 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
611 pishSectionHeaders
= pBuffer
;
616 /* allocate the segments */
617 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
618 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
620 if(ImageSectionObject
->Segments
== NULL
)
621 DIE(("AllocateSegments failed\n"));
623 /* initialize the headers segment */
624 pssSegments
= ImageSectionObject
->Segments
;
626 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
628 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
629 DIE(("Cannot align the size of the section headers\n"));
631 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
632 DIE(("Cannot align the size of the section headers\n"));
634 pssSegments
[0].FileOffset
= 0;
635 pssSegments
[0].Protection
= PAGE_READONLY
;
636 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
637 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
638 pssSegments
[0].VirtualAddress
= 0;
639 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
640 pssSegments
[0].WriteCopy
= TRUE
;
642 /* skip the headers segment */
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* convert the executable sections into segments. See also [1], section 4 */
648 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
650 ULONG nCharacteristics
;
652 /* validate the alignment */
653 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
654 DIE(("VirtualAddress[%u] is not aligned\n", i
));
656 /* sections must be contiguous, ordered by base address and non-overlapping */
657 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
658 DIE(("Memory gap between section %u and the previous\n", i
));
660 /* ignore explicit BSS sections */
661 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
663 /* validate the alignment */
665 /* Yes, this should be a multiple of FileAlignment, but there's
666 * stuff out there that isn't. We can cope with that
668 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
669 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
672 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
673 // DIE(("PointerToRawData[%u] is not aligned\n", i));
676 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
677 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
681 ASSERT(pssSegments
[i
].FileOffset
== 0);
682 ASSERT(pssSegments
[i
].RawLength
== 0);
685 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
687 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
689 /* no explicit protection */
690 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
692 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
693 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
695 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
696 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
698 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
699 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
702 /* see table above */
703 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
704 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
706 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
707 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
709 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
711 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
712 DIE(("Cannot align the virtual size of section %u\n", i
));
714 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
716 if(pssSegments
[i
].Length
== 0)
717 DIE(("Virtual size of section %u is null\n", i
));
719 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
720 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
722 /* ensure the memory image is no larger than 4GB */
723 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
724 DIE(("The image is larger than 4GB\n"));
727 /* spare our caller some work in validating the segments */
728 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
730 if(nSectionAlignment
>= PAGE_SIZE
)
731 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
734 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;