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>
20 #define MAXULONG ((ULONG)(~1))
23 static ULONG SectionCharacteristicsToProtect
[16] =
25 PAGE_NOACCESS
, /* 0 = NONE */
26 PAGE_NOACCESS
, /* 1 = SHARED */
27 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
28 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
29 PAGE_READONLY
, /* 4 = READABLE */
30 PAGE_READONLY
, /* 5 = READABLE, SHARED */
31 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
32 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
34 * FIXME? do we really need the WriteCopy field in segments? can't we use
35 * PAGE_WRITECOPY here?
37 PAGE_READWRITE
, /* 8 = WRITABLE */
38 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
39 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
40 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
41 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
42 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
43 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
44 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
47 /* TODO: Intsafe should be made into a library, as it's generally useful */
48 static __inline BOOLEAN
Intsafe_CanAddULongPtr(IN ULONG_PTR Addend1
, IN ULONG_PTR Addend2
)
50 return Addend1
<= (MAXULONG_PTR
- Addend2
);
54 #define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
57 static __inline BOOLEAN
Intsafe_CanAddLong64(IN LONG64 Addend1
, IN LONG64 Addend2
)
59 return Addend1
<= (MAXLONGLONG
- Addend2
);
62 static __inline BOOLEAN
Intsafe_CanAddULong32(IN ULONG Addend1
, IN ULONG Addend2
)
64 return Addend1
<= (MAXULONG
- Addend2
);
67 static __inline BOOLEAN
Intsafe_AddULong32(OUT PULONG Result
, IN ULONG Addend1
, IN ULONG Addend2
)
69 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
72 *Result
= Addend1
+ Addend2
;
76 static __inline BOOLEAN
Intsafe_CanMulULong32(IN ULONG Factor1
, IN ULONG Factor2
)
78 return Factor1
<= (MAXULONG
/ Factor2
);
81 static __inline BOOLEAN
Intsafe_CanOffsetPointer(IN CONST VOID
* Pointer
, IN SIZE_T Offset
)
83 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
84 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
87 /* TODO: these are standard DDK/PSDK macros */
88 #ifndef RTL_FIELD_SIZE
89 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
92 #ifndef RTL_SIZEOF_THROUGH_FIELD
93 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
94 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
97 #ifndef RTL_CONTAINS_FIELD
98 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
99 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
102 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
106 return (Number
& (Number
- 1)) == 0;
109 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
111 ASSERT(IsPowerOf2(Alignment
));
112 return Address
& (Alignment
- 1);
115 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
117 return ModPow2(Address
, Alignment
) == 0;
120 static __inline BOOLEAN
AlignUp(OUT PULONG AlignedAddress
, IN ULONG Address
, IN ULONG Alignment
)
122 ULONG nExcess
= ModPow2(Address
, Alignment
);
126 *AlignedAddress
= Address
;
130 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
133 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
135 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
136 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
141 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
142 File Format Specification", revision 6.0 (February 1999)
144 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
145 IN SIZE_T FileHeaderSize
,
147 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
149 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
150 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
153 ULONG cbFileHeaderOffsetSize
= 0;
154 ULONG cbSectionHeadersOffset
= 0;
155 ULONG cbSectionHeadersSize
;
156 ULONG cbSectionHeadersOffsetSize
= 0;
157 ULONG cbOptHeaderSize
;
158 ULONG cbHeadersSize
= 0;
159 ULONG nSectionAlignment
;
160 ULONG nFileAlignment
;
161 const IMAGE_DOS_HEADER
* pidhDosHeader
;
162 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
163 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
164 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
165 PMM_SECTION_SEGMENT pssSegments
;
166 LARGE_INTEGER lnOffset
;
168 ULONG nPrevVirtualEndOfSegment
= 0;
169 ULONG nFileSizeOfHeaders
= 0;
173 ASSERT(FileHeaderSize
> 0);
175 ASSERT(ImageSectionObject
);
177 ASSERT(AllocateSegmentsCb
);
179 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
181 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
182 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
184 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
187 pidhDosHeader
= FileHeader
;
190 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
192 /* image too small to be an MZ executable */
193 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
194 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
196 /* no MZ signature */
197 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
198 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
200 /* not a Windows executable */
201 if(pidhDosHeader
->e_lfanew
<= 0)
202 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
205 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
207 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
208 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
210 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
215 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
216 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
218 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
219 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
222 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
223 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
224 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
225 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
228 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
229 * need to read the header from the file
231 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
232 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
234 ULONG cbNtHeaderSize
;
238 l_ReadHeaderFromFile
:
240 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
242 /* read the header from the file */
243 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
245 if(!NT_SUCCESS(nStatus
))
246 DIE(("ReadFile failed, status %08X\n", nStatus
));
250 ASSERT(cbReadSize
> 0);
252 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
254 /* the buffer doesn't contain the file header */
255 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
256 DIE(("The file doesn't contain the PE file header\n"));
258 pinhNtHeader
= pData
;
260 /* object still not aligned: copy it to the beginning of the buffer */
261 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
263 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
264 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
265 pinhNtHeader
= pBuffer
;
268 /* invalid NT header */
269 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
271 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
272 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
274 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
276 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
277 DIE(("The full NT header is too large\n"));
279 /* the buffer doesn't contain the whole NT header */
280 if(cbReadSize
< cbNtHeaderSize
)
281 DIE(("The file doesn't contain the full NT header\n"));
285 ULONG cbOptHeaderOffsetSize
= 0;
287 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
289 /* don't trust an invalid NT header */
290 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
291 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
293 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
294 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
296 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
297 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
299 /* the buffer doesn't contain the whole NT header: read it from the file */
300 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
301 goto l_ReadHeaderFromFile
;
304 /* read information from the NT header */
305 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
306 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
308 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
310 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
312 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
313 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
315 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
317 switch(piohOptHeader
->Magic
)
319 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
320 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
324 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
327 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
328 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
330 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
331 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
333 /* See [1], section 3.4.2 */
334 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
336 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
337 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
339 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
340 DIE(("The section alignment is smaller than the file alignment\n"));
342 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
343 nFileAlignment
= piohOptHeader
->FileAlignment
;
345 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
346 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
350 nSectionAlignment
= PAGE_SIZE
;
351 nFileAlignment
= PAGE_SIZE
;
354 ASSERT(IsPowerOf2(nSectionAlignment
));
355 ASSERT(IsPowerOf2(nFileAlignment
));
357 switch(piohOptHeader
->Magic
)
360 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
362 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
363 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
365 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
366 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
368 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
369 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
371 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
372 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
378 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
380 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
382 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
384 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
386 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
387 DIE(("ImageBase exceeds the address space\n"));
389 ImageSectionObject
->ImageBase
= pioh64OptHeader
->ImageBase
;
392 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
394 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
395 DIE(("SizeOfImage exceeds the address space\n"));
397 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
400 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
402 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
403 DIE(("SizeOfStackReserve exceeds the address space\n"));
405 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
408 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
410 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
411 DIE(("SizeOfStackCommit exceeds the address space\n"));
413 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
420 /* [1], section 3.4.2 */
421 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
422 DIE(("ImageBase is not aligned on a 64KB boundary"));
424 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
425 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
426 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
428 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
430 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
432 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
433 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
435 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
436 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
440 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
442 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
444 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
445 piohOptHeader
->AddressOfEntryPoint
;
448 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
450 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
451 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
453 ImageSectionObject
->Executable
= TRUE
;
455 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
456 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
458 /* SECTION HEADERS */
459 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
461 /* see [1], section 3.3 */
462 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
463 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
466 * the additional segment is for the file's headers. They need to be present for
467 * the benefit of the dynamic loader (to locate exports, defaults for thread
468 * parameters, resources, etc.)
470 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
472 /* file offset for the section headers */
473 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
474 DIE(("Offset overflow\n"));
476 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
477 DIE(("Offset overflow\n"));
479 /* size of the section headers */
480 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
481 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
483 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
484 DIE(("Section headers too large\n"));
486 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
488 /* size of the executable's headers */
489 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
491 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
492 // DIE(("SizeOfHeaders is not aligned\n"));
494 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
495 DIE(("The section headers overflow SizeOfHeaders\n"));
497 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
499 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
500 DIE(("Overflow aligning the size of headers\n"));
507 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
508 /* WARNING: piohOptHeader IS NO LONGER USABLE */
509 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
511 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
512 pishSectionHeaders
= NULL
;
516 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
517 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
519 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
520 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
524 * the buffer doesn't contain the section headers, or the alignment is wrong:
525 * read the headers from the file
527 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
528 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
533 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
535 /* read the header from the file */
536 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
538 if(!NT_SUCCESS(nStatus
))
539 DIE(("ReadFile failed with status %08X\n", nStatus
));
543 ASSERT(cbReadSize
> 0);
545 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
547 /* the buffer doesn't contain all the section headers */
548 if(cbReadSize
< cbSectionHeadersSize
)
549 DIE(("The file doesn't contain all of the section headers\n"));
551 pishSectionHeaders
= pData
;
553 /* object still not aligned: copy it to the beginning of the buffer */
554 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
556 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
557 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
558 pishSectionHeaders
= pBuffer
;
563 /* allocate the segments */
564 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
565 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
567 if(ImageSectionObject
->Segments
== NULL
)
568 DIE(("AllocateSegments failed\n"));
570 /* initialize the headers segment */
571 pssSegments
= ImageSectionObject
->Segments
;
573 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
575 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
576 DIE(("Cannot align the size of the section headers\n"));
578 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
579 DIE(("Cannot align the size of the section headers\n"));
581 pssSegments
[0].FileOffset
= 0;
582 pssSegments
[0].Protection
= PAGE_READONLY
;
583 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
584 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
585 pssSegments
[0].VirtualAddress
= 0;
586 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
587 pssSegments
[0].WriteCopy
= TRUE
;
589 /* skip the headers segment */
592 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
594 /* convert the executable sections into segments. See also [1], section 4 */
595 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
597 ULONG nCharacteristics
;
599 /* validate the alignment */
600 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
601 DIE(("VirtualAddress[%u] is not aligned\n", i
));
603 /* sections must be contiguous, ordered by base address and non-overlapping */
604 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
605 DIE(("Memory gap between section %u and the previous\n", i
));
607 /* ignore explicit BSS sections */
608 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
610 /* validate the alignment */
612 /* Yes, this should be a multiple of FileAlignment, but there's
613 * stuff out there that isn't. We can cope with that
615 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
616 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
619 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
620 // DIE(("PointerToRawData[%u] is not aligned\n", i));
623 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
624 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
628 ASSERT(pssSegments
[i
].FileOffset
== 0);
629 ASSERT(pssSegments
[i
].RawLength
== 0);
632 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
634 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
636 /* no explicit protection */
637 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
639 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
640 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
642 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
643 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
645 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
646 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
649 /* see table above */
650 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
651 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
653 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
654 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
656 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
658 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
659 DIE(("Cannot align the virtual size of section %u\n", i
));
661 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
663 if(pssSegments
[i
].Length
== 0)
664 DIE(("Virtual size of section %u is null\n", i
));
666 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
667 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
669 /* ensure the memory image is no larger than 4GB */
670 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
671 DIE(("The image is larger than 4GB\n"));
674 /* spare our caller some work in validating the segments */
675 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
677 if(nSectionAlignment
>= PAGE_SIZE
)
678 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
681 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;