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(IN ULONG_PTR Addend1
, IN ULONG_PTR Addend2
)
51 return Addend1
<= (MAXULONG_PTR
- Addend2
);
55 #define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
58 static __inline BOOLEAN
Intsafe_CanAddLong64(IN LONG64 Addend1
, IN LONG64 Addend2
)
60 return Addend1
<= (MAXLONGLONG
- Addend2
);
63 static __inline BOOLEAN
Intsafe_CanAddULong32(IN ULONG Addend1
, IN ULONG Addend2
)
65 return Addend1
<= (MAXULONG
- Addend2
);
68 static __inline BOOLEAN
Intsafe_AddULong32(OUT PULONG Result
, IN ULONG Addend1
, IN ULONG Addend2
)
70 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
73 *Result
= Addend1
+ Addend2
;
77 static __inline BOOLEAN
Intsafe_CanMulULong32(IN ULONG Factor1
, IN ULONG Factor2
)
79 return Factor1
<= (MAXULONG
/ Factor2
);
82 static __inline BOOLEAN
Intsafe_CanOffsetPointer(IN CONST VOID
* Pointer
, IN SIZE_T Offset
)
84 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
85 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
88 /* TODO: these are standard DDK/PSDK macros */
89 #ifndef RTL_FIELD_SIZE
90 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
93 #ifndef RTL_SIZEOF_THROUGH_FIELD
94 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
95 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
98 #ifndef RTL_CONTAINS_FIELD
99 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
100 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
103 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
108 while((Number
% 2) == 0)
114 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
116 ASSERT(IsPowerOf2(Alignment
));
117 return Address
& (Alignment
- 1);
120 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
122 return ModPow2(Address
, Alignment
) == 0;
125 static __inline BOOLEAN
AlignUp(OUT PULONG AlignedAddress
, IN ULONG Address
, IN ULONG Alignment
)
127 ULONG nExcess
= ModPow2(Address
, Alignment
);
131 *AlignedAddress
= Address
;
135 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
138 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
140 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
141 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
146 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
147 File Format Specification", revision 6.0 (February 1999)
149 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
150 IN SIZE_T FileHeaderSize
,
152 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
154 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
155 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
158 ULONG cbFileHeaderOffsetSize
= 0;
159 ULONG cbSectionHeadersOffset
= 0;
160 ULONG cbSectionHeadersSize
;
161 ULONG cbSectionHeadersOffsetSize
= 0;
162 ULONG cbOptHeaderSize
;
163 ULONG cbHeadersSize
= 0;
164 ULONG nSectionAlignment
;
165 ULONG nFileAlignment
;
166 const IMAGE_DOS_HEADER
* pidhDosHeader
;
167 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
168 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
169 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
170 PMM_SECTION_SEGMENT pssSegments
;
171 LARGE_INTEGER lnOffset
;
173 ULONG nPrevVirtualEndOfSegment
= 0;
174 ULONG nFileSizeOfHeaders
= 0;
178 ASSERT(FileHeaderSize
> 0);
180 ASSERT(ImageSectionObject
);
182 ASSERT(AllocateSegmentsCb
);
184 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
186 ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
187 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
189 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
192 pidhDosHeader
= FileHeader
;
195 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
197 /* image too small to be an MZ executable */
198 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
199 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
201 /* no MZ signature */
202 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
203 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
205 /* not a Windows executable */
206 if(pidhDosHeader
->e_lfanew
<= 0)
207 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
210 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
212 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
213 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
215 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
220 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
221 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
223 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
224 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
227 ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
228 ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
229 ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
230 ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
233 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
234 * need to read the header from the file
236 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
237 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
239 ULONG cbNtHeaderSize
;
243 l_ReadHeaderFromFile
:
245 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
247 /* read the header from the file */
248 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
250 if(!NT_SUCCESS(nStatus
))
251 DIE(("ReadFile failed, status %08X\n", nStatus
));
255 ASSERT(cbReadSize
> 0);
257 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
259 /* the buffer doesn't contain the file header */
260 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
261 DIE(("The file doesn't contain the PE file header\n"));
263 pinhNtHeader
= pData
;
265 /* object still not aligned: copy it to the beginning of the buffer */
266 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
268 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
269 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
270 pinhNtHeader
= pBuffer
;
273 /* invalid NT header */
274 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
276 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
277 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
279 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
281 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
282 DIE(("The full NT header is too large\n"));
284 /* the buffer doesn't contain the whole NT header */
285 if(cbReadSize
< cbNtHeaderSize
)
286 DIE(("The file doesn't contain the full NT header\n"));
290 ULONG cbOptHeaderOffsetSize
= 0;
292 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
294 /* don't trust an invalid NT header */
295 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
296 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
298 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
299 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
301 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
302 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
304 /* the buffer doesn't contain the whole NT header: read it from the file */
305 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
306 goto l_ReadHeaderFromFile
;
309 /* read information from the NT header */
310 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
311 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
313 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
315 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
317 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
318 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
320 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
322 switch(piohOptHeader
->Magic
)
324 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
325 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
329 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
332 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
333 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
335 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
336 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
338 /* See [1], section 3.4.2 */
339 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
341 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
342 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
344 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
345 DIE(("The section alignment is smaller than the file alignment\n"));
347 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
348 nFileAlignment
= piohOptHeader
->FileAlignment
;
350 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
351 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
355 nSectionAlignment
= PAGE_SIZE
;
356 nFileAlignment
= PAGE_SIZE
;
359 ASSERT(IsPowerOf2(nSectionAlignment
));
360 ASSERT(IsPowerOf2(nFileAlignment
));
362 switch(piohOptHeader
->Magic
)
365 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
367 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
368 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
370 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
371 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
373 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
374 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
380 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
382 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
384 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
386 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
388 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
389 DIE(("ImageBase exceeds the address space\n"));
391 ImageSectionObject
->ImageBase
= pioh64OptHeader
->ImageBase
;
394 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
396 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
397 DIE(("SizeOfStackReserve exceeds the address space\n"));
399 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
402 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
404 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
405 DIE(("SizeOfStackCommit exceeds the address space\n"));
407 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
414 /* [1], section 3.4.2 */
415 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
416 DIE(("ImageBase is not aligned on a 64KB boundary"));
418 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
419 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
420 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
422 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
424 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
426 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
427 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
429 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
430 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
434 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
436 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
438 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
439 piohOptHeader
->AddressOfEntryPoint
;
442 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
444 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
445 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
447 ImageSectionObject
->Executable
= TRUE
;
449 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
450 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
452 /* SECTION HEADERS */
453 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
455 /* see [1], section 3.3 */
456 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
457 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
460 * the additional segment is for the file's headers. They need to be present for
461 * the benefit of the dynamic loader (to locate exports, defaults for thread
462 * parameters, resources, etc.)
464 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
466 /* file offset for the section headers */
467 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
468 DIE(("Offset overflow\n"));
470 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
471 DIE(("Offset overflow\n"));
473 /* size of the section headers */
474 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
475 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
477 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
478 DIE(("Section headers too large\n"));
480 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
482 /* size of the executable's headers */
483 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
485 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
486 // DIE(("SizeOfHeaders is not aligned\n"));
488 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
489 DIE(("The section headers overflow SizeOfHeaders\n"));
491 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
493 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
494 DIE(("Overflow aligning the size of headers\n"));
501 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
502 /* WARNING: piohOptHeader IS NO LONGER USABLE */
503 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
505 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
506 pishSectionHeaders
= NULL
;
510 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
511 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
513 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
514 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
518 * the buffer doesn't contain the section headers, or the alignment is wrong:
519 * read the headers from the file
521 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
522 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
527 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
529 /* read the header from the file */
530 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
532 if(!NT_SUCCESS(nStatus
))
533 DIE(("ReadFile failed with status %08X\n", nStatus
));
537 ASSERT(cbReadSize
> 0);
539 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
541 /* the buffer doesn't contain all the section headers */
542 if(cbReadSize
< cbSectionHeadersSize
)
543 DIE(("The file doesn't contain all of the section headers\n"));
545 pishSectionHeaders
= pData
;
547 /* object still not aligned: copy it to the beginning of the buffer */
548 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
550 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
551 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
552 pishSectionHeaders
= pBuffer
;
557 /* allocate the segments */
558 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
559 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
561 if(ImageSectionObject
->Segments
== NULL
)
562 DIE(("AllocateSegments failed\n"));
564 /* initialize the headers segment */
565 pssSegments
= ImageSectionObject
->Segments
;
567 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
569 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
570 DIE(("Cannot align the size of the section headers\n"));
572 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
573 DIE(("Cannot align the size of the section headers\n"));
575 pssSegments
[0].FileOffset
= 0;
576 pssSegments
[0].Protection
= PAGE_READONLY
;
577 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
578 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
579 pssSegments
[0].VirtualAddress
= 0;
580 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
581 pssSegments
[0].WriteCopy
= TRUE
;
583 /* skip the headers segment */
586 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
588 /* convert the executable sections into segments. See also [1], section 4 */
589 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
591 ULONG nCharacteristics
;
593 /* validate the alignment */
594 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
595 DIE(("VirtualAddress[%u] is not aligned\n", i
));
597 /* sections must be contiguous, ordered by base address and non-overlapping */
598 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
599 DIE(("Memory gap between section %u and the previous\n", i
));
601 /* ignore explicit BSS sections */
602 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
604 /* validate the alignment */
606 /* Yes, this should be a multiple of FileAlignment, but there's
607 * stuff out there that isn't. We can cope with that
609 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
610 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
613 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
614 // DIE(("PointerToRawData[%u] is not aligned\n", i));
617 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
618 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
622 ASSERT(pssSegments
[i
].FileOffset
== 0);
623 ASSERT(pssSegments
[i
].RawLength
== 0);
626 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
628 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
630 /* no explicit protection */
631 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
633 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
634 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
636 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
637 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
639 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
640 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
643 /* see table above */
644 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
645 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
647 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
648 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
650 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
652 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
653 DIE(("Cannot align the virtual size of section %u\n", i
));
655 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
657 if(pssSegments
[i
].Length
== 0)
658 DIE(("Virtual size of section %u is null\n", i
));
660 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
661 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
663 /* ensure the memory image is no larger than 4GB */
664 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
665 DIE(("The image is larger than 4GB\n"));
668 /* spare our caller some work in validating the segments */
669 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
671 if(nSectionAlignment
>= PAGE_SIZE
)
672 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
675 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;