4 #include <reactos/exeformat.h>
6 #ifndef __ELF_WORD_SIZE
7 #error __ELF_WORD_SIZE must be defined
12 /* TODO: Intsafe should be made into a library, as it's generally useful */
13 static __inline BOOLEAN Intsafe_CanAddULongPtr
19 return Addend1
<= (MAXULONG_PTR
- Addend2
);
22 #define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr
24 static __inline BOOLEAN Intsafe_CanAddULong32
30 return Addend1
<= (MAXULONG
- Addend2
);
33 static __inline BOOLEAN Intsafe_AddULong32
40 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
43 *Result
= Addend1
+ Addend2
;
47 static __inline BOOLEAN Intsafe_CanAddULong64
53 return Addend1
<= (((ULONG64
)-1) - Addend2
);
56 static __inline BOOLEAN Intsafe_AddULong64
63 if(!Intsafe_CanAddULong64(Addend1
, Addend2
))
66 *Result
= Addend1
+ Addend2
;
70 static __inline BOOLEAN Intsafe_CanMulULong32
76 return Factor1
<= (MAXULONG
/ Factor2
);
79 static __inline BOOLEAN Intsafe_MulULong32
86 if(!Intsafe_CanMulULong32(Factor1
, Factor2
))
89 *Result
= Factor1
* Factor2
;
93 static __inline BOOLEAN Intsafe_CanOffsetPointer
95 IN CONST VOID
* Pointer
,
99 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
100 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
103 #if __ELF_WORD_SIZE == 32
104 #define ElfFmtpAddSize Intsafe_AddULong32
105 #define ElfFmtpReadAddr ElfFmtpReadULong
106 #define ElfFmtpReadOff ElfFmtpReadULong
107 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong
108 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong
109 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong
110 #elif __ELF_WORD_SIZE == 64
111 #define ElfFmtpAddSize Intsafe_AddULong64
112 #define ElfFmtpReadAddr ElfFmtpReadULong64
113 #define ElfFmtpReadOff ElfFmtpReadULong64
114 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64
115 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64
116 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64
119 /* TODO: these are standard DDK/PSDK macros */
120 #define RtlRetrieveUlonglong(DST_, SRC_) \
121 (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64)))
123 #ifndef RTL_FIELD_SIZE
124 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
127 #ifndef RTL_SIZEOF_THROUGH_FIELD
128 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
129 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
132 #ifndef RTL_CONTAINS_FIELD
133 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
134 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
137 #define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
139 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
140 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
143 #define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \
145 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \
146 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \
149 #define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \
151 (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \
152 (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \
155 #define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \
157 (((USHORT)(BYTE1_)) << 0) | \
158 (((USHORT)(BYTE2_)) << 8) \
161 static __inline ULONG64 ElfFmtpReadULong64
169 if(DataType
== ELF_TARG_DATA
)
176 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
177 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
184 static __inline ULONG ElfFmtpReadULong
192 if(DataType
== ELF_TARG_DATA
)
199 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
200 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
207 static __inline USHORT ElfFmtpReadUShort
215 if(DataType
== ELF_TARG_DATA
)
222 case ELFDATA2LSB
: return ELFFMT_MAKE_USHORT(p
[0], p
[1]);
223 case ELFDATA2MSB
: return ELFFMT_MAKE_USHORT(p
[1], p
[0]);
230 static __inline ULONG64 ElfFmtpSafeReadULong64
232 IN CONST ULONG64
* Input
,
239 RtlRetrieveUlonglong(&nSafeInput
, Input
);
241 p
= (PUCHAR
)&nSafeInput
;
245 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
246 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
253 static __inline ULONG ElfFmtpSafeReadULong
255 IN CONST ULONG32
* Input
,
263 CONST ULONG32
*ConstInput
;
267 RtlRetrieveUlong(&nSafeInput
, pInput
.Input
);
269 if(DataType
== ELF_TARG_DATA
)
272 p
= (PUCHAR
)&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 return (Number
& (Number
- 1)) == 0;
292 static __inline Elf_Addr ElfFmtpModPow2
295 IN Elf_Addr Alignment
298 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
299 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
300 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
301 return Address
& (Alignment
- 1);
304 static __inline Elf_Addr ElfFmtpAlignDown
307 IN Elf_Addr Alignment
310 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
311 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
312 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
313 return Address
& ~(Alignment
- 1);
316 static __inline BOOLEAN ElfFmtpAlignUp
318 OUT Elf_Addr
* AlignedAddress
,
320 IN Elf_Addr Alignment
323 Elf_Addr nExcess
= ElfFmtpModPow2(Address
, Alignment
);
327 *AlignedAddress
= Address
;
331 return ElfFmtpAddSize(AlignedAddress
, Address
, Alignment
- nExcess
);
336 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
337 (ELF) Specification", Version 1.2
340 #if __ELF_WORD_SIZE == 32
341 Elf32FmtCreateSection
342 #elif __ELF_WORD_SIZE == 64
343 Elf64FmtCreateSection
346 IN CONST VOID
* FileHeader
,
347 IN SIZE_T FileHeaderSize
,
349 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
351 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
352 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
356 const Elf_Ehdr
* pehHeader
;
357 const Elf_Phdr
* pphPHdrs
;
358 BOOLEAN fPageAligned
;
362 Elf_Off cbPHdrOffset
;
364 PMM_SECTION_SEGMENT pssSegments
;
365 Elf_Addr nImageBase
= 0;
366 Elf_Addr nEntryPoint
;
367 ULONG32 nPrevVirtualEndOfSegment
= 0;
371 (void)Intsafe_AddULong64
;
372 (void)Intsafe_MulULong32
;
373 (void)ElfFmtpReadULong64
;
374 (void)ElfFmtpSafeReadULong64
;
375 (void)ElfFmtpReadULong
;
377 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
381 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
383 /* Ensure the file contains the full header */
385 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
386 all the classes defined as of December 2004). If FileHeaderSize is less than
387 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
390 ASSERT(sizeof(Elf_Ehdr
) <= EXEFMT_LOAD_HEADER_SIZE
);
392 if(FileHeaderSize
< sizeof(Elf_Ehdr
))
393 DIE(("The file is truncated, doesn't contain the full header\n"));
395 pehHeader
= FileHeader
;
396 ASSERT(((ULONG_PTR
)pehHeader
% TYPE_ALIGNMENT(Elf_Ehdr
)) == 0);
398 nData
= pehHeader
->e_ident
[EI_DATA
];
400 /* Validate the header */
401 if(ElfFmtpReadUShort(pehHeader
->e_ehsize
, nData
) < sizeof(Elf_Ehdr
))
402 DIE(("Inconsistent value for e_ehsize\n"));
404 /* Calculate size and offset of the program headers */
405 cbPHdrSize
= ElfFmtpReadUShort(pehHeader
->e_phentsize
, nData
);
407 if(cbPHdrSize
!= sizeof(Elf_Phdr
))
408 DIE(("Inconsistent value for e_phentsize\n"));
410 /* MAXUSHORT * MAXUSHORT < MAXULONG */
411 nPHdrCount
= ElfFmtpReadUShort(pehHeader
->e_phnum
, nData
);
412 ASSERT(Intsafe_CanMulULong32(cbPHdrSize
, nPHdrCount
));
413 cbPHdrSize
*= nPHdrCount
;
415 cbPHdrOffset
= ElfFmtpReadOff(pehHeader
->e_phoff
, nData
);
417 /* The initial header doesn't contain the program headers */
418 if(cbPHdrOffset
> FileHeaderSize
|| cbPHdrSize
> (FileHeaderSize
- cbPHdrOffset
))
420 NTSTATUS nReadStatus
;
421 LARGE_INTEGER lnOffset
;
425 /* Will worry about this when ELF128 comes */
426 ASSERT(sizeof(cbPHdrOffset
) <= sizeof(lnOffset
.QuadPart
));
428 lnOffset
.QuadPart
= (LONG64
)cbPHdrOffset
;
431 We can't support executable files larger than 8 Exabytes - it's a limitation
432 of the I/O system (only 63-bit offsets are supported). Quote:
434 [...] the total amount of printed material in the world is estimated to be
435 around a fifth of an exabyte. [...] [Source: Wikipedia]
437 if(lnOffset
.u
.HighPart
< 0)
438 DIE(("The program header is too far into the file\n"));
440 nReadStatus
= ReadFileCb
450 if(!NT_SUCCESS(nReadStatus
))
452 nStatus
= nReadStatus
;
453 DIE(("ReadFile failed, status %08X\n", nStatus
));
458 ASSERT(Intsafe_CanOffsetPointer(pData
, cbReadSize
));
460 if(cbReadSize
< cbPHdrSize
)
461 DIE(("The file didn't contain the program headers\n"));
463 /* Force the buffer to be aligned */
464 if((ULONG_PTR
)pData
% TYPE_ALIGNMENT(Elf_Phdr
))
466 ASSERT(((ULONG_PTR
)pBuffer
% TYPE_ALIGNMENT(Elf_Phdr
)) == 0);
467 RtlMoveMemory(pBuffer
, pData
, cbPHdrSize
);
475 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset
, 0));
476 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbPHdrOffset
));
477 pphPHdrs
= (PVOID
)((ULONG_PTR
)FileHeader
+ (ULONG_PTR
)cbPHdrOffset
);
480 /* Allocate the segments */
481 pssSegments
= AllocateSegmentsCb(nPHdrCount
);
483 if(pssSegments
== NULL
)
485 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
486 DIE(("Out of memory\n"));
489 ImageSectionObject
->Segments
= pssSegments
;
493 /* Fill in the segments */
494 for(i
= 0, j
= 0; i
< nPHdrCount
; ++ i
)
496 switch(ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_type
, nData
))
500 static const ULONG ProgramHeaderFlagsToProtect
[8] =
502 PAGE_NOACCESS
, /* 0 */
503 PAGE_EXECUTE_READ
, /* PF_X */
504 PAGE_READWRITE
, /* PF_W */
505 PAGE_EXECUTE_READWRITE
, /* PF_X | PF_W */
506 PAGE_READONLY
, /* PF_R */
507 PAGE_EXECUTE_READ
, /* PF_X | PF_R */
508 PAGE_READWRITE
, /* PF_W | PF_R */
509 PAGE_EXECUTE_READWRITE
/* PF_X | PF_W | PF_R */
514 Elf_Addr nVirtualAddr
;
516 Elf_Size nVirtualSize
= 0;
517 Elf_Size nFileSize
= 0;
519 ASSERT(j
<= nPHdrCount
);
521 /* Retrieve and validate the segment alignment */
522 nAlignment
= ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_align
, nData
);
526 else if(!ElfFmtpIsPowerOf2(nAlignment
))
527 DIE(("Alignment of loadable segment isn't a power of 2\n"));
529 if(nAlignment
< PAGE_SIZE
)
530 fPageAligned
= FALSE
;
532 /* Retrieve the addresses and calculate the adjustment */
533 nFileOffset
= ElfFmtpSafeReadOff(&pphPHdrs
[i
].p_offset
, nData
);
534 nVirtualAddr
= ElfFmtpSafeReadAddr(&pphPHdrs
[i
].p_vaddr
, nData
);
536 nAdj
= ElfFmtpModPow2(nFileOffset
, nAlignment
);
538 if(nAdj
!= ElfFmtpModPow2(nVirtualAddr
, nAlignment
))
539 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
541 /* Retrieve, adjust and align the file size and memory size */
542 if(!ElfFmtpAddSize(&nFileSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_filesz
, nData
), nAdj
))
543 DIE(("Can't adjust the file size of loadable segment\n"));
545 if(!ElfFmtpAddSize(&nVirtualSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_memsz
, nData
), nAdj
))
546 DIE(("Can't adjust the memory size of lodable segment\n"));
548 if(!ElfFmtpAlignUp(&nVirtualSize
, nVirtualSize
, nAlignment
))
549 DIE(("Can't align the memory size of lodable segment\n"));
551 if(nFileSize
> nVirtualSize
)
552 nFileSize
= nVirtualSize
;
554 if(nVirtualSize
> MAXULONG
)
555 DIE(("Virtual image larger than 4GB\n"));
557 ASSERT(nFileSize
<= MAXULONG
);
559 pssSegments
[j
].Length
= (ULONG
)(nVirtualSize
& 0xFFFFFFFF);
560 pssSegments
[j
].RawLength
= (ULONG
)(nFileSize
& 0xFFFFFFFF);
563 nFileOffset
= ElfFmtpAlignDown(nFileOffset
, nAlignment
);
565 #if __ELF_WORD_SIZE >= 64
566 ASSERT(sizeof(nFileOffset
) == sizeof(LONG64
));
568 if(((LONG64
)nFileOffset
) < 0)
569 DIE(("File offset of loadable segment is too large\n"));
572 pssSegments
[j
].FileOffset
= (LONG64
)nFileOffset
;
574 /* Virtual address */
575 nVirtualAddr
= ElfFmtpAlignDown(nVirtualAddr
, nAlignment
);
579 /* First segment: its address is the base address of the image */
580 nImageBase
= nVirtualAddr
;
581 pssSegments
[j
].VirtualAddress
= 0;
583 /* Several places make this assumption */
584 if(pssSegments
[j
].FileOffset
!= 0)
585 DIE(("First loadable segment doesn't contain the ELF header\n"));
589 Elf_Size nVirtualOffset
;
591 /* Other segment: store the offset from the base address */
592 if(nVirtualAddr
<= nImageBase
)
593 DIE(("Loadable segments are not sorted\n"));
595 nVirtualOffset
= nVirtualAddr
- nImageBase
;
597 if(nVirtualOffset
> MAXULONG
)
598 DIE(("Virtual image larger than 4GB\n"));
600 pssSegments
[j
].VirtualAddress
= (ULONG
)(nVirtualOffset
& 0xFFFFFFFF);
602 if(pssSegments
[j
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
603 DIE(("Loadable segments are not sorted and contiguous\n"));
606 /* Memory protection */
607 pssSegments
[j
].Protection
= ProgramHeaderFlagsToProtect
609 ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_flags
, nData
) & (PF_R
| PF_W
| PF_X
)
612 /* Characteristics */
614 TODO: need to add support for the shared, non-pageable, non-cacheable and
615 discardable attributes. This involves extensions to the ELF format, so it's
616 nothing to be taken lightly
618 if(pssSegments
[j
].Protection
& PAGE_IS_EXECUTABLE
)
620 ImageSectionObject
->Executable
= TRUE
;
621 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_CODE
;
623 else if(pssSegments
[j
].RawLength
== 0)
624 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
626 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
629 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
630 now, if a bit wasteful of memory
632 pssSegments
[j
].Characteristics
|= IMAGE_SCN_MEM_NOT_PAGED
;
635 pssSegments
[j
].WriteCopy
= TRUE
;
637 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[j
].VirtualAddress
, pssSegments
[j
].Length
))
638 DIE(("Virtual image larger than 4GB\n"));
647 DIE(("No loadable segments\n"));
649 ImageSectionObject
->NrSegments
= j
;
652 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
|
653 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
656 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
658 nEntryPoint
= ElfFmtpReadAddr(pehHeader
->e_entry
, nData
);
660 if(nEntryPoint
< nImageBase
|| nEntryPoint
- nImageBase
> nPrevVirtualEndOfSegment
)
661 DIE(("Entry point not within the virtual image\n"));
663 ASSERT(nEntryPoint
>= nImageBase
);
664 ASSERT((nEntryPoint
- nImageBase
) <= MAXULONG
);
665 ImageSectionObject
->EntryPoint
= nEntryPoint
- nImageBase
;
667 /* TODO: support Wine executables and read these values from nt_headers */
668 ImageSectionObject
->ImageCharacteristics
|=
669 IMAGE_FILE_EXECUTABLE_IMAGE
|
670 IMAGE_FILE_LINE_NUMS_STRIPPED
|
671 IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
672 (nImageBase
> MAXULONG
? IMAGE_FILE_LARGE_ADDRESS_AWARE
: 0) |
673 IMAGE_FILE_DEBUG_STRIPPED
;
675 if(nData
== ELFDATA2LSB
)
676 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_LO
;
677 else if(nData
== ELFDATA2MSB
)
678 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_HI
;
680 /* Base address outside the possible address space */
681 if(nImageBase
> MAXULONG_PTR
)
682 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_NONE
;
683 /* Position-independent image, base address doesn't matter */
684 else if(nImageBase
== 0)
685 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_ANY
;
686 /* Use the specified base address */
688 ImageSectionObject
->ImageBase
= (ULONG_PTR
)nImageBase
;
691 ImageSectionObject
->Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
692 ImageSectionObject
->MinorSubsystemVersion
= 0;
693 ImageSectionObject
->MajorSubsystemVersion
= 4;
695 /* Success, at last */
696 nStatus
= STATUS_SUCCESS
;