3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/pe.c
23 * PURPOSE: Loader for PE executables
24 * PROGRAMMER: KJK::Hyperion <hackbunny@reactos.com>
28 * 2004-12-26 Actually works, several checks relaxed to support
29 * the majority of existing executables, corrected
30 * the alignment helper functions, debug messages to
34 /* INCLUDES *****************************************************************/
39 #include <internal/debug.h>
41 #include <reactos/exeformat.h>
43 static ULONG SectionCharacteristicsToProtect
[16] =
45 PAGE_NOACCESS
, /* 0 = NONE */
46 PAGE_NOACCESS
, /* 1 = SHARED */
47 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
48 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
49 PAGE_READONLY
, /* 4 = READABLE */
50 PAGE_READONLY
, /* 5 = READABLE, SHARED */
51 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
52 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
54 * FIXME? do we really need the WriteCopy field in segments? can't we use
55 * PAGE_WRITECOPY here?
57 PAGE_READWRITE
, /* 8 = WRITABLE */
58 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
59 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
60 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
61 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
62 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
63 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
64 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
67 /* TODO: Intsafe should be made into a library, as it's generally useful */
68 static __inline BOOLEAN Intsafe_CanAddULongPtr
74 return Addend1
<= (MAXULONG_PTR
- Addend2
);
78 #define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
81 static __inline BOOLEAN Intsafe_CanAddLong64
87 return Addend1
<= (MAXLONGLONG
- Addend2
);
90 static __inline BOOLEAN Intsafe_CanAddULong32
96 return Addend1
<= (MAXULONG
- Addend2
);
99 static __inline BOOLEAN Intsafe_AddULong32
106 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
109 *Result
= Addend1
+ Addend2
;
113 static __inline BOOLEAN Intsafe_CanMulULong32
119 return Factor1
<= (MAXULONG
/ Factor2
);
122 static __inline BOOLEAN Intsafe_CanOffsetPointer
124 IN CONST VOID
* Pointer
,
128 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
129 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
132 /* TODO: these are standard DDK/PSDK macros */
133 #ifndef RTL_FIELD_SIZE
134 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
137 #ifndef RTL_SIZEOF_THROUGH_FIELD
138 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
139 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
142 #ifndef RTL_CONTAINS_FIELD
143 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
144 ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_)))
147 static __inline BOOLEAN
IsPowerOf2(IN ULONG Number
)
152 while((Number
% 2) == 0)
158 static __inline ULONG
ModPow2(IN ULONG Address
, IN ULONG Alignment
)
160 ASSERT(IsPowerOf2(Alignment
));
161 return Address
& (Alignment
- 1);
164 static __inline BOOLEAN
IsAligned(IN ULONG Address
, IN ULONG Alignment
)
166 return ModPow2(Address
, Alignment
) == 0;
169 static __inline BOOLEAN AlignUp
171 OUT PULONG AlignedAddress
,
176 ULONG nExcess
= ModPow2(Address
, Alignment
);
180 *AlignedAddress
= Address
;
184 return Intsafe_AddULong32(AlignedAddress
, Address
, Alignment
- nExcess
);
187 #define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
189 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
190 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
195 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
196 File Format Specification", revision 6.0 (February 1999)
198 NTSTATUS NTAPI PeFmtCreateSection
200 IN CONST VOID
* FileHeader
,
201 IN SIZE_T FileHeaderSize
,
203 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
205 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
206 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
210 ULONG cbFileHeaderOffsetSize
;
211 ULONG cbSectionHeadersOffset
;
212 ULONG cbSectionHeadersSize
;
213 ULONG cbSectionHeadersOffsetSize
;
214 ULONG cbOptHeaderSize
;
216 ULONG nSectionAlignment
;
217 ULONG nFileAlignment
;
218 const IMAGE_DOS_HEADER
* pidhDosHeader
;
219 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
220 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
221 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
222 PMM_SECTION_SEGMENT pssSegments
;
223 LARGE_INTEGER lnOffset
;
225 ULONG nPrevVirtualEndOfSegment
;
226 ULONG nFileSizeOfHeaders
;
230 ASSERT(FileHeaderSize
> 0);
232 ASSERT(ImageSectionObject
);
234 ASSERT(AllocateSegmentsCb
);
236 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
238 ASSERT(FileHeaderSize
>= sizeof(IMAGE_DOS_HEADER
));
239 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
241 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
244 pidhDosHeader
= FileHeader
;
247 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
249 /* no MZ signature */
250 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
251 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
253 /* not a Windows executable */
254 if(pidhDosHeader
->e_lfanew
<= 0)
255 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
258 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
260 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
261 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
263 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
268 we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
269 and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
271 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
272 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
275 ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
276 ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
277 ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
278 ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
281 the buffer doesn't contain the NT file header, or the alignment is wrong: we
282 need to read the header from the file
286 FileHeaderSize
< cbFileHeaderOffsetSize
||
287 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0
290 ULONG cbNtHeaderSize
;
294 l_ReadHeaderFromFile
:
295 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
297 /* read the header from the file */
302 sizeof(IMAGE_NT_HEADERS64
),
308 if(!NT_SUCCESS(nStatus
))
309 DIE(("ReadFile failed, status %08X\n", nStatus
));
313 ASSERT(cbReadSize
> 0);
315 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
317 /* the buffer doesn't contain the file header */
318 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
319 DIE(("The file doesn't contain the PE file header\n"));
321 pinhNtHeader
= pData
;
323 /* object still not aligned: copy it to the beginning of the buffer */
324 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
326 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
327 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
328 pinhNtHeader
= pBuffer
;
331 /* invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The full NT header is too large\n"));
338 nStatus
= STATUS_UNSUCCESSFUL
;
340 /* the buffer doesn't contain the whole NT header */
341 if(cbReadSize
< cbNtHeaderSize
)
342 DIE(("The file doesn't contain the full NT header\n"));
346 ULONG cbOptHeaderOffsetSize
;
348 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
350 /* don't trust an invalid NT header */
351 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
352 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
354 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
355 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
357 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
358 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
360 /* the buffer doesn't contain the whole NT header: read it from the file */
361 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
362 goto l_ReadHeaderFromFile
;
365 /* read information from the NT header */
366 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
367 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
369 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
371 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
373 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
374 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
376 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
378 switch(piohOptHeader
->Magic
)
380 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
381 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
385 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
388 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
389 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
393 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
394 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
)
397 /* See [1], section 3.4.2 */
398 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
400 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
401 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
403 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
404 DIE(("The section alignment is smaller than the file alignment\n"));
406 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
407 nFileAlignment
= piohOptHeader
->FileAlignment
;
409 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
410 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
414 nSectionAlignment
= PAGE_SIZE
;
415 nFileAlignment
= PAGE_SIZE
;
418 ASSERT(IsPowerOf2(nSectionAlignment
));
419 ASSERT(IsPowerOf2(nFileAlignment
));
421 switch(piohOptHeader
->Magic
)
424 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
426 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
427 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
429 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
430 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
432 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
433 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
439 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
441 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
443 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
445 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
447 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
448 DIE(("ImageBase exceeds the address space\n"));
450 ImageSectionObject
->ImageBase
= pioh64OptHeader
->ImageBase
;
453 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
455 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
456 DIE(("SizeOfStackReserve exceeds the address space\n"));
458 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
461 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
463 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
464 DIE(("SizeOfStackCommit exceeds the address space\n"));
466 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
473 /* [1], section 3.4.2 */
474 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
475 DIE(("ImageBase is not aligned on a 64KB boundary"));
477 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
478 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
479 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
481 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
483 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
487 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
488 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
)
491 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
492 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
496 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
498 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
499 ImageSectionObject
->EntryPoint
= piohOptHeader
->AddressOfEntryPoint
;
501 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
503 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
504 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
506 ImageSectionObject
->Executable
= TRUE
;
508 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
509 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
511 /* SECTION HEADERS */
512 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
514 /* see [1], section 3.3 */
515 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
516 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
519 the additional segment is for the file's headers. They need to be present for
520 the benefit of the dynamic loader (to locate exports, defaults for thread
521 parameters, resources, etc.)
523 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
525 /* file offset for the section headers */
526 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
527 DIE(("Offset overflow\n"));
529 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
530 DIE(("Offset overflow\n"));
532 /* size of the section headers */
533 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
534 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
536 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
537 DIE(("Section headers too large\n"));
539 ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
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
582 FileHeaderSize
< cbSectionHeadersOffsetSize
||
583 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0
589 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
591 /* read the header from the file */
596 cbSectionHeadersSize
,
602 if(!NT_SUCCESS(nStatus
))
603 DIE(("ReadFile failed with status %08X\n", nStatus
));
607 ASSERT(cbReadSize
> 0);
609 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
611 /* the buffer doesn't contain all the section headers */
612 if(cbReadSize
< cbSectionHeadersSize
)
613 DIE(("The file doesn't contain all of the section headers\n"));
615 pishSectionHeaders
= pData
;
617 /* object still not aligned: copy it to the beginning of the buffer */
618 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
620 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
621 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
622 pishSectionHeaders
= pBuffer
;
627 /* allocate the segments */
628 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
629 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
631 if(ImageSectionObject
->Segments
== NULL
)
632 DIE(("AllocateSegments failed\n"));
634 /* initialize the headers segment */
635 pssSegments
= ImageSectionObject
->Segments
;
637 ASSERT(IsAligned(cbHeadersSize
, nFileAlignment
));
639 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
640 DIE(("Cannot align the size of the section headers\n"));
642 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
643 DIE(("Cannot align the size of the section headers\n"));
645 pssSegments
[0].FileOffset
= 0;
646 pssSegments
[0].Protection
= PAGE_READONLY
;
647 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
648 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
649 pssSegments
[0].VirtualAddress
= 0;
650 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
651 pssSegments
[0].WriteCopy
= TRUE
;
653 /* skip the headers segment */
656 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
658 /* convert the executable sections into segments. See also [1], section 4 */
659 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
661 ULONG nCharacteristics
;
663 /* validate the alignment */
664 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
665 DIE(("VirtualAddress[%u] is not aligned\n", i
));
667 /* sections must be contiguous, ordered by base address and non-overlapping */
668 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
669 DIE(("Memory gap between section %u and the previous\n", i
));
671 /* ignore explicit BSS sections */
672 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
674 /* validate the alignment */
675 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
676 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
678 if(!IsAligned(pishSectionHeaders
[i
].PointerToRawData
, nFileAlignment
))
679 DIE(("PointerToRawData[%u] is not aligned\n", i
));
682 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
683 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
687 ASSERT(pssSegments
[i
].FileOffset
== 0);
688 ASSERT(pssSegments
[i
].RawLength
== 0);
691 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
693 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
695 /* no explicit protection */
696 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
698 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
699 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
701 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
702 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
704 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
705 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
708 /* see table above */
709 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
710 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
712 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
713 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
715 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
717 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
718 DIE(("Cannot align the virtual size of section %u\n", i
));
720 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
722 if(pssSegments
[i
].Length
== 0)
723 DIE(("Virtual size of section %u is null\n", i
));
725 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
726 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
728 /* ensure the memory image is no larger than 4GB */
729 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
730 DIE(("The image is larger than 4GB\n"));
733 /* spare our caller some work in validating the segments */
734 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
736 if(nSectionAlignment
>= PAGE_SIZE
)
737 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
740 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
& EXEFMT_LOADED_PE32
;