4 #include <reactos/exeformat.h>
6 #ifndef __ELF_WORD_SIZE
7 #error __ELF_WORD_SIZE must be defined
11 #define MAXULONG ((ULONG)(~1))
16 /* TODO: Intsafe should be made into a library, as it's generally useful */
17 static __inline BOOLEAN Intsafe_CanAddULongPtr
23 return Addend1
<= (MAXULONG_PTR
- Addend2
);
26 #define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr
28 static __inline BOOLEAN Intsafe_CanAddULong32
34 return Addend1
<= (MAXULONG
- Addend2
);
37 static __inline BOOLEAN Intsafe_AddULong32
44 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
47 *Result
= Addend1
+ Addend2
;
51 static __inline BOOLEAN Intsafe_CanAddULong64
57 return Addend1
<= (((ULONG64
)-1) - Addend2
);
60 static __inline BOOLEAN Intsafe_AddULong64
67 if(!Intsafe_CanAddULong64(Addend1
, Addend2
))
70 *Result
= Addend1
+ Addend2
;
74 static __inline BOOLEAN Intsafe_CanMulULong32
80 return Factor1
<= (MAXULONG
/ Factor2
);
83 static __inline BOOLEAN Intsafe_MulULong32
90 if(!Intsafe_CanMulULong32(Factor1
, Factor2
))
93 *Result
= Factor1
* Factor2
;
97 static __inline BOOLEAN Intsafe_CanOffsetPointer
99 IN CONST VOID
* Pointer
,
103 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
104 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
107 #if __ELF_WORD_SIZE == 32
108 #define ElfFmtpAddSize Intsafe_AddULong32
109 #define ElfFmtpReadAddr ElfFmtpReadULong
110 #define ElfFmtpReadOff ElfFmtpReadULong
111 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong
112 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong
113 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong
114 #elif __ELF_WORD_SIZE == 64
115 #define ElfFmtpAddSize Intsafe_AddULong64
116 #define ElfFmtpReadAddr ElfFmtpReadULong64
117 #define ElfFmtpReadOff ElfFmtpReadULong64
118 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64
119 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64
120 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64
123 /* TODO: these are standard DDK/PSDK macros */
124 #define RtlRetrieveUlonglong(DST_, SRC_) \
125 (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64)))
127 #ifndef RTL_FIELD_SIZE
128 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
131 #ifndef RTL_SIZEOF_THROUGH_FIELD
132 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
133 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
136 #ifndef RTL_CONTAINS_FIELD
137 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
138 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
141 #define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
143 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
144 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
147 #define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \
149 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \
150 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \
153 #define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \
155 (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \
156 (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \
159 #define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \
161 (((USHORT)(BYTE1_)) << 0) | \
162 (((USHORT)(BYTE2_)) << 8) \
165 static __inline ULONG64 ElfFmtpReadULong64
173 if(DataType
== ELF_TARG_DATA
)
180 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
181 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
188 static __inline ULONG ElfFmtpReadULong
196 if(DataType
== ELF_TARG_DATA
)
203 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
204 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
211 static __inline USHORT ElfFmtpReadUShort
219 if(DataType
== ELF_TARG_DATA
)
226 case ELFDATA2LSB
: return ELFFMT_MAKE_USHORT(p
[0], p
[1]);
227 case ELFDATA2MSB
: return ELFFMT_MAKE_USHORT(p
[1], p
[0]);
234 static __inline ULONG64 ElfFmtpSafeReadULong64
236 IN CONST ULONG64
* Input
,
243 RtlRetrieveUlonglong(&nSafeInput
, Input
);
245 p
= (PUCHAR
)&nSafeInput
;
249 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
250 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
257 static __inline ULONG ElfFmtpSafeReadULong
259 IN CONST ULONG32
* Input
,
267 CONST ULONG32
*ConstInput
;
271 RtlRetrieveUlong(&nSafeInput
, pInput
.Input
);
273 if(DataType
== ELF_TARG_DATA
)
276 p
= (PUCHAR
)&nSafeInput
;
280 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
281 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
288 static __inline BOOLEAN
ElfFmtpIsPowerOf2(IN Elf_Addr Number
)
293 return (Number
& (Number
- 1)) == 0;
296 static __inline Elf_Addr ElfFmtpModPow2
299 IN Elf_Addr Alignment
302 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
303 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
304 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
305 return Address
& (Alignment
- 1);
308 static __inline Elf_Addr ElfFmtpAlignDown
311 IN Elf_Addr Alignment
314 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
315 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
316 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
317 return Address
& ~(Alignment
- 1);
320 static __inline BOOLEAN ElfFmtpAlignUp
322 OUT Elf_Addr
* AlignedAddress
,
324 IN Elf_Addr Alignment
327 Elf_Addr nExcess
= ElfFmtpModPow2(Address
, Alignment
);
331 *AlignedAddress
= Address
;
335 return ElfFmtpAddSize(AlignedAddress
, Address
, Alignment
- nExcess
);
340 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
341 (ELF) Specification", Version 1.2
344 #if __ELF_WORD_SIZE == 32
345 Elf32FmtCreateSection
346 #elif __ELF_WORD_SIZE == 64
347 Elf64FmtCreateSection
350 IN CONST VOID
* FileHeader
,
351 IN SIZE_T FileHeaderSize
,
353 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
355 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
356 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
360 const Elf_Ehdr
* pehHeader
;
361 const Elf_Phdr
* pphPHdrs
;
362 BOOLEAN fPageAligned
;
366 Elf_Off cbPHdrOffset
;
368 PMM_SECTION_SEGMENT pssSegments
;
369 Elf_Addr nImageBase
= 0;
370 Elf_Addr nEntryPoint
;
371 ULONG32 nPrevVirtualEndOfSegment
= 0;
375 (void)Intsafe_AddULong64
;
376 (void)Intsafe_MulULong32
;
377 (void)ElfFmtpReadULong64
;
378 (void)ElfFmtpSafeReadULong64
;
379 (void)ElfFmtpReadULong
;
381 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
385 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
387 /* Ensure the file contains the full header */
389 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
390 all the classes defined as of December 2004). If FileHeaderSize is less than
391 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
394 ASSERT(sizeof(Elf_Ehdr
) <= EXEFMT_LOAD_HEADER_SIZE
);
396 if(FileHeaderSize
< sizeof(Elf_Ehdr
))
397 DIE(("The file is truncated, doesn't contain the full header\n"));
399 pehHeader
= FileHeader
;
400 ASSERT(((ULONG_PTR
)pehHeader
% TYPE_ALIGNMENT(Elf_Ehdr
)) == 0);
402 nData
= pehHeader
->e_ident
[EI_DATA
];
404 /* Validate the header */
405 if(ElfFmtpReadUShort(pehHeader
->e_ehsize
, nData
) < sizeof(Elf_Ehdr
))
406 DIE(("Inconsistent value for e_ehsize\n"));
408 /* Calculate size and offset of the program headers */
409 cbPHdrSize
= ElfFmtpReadUShort(pehHeader
->e_phentsize
, nData
);
411 if(cbPHdrSize
!= sizeof(Elf_Phdr
))
412 DIE(("Inconsistent value for e_phentsize\n"));
414 /* MAXUSHORT * MAXUSHORT < MAXULONG */
415 nPHdrCount
= ElfFmtpReadUShort(pehHeader
->e_phnum
, nData
);
416 ASSERT(Intsafe_CanMulULong32(cbPHdrSize
, nPHdrCount
));
417 cbPHdrSize
*= nPHdrCount
;
419 cbPHdrOffset
= ElfFmtpReadOff(pehHeader
->e_phoff
, nData
);
421 /* The initial header doesn't contain the program headers */
422 if(cbPHdrOffset
> FileHeaderSize
|| cbPHdrSize
> (FileHeaderSize
- cbPHdrOffset
))
424 NTSTATUS nReadStatus
;
425 LARGE_INTEGER lnOffset
;
429 /* Will worry about this when ELF128 comes */
430 ASSERT(sizeof(cbPHdrOffset
) <= sizeof(lnOffset
.QuadPart
));
432 lnOffset
.QuadPart
= (LONG64
)cbPHdrOffset
;
435 We can't support executable files larger than 8 Exabytes - it's a limitation
436 of the I/O system (only 63-bit offsets are supported). Quote:
438 [...] the total amount of printed material in the world is estimated to be
439 around a fifth of an exabyte. [...] [Source: Wikipedia]
441 if(lnOffset
.u
.HighPart
< 0)
442 DIE(("The program header is too far into the file\n"));
444 nReadStatus
= ReadFileCb
454 if(!NT_SUCCESS(nReadStatus
))
456 nStatus
= nReadStatus
;
457 DIE(("ReadFile failed, status %08X\n", nStatus
));
462 ASSERT(Intsafe_CanOffsetPointer(pData
, cbReadSize
));
464 if(cbReadSize
< cbPHdrSize
)
465 DIE(("The file didn't contain the program headers\n"));
467 /* Force the buffer to be aligned */
468 if((ULONG_PTR
)pData
% TYPE_ALIGNMENT(Elf_Phdr
))
470 ASSERT(((ULONG_PTR
)pBuffer
% TYPE_ALIGNMENT(Elf_Phdr
)) == 0);
471 RtlMoveMemory(pBuffer
, pData
, cbPHdrSize
);
479 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset
, 0));
480 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbPHdrOffset
));
481 pphPHdrs
= (PVOID
)((ULONG_PTR
)FileHeader
+ (ULONG_PTR
)cbPHdrOffset
);
484 /* Allocate the segments */
485 pssSegments
= AllocateSegmentsCb(nPHdrCount
);
487 if(pssSegments
== NULL
)
489 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
490 DIE(("Out of memory\n"));
493 ImageSectionObject
->Segments
= pssSegments
;
497 /* Fill in the segments */
498 for(i
= 0, j
= 0; i
< nPHdrCount
; ++ i
)
500 switch(ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_type
, nData
))
504 static const ULONG ProgramHeaderFlagsToProtect
[8] =
506 PAGE_NOACCESS
, /* 0 */
507 PAGE_EXECUTE_READ
, /* PF_X */
508 PAGE_READWRITE
, /* PF_W */
509 PAGE_EXECUTE_READWRITE
, /* PF_X | PF_W */
510 PAGE_READONLY
, /* PF_R */
511 PAGE_EXECUTE_READ
, /* PF_X | PF_R */
512 PAGE_READWRITE
, /* PF_W | PF_R */
513 PAGE_EXECUTE_READWRITE
/* PF_X | PF_W | PF_R */
518 Elf_Addr nVirtualAddr
;
520 Elf_Size nVirtualSize
= 0;
521 Elf_Size nFileSize
= 0;
523 ASSERT(j
<= nPHdrCount
);
525 /* Retrieve and validate the segment alignment */
526 nAlignment
= ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_align
, nData
);
530 else if(!ElfFmtpIsPowerOf2(nAlignment
))
531 DIE(("Alignment of loadable segment isn't a power of 2\n"));
533 if(nAlignment
< PAGE_SIZE
)
534 fPageAligned
= FALSE
;
536 /* Retrieve the addresses and calculate the adjustment */
537 nFileOffset
= ElfFmtpSafeReadOff(&pphPHdrs
[i
].p_offset
, nData
);
538 nVirtualAddr
= ElfFmtpSafeReadAddr(&pphPHdrs
[i
].p_vaddr
, nData
);
540 nAdj
= ElfFmtpModPow2(nFileOffset
, nAlignment
);
542 if(nAdj
!= ElfFmtpModPow2(nVirtualAddr
, nAlignment
))
543 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
545 /* Retrieve, adjust and align the file size and memory size */
546 if(!ElfFmtpAddSize(&nFileSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_filesz
, nData
), nAdj
))
547 DIE(("Can't adjust the file size of loadable segment\n"));
549 if(!ElfFmtpAddSize(&nVirtualSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_memsz
, nData
), nAdj
))
550 DIE(("Can't adjust the memory size of lodable segment\n"));
552 if(!ElfFmtpAlignUp(&nVirtualSize
, nVirtualSize
, nAlignment
))
553 DIE(("Can't align the memory size of lodable segment\n"));
555 if(nFileSize
> nVirtualSize
)
556 nFileSize
= nVirtualSize
;
558 if(nVirtualSize
> MAXULONG
)
559 DIE(("Virtual image larger than 4GB\n"));
561 ASSERT(nFileSize
<= MAXULONG
);
563 pssSegments
[j
].Length
= (ULONG
)(nVirtualSize
& 0xFFFFFFFF);
564 pssSegments
[j
].RawLength
= (ULONG
)(nFileSize
& 0xFFFFFFFF);
567 nFileOffset
= ElfFmtpAlignDown(nFileOffset
, nAlignment
);
569 #if __ELF_WORD_SIZE >= 64
570 ASSERT(sizeof(nFileOffset
) == sizeof(LONG64
));
572 if(((LONG64
)nFileOffset
) < 0)
573 DIE(("File offset of loadable segment is too large\n"));
576 pssSegments
[j
].FileOffset
= (LONG64
)nFileOffset
;
578 /* Virtual address */
579 nVirtualAddr
= ElfFmtpAlignDown(nVirtualAddr
, nAlignment
);
583 /* First segment: its address is the base address of the image */
584 nImageBase
= nVirtualAddr
;
585 pssSegments
[j
].VirtualAddress
= 0;
587 /* Several places make this assumption */
588 if(pssSegments
[j
].FileOffset
!= 0)
589 DIE(("First loadable segment doesn't contain the ELF header\n"));
593 Elf_Size nVirtualOffset
;
595 /* Other segment: store the offset from the base address */
596 if(nVirtualAddr
<= nImageBase
)
597 DIE(("Loadable segments are not sorted\n"));
599 nVirtualOffset
= nVirtualAddr
- nImageBase
;
601 if(nVirtualOffset
> MAXULONG
)
602 DIE(("Virtual image larger than 4GB\n"));
604 pssSegments
[j
].VirtualAddress
= (ULONG
)(nVirtualOffset
& 0xFFFFFFFF);
606 if(pssSegments
[j
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
607 DIE(("Loadable segments are not sorted and contiguous\n"));
610 /* Memory protection */
611 pssSegments
[j
].Protection
= ProgramHeaderFlagsToProtect
613 ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_flags
, nData
) & (PF_R
| PF_W
| PF_X
)
616 /* Characteristics */
618 TODO: need to add support for the shared, non-pageable, non-cacheable and
619 discardable attributes. This involves extensions to the ELF format, so it's
620 nothing to be taken lightly
622 if(pssSegments
[j
].Protection
& PAGE_IS_EXECUTABLE
)
624 ImageSectionObject
->Executable
= TRUE
;
625 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_CODE
;
627 else if(pssSegments
[j
].RawLength
== 0)
628 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
630 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
633 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
634 now, if a bit wasteful of memory
636 pssSegments
[j
].Characteristics
|= IMAGE_SCN_MEM_NOT_PAGED
;
639 pssSegments
[j
].WriteCopy
= TRUE
;
641 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[j
].VirtualAddress
, pssSegments
[j
].Length
))
642 DIE(("Virtual image larger than 4GB\n"));
651 DIE(("No loadable segments\n"));
653 ImageSectionObject
->NrSegments
= j
;
656 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
|
657 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
660 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
662 nEntryPoint
= ElfFmtpReadAddr(pehHeader
->e_entry
, nData
);
664 if(nEntryPoint
< nImageBase
|| nEntryPoint
- nImageBase
> nPrevVirtualEndOfSegment
)
665 DIE(("Entry point not within the virtual image\n"));
667 ASSERT(nEntryPoint
>= nImageBase
);
668 ASSERT((nEntryPoint
- nImageBase
) <= MAXULONG
);
669 ImageSectionObject
->EntryPoint
= nEntryPoint
- nImageBase
;
671 /* TODO: support Wine executables and read these values from nt_headers */
672 ImageSectionObject
->ImageCharacteristics
|=
673 IMAGE_FILE_EXECUTABLE_IMAGE
|
674 IMAGE_FILE_LINE_NUMS_STRIPPED
|
675 IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
676 (nImageBase
> MAXULONG
? IMAGE_FILE_LARGE_ADDRESS_AWARE
: 0) |
677 IMAGE_FILE_DEBUG_STRIPPED
;
679 if(nData
== ELFDATA2LSB
)
680 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_LO
;
681 else if(nData
== ELFDATA2MSB
)
682 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_HI
;
684 /* Base address outside the possible address space */
685 if(nImageBase
> MAXULONG_PTR
)
686 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_NONE
;
687 /* Position-independent image, base address doesn't matter */
688 else if(nImageBase
== 0)
689 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_ANY
;
690 /* Use the specified base address */
692 ImageSectionObject
->ImageBase
= (ULONG_PTR
)nImageBase
;
695 ImageSectionObject
->Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
696 ImageSectionObject
->MinorSubsystemVersion
= 0;
697 ImageSectionObject
->MajorSubsystemVersion
= 4;
699 /* Success, at last */
700 nStatus
= STATUS_SUCCESS
;