7 #include <internal/debug.h>
9 #include <reactos/exeformat.h>
11 #ifndef __ELF_WORD_SIZE
12 #error __ELF_WORD_SIZE must be defined
17 /* TODO: Intsafe should be made into a library, as it's generally useful */
18 static __inline BOOLEAN Intsafe_CanAddULongPtr
24 return Addend1
<= (MAXULONG_PTR
- Addend2
);
27 #define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr
29 static __inline BOOLEAN Intsafe_CanAddULong32
35 return Addend1
<= (MAXULONG
- Addend2
);
38 static __inline BOOLEAN Intsafe_AddULong32
45 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
48 *Result
= Addend1
+ Addend2
;
52 static __inline BOOLEAN Intsafe_CanAddULong64
58 return Addend1
<= (((ULONG64
)-1) - Addend2
);
61 static __inline BOOLEAN Intsafe_AddULong64
68 if(!Intsafe_CanAddULong64(Addend1
, Addend2
))
71 *Result
= Addend1
+ Addend2
;
75 static __inline BOOLEAN Intsafe_CanMulULong32
81 return Factor1
<= (MAXULONG
/ Factor2
);
84 static __inline BOOLEAN Intsafe_MulULong32
91 if(!Intsafe_CanMulULong32(Factor1
, Factor2
))
94 *Result
= Factor1
* Factor2
;
98 static __inline BOOLEAN Intsafe_CanOffsetPointer
100 IN CONST VOID
* Pointer
,
104 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
105 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
108 #if __ELF_WORD_SIZE == 32
109 #define ElfFmtpAddSize Intsafe_AddULong32
110 #define ElfFmtpReadAddr ElfFmtpReadULong
111 #define ElfFmtpReadOff ElfFmtpReadULong
112 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong
113 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong
114 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong
115 #elif __ELF_WORD_SIZE == 64
116 #define ElfFmtpAddSize Intsafe_AddULong64
117 #define ElfFmtpReadAddr ElfFmtpReadULong64
118 #define ElfFmtpReadOff ElfFmtpReadULong64
119 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64
120 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64
121 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64
124 /* TODO: these are standard DDK/PSDK macros */
125 #define RtlRetrieveUlonglong(DST_, SRC_) \
126 (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64)))
128 #ifndef RTL_FIELD_SIZE
129 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
132 #ifndef RTL_SIZEOF_THROUGH_FIELD
133 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
134 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
137 #ifndef RTL_CONTAINS_FIELD
138 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
139 ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_)))
142 #define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
144 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
145 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
148 #define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \
150 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \
151 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \
154 #define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \
156 (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \
157 (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \
160 #define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \
162 (((USHORT)(BYTE1_)) << 0) | \
163 (((USHORT)(BYTE2_)) << 8) \
166 static __inline ULONG64 ElfFmtpReadULong64
174 if(DataType
== ELF_TARG_DATA
)
181 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
182 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
189 static __inline ULONG ElfFmtpReadULong
197 if(DataType
== ELF_TARG_DATA
)
204 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
205 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
212 static __inline USHORT ElfFmtpReadUShort
220 if(DataType
== ELF_TARG_DATA
)
227 case ELFDATA2LSB
: return ELFFMT_MAKE_USHORT(p
[0], p
[1]);
228 case ELFDATA2MSB
: return ELFFMT_MAKE_USHORT(p
[1], p
[0]);
235 static __inline ULONG64 ElfFmtpSafeReadULong64
237 IN CONST ULONG64
* Input
,
244 RtlRetrieveUlonglong(&nSafeInput
, Input
);
246 p
= (PBYTE
)&nSafeInput
;
250 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
251 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
258 static __inline ULONG ElfFmtpSafeReadULong
260 IN CONST ULONG32
* Input
,
267 RtlRetrieveUlong(&nSafeInput
, Input
);
269 if(DataType
== ELF_TARG_DATA
)
272 p
= (PBYTE
)&nSafeInput
;
276 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
277 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
284 static __inline BOOLEAN
ElfFmtpIsPowerOf2(IN Elf_Addr Number
)
289 while((Number
% 2) == 0)
295 static __inline Elf_Addr ElfFmtpModPow2
298 IN Elf_Addr Alignment
301 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
302 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
303 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
304 return Address
& (Alignment
- 1);
307 static __inline Elf_Addr ElfFmtpAlignDown
310 IN Elf_Addr Alignment
313 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
314 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
315 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
316 return Address
& ~(Alignment
- 1);
319 static __inline BOOLEAN ElfFmtpAlignUp
321 OUT Elf_Addr
* AlignedAddress
,
323 IN Elf_Addr Alignment
326 Elf_Addr nExcess
= ElfFmtpModPow2(Address
, Alignment
);
330 *AlignedAddress
= Address
;
334 return ElfFmtpAddSize(AlignedAddress
, Address
, Alignment
- nExcess
);
339 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
340 (ELF) Specification", Version 1.2
343 #if __ELF_WORD_SIZE == 32
344 Elf32FmtCreateSection
345 #elif __ELF_WORD_SIZE == 64
346 Elf64FmtCreateSection
349 IN CONST VOID
* FileHeader
,
350 IN SIZE_T FileHeaderSize
,
352 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
354 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
355 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
359 const Elf_Ehdr
* pehHeader
;
360 const Elf_Phdr
* pphPHdrs
;
361 BOOLEAN fPageAligned
;
365 Elf_Off cbPHdrOffset
;
367 PMM_SECTION_SEGMENT pssSegments
;
368 Elf_Addr nImageBase
= 0;
369 Elf_Addr nEntryPoint
;
370 ULONG32 nPrevVirtualEndOfSegment
= 0;
374 (void)Intsafe_AddULong64
;
375 (void)Intsafe_MulULong32
;
376 (void)ElfFmtpReadULong64
;
377 (void)ElfFmtpSafeReadULong64
;
378 (void)ElfFmtpReadULong
;
380 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
384 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
386 /* Ensure the file contains the full header */
388 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
389 all the classes defined as of December 2004). If FileHeaderSize is less than
390 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
393 ASSERT(sizeof(Elf_Ehdr
) <= EXEFMT_LOAD_HEADER_SIZE
);
395 if(FileHeaderSize
< sizeof(Elf_Ehdr
))
396 DIE(("The file is truncated, doesn't contain the full header\n"));
398 pehHeader
= FileHeader
;
399 ASSERT(((ULONG_PTR
)pehHeader
% TYPE_ALIGNMENT(Elf_Ehdr
)) == 0);
401 nData
= pehHeader
->e_ident
[EI_DATA
];
403 /* Validate the header */
404 if(ElfFmtpReadUShort(pehHeader
->e_ehsize
, nData
) < sizeof(Elf_Ehdr
))
405 DIE(("Inconsistent value for e_ehsize\n"));
407 /* Calculate size and offset of the program headers */
408 cbPHdrSize
= ElfFmtpReadUShort(pehHeader
->e_phentsize
, nData
);
410 if(cbPHdrSize
!= sizeof(Elf_Phdr
))
411 DIE(("Inconsistent value for e_phentsize\n"));
413 /* MAXUSHORT * MAXUSHORT < MAXULONG */
414 nPHdrCount
= ElfFmtpReadUShort(pehHeader
->e_phnum
, nData
);
415 ASSERT(Intsafe_CanMulULong32(cbPHdrSize
, nPHdrCount
));
416 cbPHdrSize
*= nPHdrCount
;
418 cbPHdrOffset
= ElfFmtpReadOff(pehHeader
->e_phoff
, nData
);
420 /* The initial header doesn't contain the program headers */
421 if(cbPHdrOffset
> FileHeaderSize
|| cbPHdrSize
> (FileHeaderSize
- cbPHdrOffset
))
423 NTSTATUS nReadStatus
;
424 LARGE_INTEGER lnOffset
;
428 /* Will worry about this when ELF128 comes */
429 ASSERT(sizeof(cbPHdrOffset
) <= sizeof(lnOffset
.QuadPart
));
431 lnOffset
.QuadPart
= (LONG64
)cbPHdrOffset
;
434 We can't support executable files larger than 8 Exabytes - it's a limitation
435 of the I/O system (only 63-bit offsets are supported). Quote:
437 [...] the total amount of printed material in the world is estimated to be
438 around a fifth of an exabyte. [...] [Source: Wikipedia]
440 if(lnOffset
.u
.HighPart
< 0)
441 DIE(("The program header is too far into the file\n"));
443 nReadStatus
= ReadFileCb
453 if(!NT_SUCCESS(nReadStatus
))
455 nStatus
= nReadStatus
;
456 DIE(("ReadFile failed, status %08X\n", nStatus
));
461 ASSERT(Intsafe_CanOffsetPointer(pData
, cbReadSize
));
463 if(cbReadSize
< cbPHdrSize
)
464 DIE(("The file didn't contain the program headers\n"));
466 /* Force the buffer to be aligned */
467 if((ULONG_PTR
)pData
% TYPE_ALIGNMENT(Elf_Phdr
))
469 ASSERT(((ULONG_PTR
)pBuffer
% TYPE_ALIGNMENT(Elf_Phdr
)) == 0);
470 RtlMoveMemory(pBuffer
, pData
, cbPHdrSize
);
478 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset
, 0));
479 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbPHdrOffset
));
480 pphPHdrs
= (PVOID
)((ULONG_PTR
)FileHeader
+ (ULONG_PTR
)cbPHdrOffset
);
483 /* Allocate the segments */
484 pssSegments
= AllocateSegmentsCb(nPHdrCount
);
486 if(pssSegments
== NULL
)
488 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
489 DIE(("Out of memory\n"));
492 ImageSectionObject
->Segments
= pssSegments
;
496 /* Fill in the segments */
497 for(i
= 0, j
= 0; i
< nPHdrCount
; ++ i
)
499 switch(ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_type
, nData
))
503 static const ULONG ProgramHeaderFlagsToProtect
[8] =
505 PAGE_NOACCESS
, /* 0 */
506 PAGE_EXECUTE_READ
, /* PF_X */
507 PAGE_READWRITE
, /* PF_W */
508 PAGE_EXECUTE_READWRITE
, /* PF_X | PF_W */
509 PAGE_READONLY
, /* PF_R */
510 PAGE_EXECUTE_READ
, /* PF_X | PF_R */
511 PAGE_READWRITE
, /* PF_W | PF_R */
512 PAGE_EXECUTE_READWRITE
/* PF_X | PF_W | PF_R */
517 Elf_Addr nVirtualAddr
;
519 Elf_Size nVirtualSize
;
522 ASSERT(j
<= nPHdrCount
);
524 /* Retrieve and validate the segment alignment */
525 nAlignment
= ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_align
, nData
);
529 else if(!ElfFmtpIsPowerOf2(nAlignment
))
530 DIE(("Alignment of loadable segment isn't a power of 2\n"));
532 if(nAlignment
< PAGE_SIZE
)
533 fPageAligned
= FALSE
;
535 /* Retrieve the addresses and calculate the adjustment */
536 nFileOffset
= ElfFmtpSafeReadOff(&pphPHdrs
[i
].p_offset
, nData
);
537 nVirtualAddr
= ElfFmtpSafeReadAddr(&pphPHdrs
[i
].p_vaddr
, nData
);
539 nAdj
= ElfFmtpModPow2(nFileOffset
, nAlignment
);
541 if(nAdj
!= ElfFmtpModPow2(nVirtualAddr
, nAlignment
))
542 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
544 /* Retrieve, adjust and align the file size and memory size */
545 if(!ElfFmtpAddSize(&nFileSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_filesz
, nData
), nAdj
))
546 DIE(("Can't adjust the file size of loadable segment\n"));
548 if(!ElfFmtpAddSize(&nVirtualSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_memsz
, nData
), nAdj
))
549 DIE(("Can't adjust the memory size of lodable segment\n"));
551 if(!ElfFmtpAlignUp(&nVirtualSize
, nVirtualSize
, nAlignment
))
552 DIE(("Can't align the memory size of lodable segment\n"));
554 if(nFileSize
> nVirtualSize
)
555 nFileSize
= nVirtualSize
;
557 if(nVirtualSize
> MAXULONG
)
558 DIE(("Virtual image larger than 4GB\n"));
560 ASSERT(nFileSize
<= MAXULONG
);
562 pssSegments
[j
].Length
= (ULONG
)(nVirtualSize
& 0xFFFFFFFF);
563 pssSegments
[j
].RawLength
= (ULONG
)(nFileSize
& 0xFFFFFFFF);
566 nFileOffset
= ElfFmtpAlignDown(nFileOffset
, nAlignment
);
568 #if __ELF_WORD_SIZE >= 64
569 ASSERT(sizeof(nFileOffset
) == sizeof(LONG64
));
571 if(((LONG64
)nFileOffset
) < 0)
572 DIE(("File offset of loadable segment is too large\n"));
575 pssSegments
[j
].FileOffset
= (LONG64
)nFileOffset
;
577 /* Virtual address */
578 nVirtualAddr
= ElfFmtpAlignDown(nVirtualAddr
, nAlignment
);
582 /* First segment: its address is the base address of the image */
583 nImageBase
= nVirtualAddr
;
584 pssSegments
[j
].VirtualAddress
= 0;
586 /* Several places make this assumption */
587 if(pssSegments
[j
].FileOffset
!= 0)
588 DIE(("First loadable segment doesn't contain the ELF header\n"));
592 Elf_Size nVirtualOffset
;
594 /* Other segment: store the offset from the base address */
595 if(nVirtualAddr
<= nImageBase
)
596 DIE(("Loadable segments are not sorted\n"));
598 nVirtualOffset
= nVirtualAddr
- nImageBase
;
600 if(nVirtualOffset
> MAXULONG
)
601 DIE(("Virtual image larger than 4GB\n"));
603 pssSegments
[j
].VirtualAddress
= (ULONG
)(nVirtualOffset
& 0xFFFFFFFF);
605 if(pssSegments
[j
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
606 DIE(("Loadable segments are not sorted and contiguous\n"));
609 /* Memory protection */
610 pssSegments
[j
].Protection
= ProgramHeaderFlagsToProtect
612 ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_flags
, nData
) & (PF_R
| PF_W
| PF_X
)
615 /* Characteristics */
617 TODO: need to add support for the shared, non-pageable, non-cacheable and
618 discardable attributes. This involves extensions to the ELF format, so it's
619 nothing to be taken lightly
621 if(pssSegments
[j
].Protection
& PAGE_IS_EXECUTABLE
)
623 ImageSectionObject
->Executable
= TRUE
;
624 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_CODE
;
626 else if(pssSegments
[j
].RawLength
== 0)
627 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
629 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
632 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
633 now, if a bit wasteful of memory
635 pssSegments
[j
].Characteristics
|= IMAGE_SCN_MEM_NOT_PAGED
;
638 pssSegments
[j
].WriteCopy
= TRUE
;
640 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[j
].VirtualAddress
, pssSegments
[j
].Length
))
641 DIE(("Virtual image larger than 4GB\n"));
650 DIE(("No loadable segments\n"));
652 ImageSectionObject
->NrSegments
= j
;
655 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
|
656 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
659 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
661 nEntryPoint
= ElfFmtpReadAddr(pehHeader
->e_entry
, nData
);
663 if(nEntryPoint
< nImageBase
|| nEntryPoint
- nImageBase
> nPrevVirtualEndOfSegment
)
664 DIE(("Entry point not within the virtual image\n"));
666 ASSERT(nEntryPoint
>= nImageBase
);
667 ASSERT((nEntryPoint
- nImageBase
) <= MAXULONG
);
668 ImageSectionObject
->EntryPoint
= nEntryPoint
- nImageBase
;
670 /* TODO: support Wine executables and read these values from nt_headers */
671 ImageSectionObject
->ImageCharacteristics
|=
672 IMAGE_FILE_EXECUTABLE_IMAGE
|
673 IMAGE_FILE_LINE_NUMS_STRIPPED
|
674 IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
675 (nImageBase
> MAXULONG
? IMAGE_FILE_LARGE_ADDRESS_AWARE
: 0) |
676 IMAGE_FILE_DEBUG_STRIPPED
;
678 if(nData
== ELFDATA2LSB
)
679 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_LO
;
680 else if(nData
== ELFDATA2MSB
)
681 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_HI
;
683 /* Base address outside the possible address space */
684 if(nImageBase
> MAXULONG_PTR
)
685 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_NONE
;
686 /* Position-independent image, base address doesn't matter */
687 else if(nImageBase
== 0)
688 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_ANY
;
689 /* Use the specified base address */
691 ImageSectionObject
->ImageBase
= (ULONG_PTR
)nImageBase
;
694 ImageSectionObject
->Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
695 ImageSectionObject
->MinorSubsystemVersion
= 0;
696 ImageSectionObject
->MajorSubsystemVersion
= 4;
698 /* Success, at last */
699 nStatus
= STATUS_SUCCESS
;