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>
21 #define MAXULONG ((ULONG)(~1))
24 static ULONG SectionCharacteristicsToProtect
[16] =
26 PAGE_NOACCESS
, /* 0 = NONE */
27 PAGE_NOACCESS
, /* 1 = SHARED */
28 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
29 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
30 PAGE_READONLY
, /* 4 = READABLE */
31 PAGE_READONLY
, /* 5 = READABLE, SHARED */
32 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
33 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
35 * FIXME? do we really need the WriteCopy field in segments? can't we use
36 * PAGE_WRITECOPY here?
38 PAGE_READWRITE
, /* 8 = WRITABLE */
39 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
40 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
41 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
42 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
43 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
44 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
45 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
48 /* TODO: Intsafe should be made into a library, as it's generally useful */
49 static __inline BOOLEAN Intsafe_CanAddULongPtr
55 return Addend1
<= (MAXULONG_PTR
- Addend2
);
59 #define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
62 static __inline BOOLEAN Intsafe_CanAddLong64
68 return Addend1
<= (MAXLONGLONG
- Addend2
);
71 static __inline BOOLEAN Intsafe_CanAddULong32
77 return Addend1
<= (MAXULONG
- Addend2
);
80 static __inline BOOLEAN Intsafe_AddULong32
87 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
90 *Result
= Addend1
+ Addend2
;
94 static __inline BOOLEAN Intsafe_CanMulULong32
100 return Factor1
<= (MAXULONG
/ Factor2
);
103 static __inline BOOLEAN Intsafe_CanOffsetPointer
105 IN CONST VOID
* Pointer
,
109 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
110 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
113 /* TODO: these are standard DDK/PSDK macros */
114 #ifndef RTL_FIELD_SIZE
115 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
118 #ifndef RTL_SIZEOF_THROUGH_FIELD
119 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
120 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
123 #ifndef RTL_CONTAINS_FIELD
124 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
125 ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_)))
128 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
133 while((Number
% 2) == 0)
139 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
141 ASSERT(IsPowerOf2(Alignment
));
142 return Address
& (Alignment
- 1);
145 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
147 return ModPow2(Address
, Alignment
) == 0;
150 static __inline BOOLEAN AlignUp
152 OUT PULONG AlignedAddress
,
157 ULONG nExcess
= ModPow2(Address
, Alignment
);
161 *AlignedAddress
= Address
;
165 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
168 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
170 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
171 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
176 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
177 File Format Specification", revision 6.0 (February 1999)
179 NTSTATUS NTAPI PeFmtCreateSection
181 IN CONST VOID
* FileHeader
,
182 IN SIZE_T FileHeaderSize
,
184 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
186 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
187 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
191 ULONG cbFileHeaderOffsetSize
;
192 ULONG cbSectionHeadersOffset
;
193 ULONG cbSectionHeadersSize
;
194 ULONG cbSectionHeadersOffsetSize
;
195 ULONG cbOptHeaderSize
;
197 ULONG nSectionAlignment
;
198 ULONG nFileAlignment
;
199 const IMAGE_DOS_HEADER
* pidhDosHeader
;
200 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
201 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
202 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
203 PMM_SECTION_SEGMENT pssSegments
;
204 LARGE_INTEGER lnOffset
;
206 ULONG nPrevVirtualEndOfSegment
;
207 ULONG nFileSizeOfHeaders
;
211 ASSERT(FileHeaderSize
> 0);
213 ASSERT(ImageSectionObject
);
215 ASSERT(AllocateSegmentsCb
);
217 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
219 ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
220 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
222 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
225 pidhDosHeader
= FileHeader
;
228 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
230 /* image too small to be an MZ executable */
231 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
232 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
234 /* no MZ signature */
235 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
236 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
238 /* not a Windows executable */
239 if(pidhDosHeader
->e_lfanew
<= 0)
240 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
243 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
245 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
246 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
248 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
253 we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
254 and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
256 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
257 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
260 ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
261 ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
262 ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
263 ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
266 the buffer doesn't contain the NT file header, or the alignment is wrong: we
267 need to read the header from the file
271 FileHeaderSize
< cbFileHeaderOffsetSize
||
272 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0
275 ULONG cbNtHeaderSize
;
279 l_ReadHeaderFromFile
:
280 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
282 /* read the header from the file */
287 sizeof(IMAGE_NT_HEADERS64
),
293 if(!NT_SUCCESS(nStatus
))
294 DIE(("ReadFile failed, status %08X\n", nStatus
));
298 ASSERT(cbReadSize
> 0);
300 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
302 /* the buffer doesn't contain the file header */
303 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
304 DIE(("The file doesn't contain the PE file header\n"));
306 pinhNtHeader
= pData
;
308 /* object still not aligned: copy it to the beginning of the buffer */
309 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
311 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
312 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
313 pinhNtHeader
= pBuffer
;
316 /* invalid NT header */
317 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
319 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
320 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
322 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
324 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
325 DIE(("The full NT header is too large\n"));
327 /* the buffer doesn't contain the whole NT header */
328 if(cbReadSize
< cbNtHeaderSize
)
329 DIE(("The file doesn't contain the full NT header\n"));
333 ULONG cbOptHeaderOffsetSize
;
335 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
337 /* don't trust an invalid NT header */
338 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
339 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
341 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
342 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
344 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
345 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
347 /* the buffer doesn't contain the whole NT header: read it from the file */
348 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
349 goto l_ReadHeaderFromFile
;
352 /* read information from the NT header */
353 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
354 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
356 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
358 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
360 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
361 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
363 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
365 switch(piohOptHeader
->Magic
)
367 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
368 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
372 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
375 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
376 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
380 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
381 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
)
384 /* See [1], section 3.4.2 */
385 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
387 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
388 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
390 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
391 DIE(("The section alignment is smaller than the file alignment\n"));
393 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
394 nFileAlignment
= piohOptHeader
->FileAlignment
;
396 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
397 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
401 nSectionAlignment
= PAGE_SIZE
;
402 nFileAlignment
= PAGE_SIZE
;
405 ASSERT(IsPowerOf2(nSectionAlignment
));
406 ASSERT(IsPowerOf2(nFileAlignment
));
408 switch(piohOptHeader
->Magic
)
411 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
413 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
414 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
416 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
417 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
419 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
420 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
426 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
428 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
430 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
432 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
434 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
435 DIE(("ImageBase exceeds the address space\n"));
437 ImageSectionObject
->ImageBase
= pioh64OptHeader
->ImageBase
;
440 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
442 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
443 DIE(("SizeOfStackReserve exceeds the address space\n"));
445 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
448 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
450 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
451 DIE(("SizeOfStackCommit exceeds the address space\n"));
453 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
460 /* [1], section 3.4.2 */
461 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
462 DIE(("ImageBase is not aligned on a 64KB boundary"));
464 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
465 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
466 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
468 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
470 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
474 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
475 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
)
478 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
479 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
483 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
485 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
487 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
488 piohOptHeader
->AddressOfEntryPoint
;
491 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
493 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
494 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
496 ImageSectionObject
->Executable
= TRUE
;
498 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
499 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
501 /* SECTION HEADERS */
502 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
504 /* see [1], section 3.3 */
505 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
506 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
509 the additional segment is for the file's headers. They need to be present for
510 the benefit of the dynamic loader (to locate exports, defaults for thread
511 parameters, resources, etc.)
513 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
515 /* file offset for the section headers */
516 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
517 DIE(("Offset overflow\n"));
519 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
520 DIE(("Offset overflow\n"));
522 /* size of the section headers */
523 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
524 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
526 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
527 DIE(("Section headers too large\n"));
529 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
531 /* size of the executable's headers */
532 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
534 //if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
535 //DIE(("SizeOfHeaders is not aligned\n"));
537 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
538 DIE(("The section headers overflow SizeOfHeaders\n"));
540 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
542 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
543 DIE(("Overflow aligning the size of headers\n"));
550 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
551 /* WARNING: piohOptHeader IS NO LONGER USABLE */
552 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
554 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
555 pishSectionHeaders
= NULL
;
559 we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
560 and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
562 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
563 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
567 the buffer doesn't contain the section headers, or the alignment is wrong:
568 read the headers from the file
572 FileHeaderSize
< cbSectionHeadersOffsetSize
||
573 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0
579 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
581 /* read the header from the file */
586 cbSectionHeadersSize
,
592 if(!NT_SUCCESS(nStatus
))
593 DIE(("ReadFile failed with status %08X\n", nStatus
));
597 ASSERT(cbReadSize
> 0);
599 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
601 /* the buffer doesn't contain all the section headers */
602 if(cbReadSize
< cbSectionHeadersSize
)
603 DIE(("The file doesn't contain all of the section headers\n"));
605 pishSectionHeaders
= pData
;
607 /* object still not aligned: copy it to the beginning of the buffer */
608 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
610 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
611 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
612 pishSectionHeaders
= pBuffer
;
617 /* allocate the segments */
618 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
619 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
621 if(ImageSectionObject
->Segments
== NULL
)
622 DIE(("AllocateSegments failed\n"));
624 /* initialize the headers segment */
625 pssSegments
= ImageSectionObject
->Segments
;
627 //ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
629 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
630 DIE(("Cannot align the size of the section headers\n"));
632 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
633 DIE(("Cannot align the size of the section headers\n"));
635 pssSegments
[0].FileOffset
= 0;
636 pssSegments
[0].Protection
= PAGE_READONLY
;
637 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
638 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
639 pssSegments
[0].VirtualAddress
= 0;
640 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
641 pssSegments
[0].WriteCopy
= TRUE
;
643 /* skip the headers segment */
646 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
648 /* convert the executable sections into segments. See also [1], section 4 */
649 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
651 ULONG nCharacteristics
;
653 /* validate the alignment */
654 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
655 DIE(("VirtualAddress[%u] is not aligned\n", i
));
657 /* sections must be contiguous, ordered by base address and non-overlapping */
658 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
659 DIE(("Memory gap between section %u and the previous\n", i
));
661 /* ignore explicit BSS sections */
662 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
664 /* validate the alignment */
665 #if 0 /* Yes, this should be a multiple of FileAlignment, but there's
666 stuff out there that isn't. We can cope with that */
667 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
668 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
671 //if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
672 //DIE(("PointerToRawData[%u] is not aligned\n", i));
675 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
676 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
680 ASSERT(pssSegments
[i
].FileOffset
== 0);
681 ASSERT(pssSegments
[i
].RawLength
== 0);
684 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
686 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
688 /* no explicit protection */
689 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
691 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
692 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
694 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
695 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
697 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
698 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
701 /* see table above */
702 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
703 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
705 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
706 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
708 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
710 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
711 DIE(("Cannot align the virtual size of section %u\n", i
));
713 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
715 if(pssSegments
[i
].Length
== 0)
716 DIE(("Virtual size of section %u is null\n", i
));
718 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
719 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
721 /* ensure the memory image is no larger than 4GB */
722 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
723 DIE(("The image is larger than 4GB\n"));
726 /* spare our caller some work in validating the segments */
727 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
729 if(nSectionAlignment
>= PAGE_SIZE
)
730 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
733 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;