6 #include <internal/debug.h>
8 #include <reactos/exeformat.h>
10 #ifndef __ELF_WORD_SIZE
11 #error __ELF_WORD_SIZE must be defined
15 #define MAXULONG ((ULONG)(~1))
20 /* TODO: Intsafe should be made into a library, as it's generally useful */
21 static __inline BOOLEAN Intsafe_CanAddULongPtr
27 return Addend1
<= (MAXULONG_PTR
- Addend2
);
30 #define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr
32 static __inline BOOLEAN Intsafe_CanAddULong32
38 return Addend1
<= (MAXULONG
- Addend2
);
41 static __inline BOOLEAN Intsafe_AddULong32
48 if(!Intsafe_CanAddULong32(Addend1
, Addend2
))
51 *Result
= Addend1
+ Addend2
;
55 static __inline BOOLEAN Intsafe_CanAddULong64
61 return Addend1
<= (((ULONG64
)-1) - Addend2
);
64 static __inline BOOLEAN Intsafe_AddULong64
71 if(!Intsafe_CanAddULong64(Addend1
, Addend2
))
74 *Result
= Addend1
+ Addend2
;
78 static __inline BOOLEAN Intsafe_CanMulULong32
84 return Factor1
<= (MAXULONG
/ Factor2
);
87 static __inline BOOLEAN Intsafe_MulULong32
94 if(!Intsafe_CanMulULong32(Factor1
, Factor2
))
97 *Result
= Factor1
* Factor2
;
101 static __inline BOOLEAN Intsafe_CanOffsetPointer
103 IN CONST VOID
* Pointer
,
107 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
108 return Intsafe_CanAddULongPtr((ULONG_PTR
)Pointer
, Offset
);
111 #if __ELF_WORD_SIZE == 32
112 #define ElfFmtpAddSize Intsafe_AddULong32
113 #define ElfFmtpReadAddr ElfFmtpReadULong
114 #define ElfFmtpReadOff ElfFmtpReadULong
115 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong
116 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong
117 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong
118 #elif __ELF_WORD_SIZE == 64
119 #define ElfFmtpAddSize Intsafe_AddULong64
120 #define ElfFmtpReadAddr ElfFmtpReadULong64
121 #define ElfFmtpReadOff ElfFmtpReadULong64
122 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64
123 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64
124 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64
127 /* TODO: these are standard DDK/PSDK macros */
128 #define RtlRetrieveUlonglong(DST_, SRC_) \
129 (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64)))
131 #ifndef RTL_FIELD_SIZE
132 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
135 #ifndef RTL_SIZEOF_THROUGH_FIELD
136 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
137 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
140 #ifndef RTL_CONTAINS_FIELD
141 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
142 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
145 #define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
147 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
148 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
151 #define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \
153 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \
154 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \
157 #define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \
159 (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \
160 (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \
163 #define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \
165 (((USHORT)(BYTE1_)) << 0) | \
166 (((USHORT)(BYTE2_)) << 8) \
169 static __inline ULONG64 ElfFmtpReadULong64
177 if(DataType
== ELF_TARG_DATA
)
184 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
185 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
192 static __inline ULONG ElfFmtpReadULong
200 if(DataType
== ELF_TARG_DATA
)
207 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
208 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
215 static __inline USHORT ElfFmtpReadUShort
223 if(DataType
== ELF_TARG_DATA
)
230 case ELFDATA2LSB
: return ELFFMT_MAKE_USHORT(p
[0], p
[1]);
231 case ELFDATA2MSB
: return ELFFMT_MAKE_USHORT(p
[1], p
[0]);
238 static __inline ULONG64 ElfFmtpSafeReadULong64
240 IN CONST ULONG64
* Input
,
247 RtlRetrieveUlonglong(&nSafeInput
, Input
);
249 p
= (PUCHAR
)&nSafeInput
;
253 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG64(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
254 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG64(p
[7], p
[6], p
[5], p
[4], p
[3], p
[2], p
[1], p
[0]);
261 static __inline ULONG ElfFmtpSafeReadULong
263 IN CONST ULONG32
* Input
,
271 CONST ULONG32
*ConstInput
;
275 RtlRetrieveUlong(&nSafeInput
, pInput
.Input
);
277 if(DataType
== ELF_TARG_DATA
)
280 p
= (PUCHAR
)&nSafeInput
;
284 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
285 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
292 static __inline BOOLEAN
ElfFmtpIsPowerOf2(IN Elf_Addr Number
)
297 return (Number
& (Number
- 1)) == 0;
300 static __inline Elf_Addr ElfFmtpModPow2
303 IN Elf_Addr Alignment
306 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
307 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
308 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
309 return Address
& (Alignment
- 1);
312 static __inline Elf_Addr ElfFmtpAlignDown
315 IN Elf_Addr Alignment
318 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
319 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
320 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
321 return Address
& ~(Alignment
- 1);
324 static __inline BOOLEAN ElfFmtpAlignUp
326 OUT Elf_Addr
* AlignedAddress
,
328 IN Elf_Addr Alignment
331 Elf_Addr nExcess
= ElfFmtpModPow2(Address
, Alignment
);
335 *AlignedAddress
= Address
;
339 return ElfFmtpAddSize(AlignedAddress
, Address
, Alignment
- nExcess
);
344 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
345 (ELF) Specification", Version 1.2
348 #if __ELF_WORD_SIZE == 32
349 Elf32FmtCreateSection
350 #elif __ELF_WORD_SIZE == 64
351 Elf64FmtCreateSection
354 IN CONST VOID
* FileHeader
,
355 IN SIZE_T FileHeaderSize
,
357 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
359 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
360 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
364 const Elf_Ehdr
* pehHeader
;
365 const Elf_Phdr
* pphPHdrs
;
366 BOOLEAN fPageAligned
;
370 Elf_Off cbPHdrOffset
;
372 PMM_SECTION_SEGMENT pssSegments
;
373 Elf_Addr nImageBase
= 0;
374 Elf_Addr nEntryPoint
;
375 ULONG32 nPrevVirtualEndOfSegment
= 0;
379 (void)Intsafe_AddULong64
;
380 (void)Intsafe_MulULong32
;
381 (void)ElfFmtpReadULong64
;
382 (void)ElfFmtpSafeReadULong64
;
383 (void)ElfFmtpReadULong
;
385 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
389 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
391 /* Ensure the file contains the full header */
393 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
394 all the classes defined as of December 2004). If FileHeaderSize is less than
395 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
398 ASSERT(sizeof(Elf_Ehdr
) <= EXEFMT_LOAD_HEADER_SIZE
);
400 if(FileHeaderSize
< sizeof(Elf_Ehdr
))
401 DIE(("The file is truncated, doesn't contain the full header\n"));
403 pehHeader
= FileHeader
;
404 ASSERT(((ULONG_PTR
)pehHeader
% TYPE_ALIGNMENT(Elf_Ehdr
)) == 0);
406 nData
= pehHeader
->e_ident
[EI_DATA
];
408 /* Validate the header */
409 if(ElfFmtpReadUShort(pehHeader
->e_ehsize
, nData
) < sizeof(Elf_Ehdr
))
410 DIE(("Inconsistent value for e_ehsize\n"));
412 /* Calculate size and offset of the program headers */
413 cbPHdrSize
= ElfFmtpReadUShort(pehHeader
->e_phentsize
, nData
);
415 if(cbPHdrSize
!= sizeof(Elf_Phdr
))
416 DIE(("Inconsistent value for e_phentsize\n"));
418 /* MAXUSHORT * MAXUSHORT < MAXULONG */
419 nPHdrCount
= ElfFmtpReadUShort(pehHeader
->e_phnum
, nData
);
420 ASSERT(Intsafe_CanMulULong32(cbPHdrSize
, nPHdrCount
));
421 cbPHdrSize
*= nPHdrCount
;
423 cbPHdrOffset
= ElfFmtpReadOff(pehHeader
->e_phoff
, nData
);
425 /* The initial header doesn't contain the program headers */
426 if(cbPHdrOffset
> FileHeaderSize
|| cbPHdrSize
> (FileHeaderSize
- cbPHdrOffset
))
428 NTSTATUS nReadStatus
;
429 LARGE_INTEGER lnOffset
;
433 /* Will worry about this when ELF128 comes */
434 ASSERT(sizeof(cbPHdrOffset
) <= sizeof(lnOffset
.QuadPart
));
436 lnOffset
.QuadPart
= (LONG64
)cbPHdrOffset
;
439 We can't support executable files larger than 8 Exabytes - it's a limitation
440 of the I/O system (only 63-bit offsets are supported). Quote:
442 [...] the total amount of printed material in the world is estimated to be
443 around a fifth of an exabyte. [...] [Source: Wikipedia]
445 if(lnOffset
.u
.HighPart
< 0)
446 DIE(("The program header is too far into the file\n"));
448 nReadStatus
= ReadFileCb
458 if(!NT_SUCCESS(nReadStatus
))
460 nStatus
= nReadStatus
;
461 DIE(("ReadFile failed, status %08X\n", nStatus
));
466 ASSERT(Intsafe_CanOffsetPointer(pData
, cbReadSize
));
468 if(cbReadSize
< cbPHdrSize
)
469 DIE(("The file didn't contain the program headers\n"));
471 /* Force the buffer to be aligned */
472 if((ULONG_PTR
)pData
% TYPE_ALIGNMENT(Elf_Phdr
))
474 ASSERT(((ULONG_PTR
)pBuffer
% TYPE_ALIGNMENT(Elf_Phdr
)) == 0);
475 RtlMoveMemory(pBuffer
, pData
, cbPHdrSize
);
483 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset
, 0));
484 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbPHdrOffset
));
485 pphPHdrs
= (PVOID
)((ULONG_PTR
)FileHeader
+ (ULONG_PTR
)cbPHdrOffset
);
488 /* Allocate the segments */
489 pssSegments
= AllocateSegmentsCb(nPHdrCount
);
491 if(pssSegments
== NULL
)
493 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
494 DIE(("Out of memory\n"));
497 ImageSectionObject
->Segments
= pssSegments
;
501 /* Fill in the segments */
502 for(i
= 0, j
= 0; i
< nPHdrCount
; ++ i
)
504 switch(ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_type
, nData
))
508 static const ULONG ProgramHeaderFlagsToProtect
[8] =
510 PAGE_NOACCESS
, /* 0 */
511 PAGE_EXECUTE_READ
, /* PF_X */
512 PAGE_READWRITE
, /* PF_W */
513 PAGE_EXECUTE_READWRITE
, /* PF_X | PF_W */
514 PAGE_READONLY
, /* PF_R */
515 PAGE_EXECUTE_READ
, /* PF_X | PF_R */
516 PAGE_READWRITE
, /* PF_W | PF_R */
517 PAGE_EXECUTE_READWRITE
/* PF_X | PF_W | PF_R */
522 Elf_Addr nVirtualAddr
;
524 Elf_Size nVirtualSize
= 0;
525 Elf_Size nFileSize
= 0;
527 ASSERT(j
<= nPHdrCount
);
529 /* Retrieve and validate the segment alignment */
530 nAlignment
= ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_align
, nData
);
534 else if(!ElfFmtpIsPowerOf2(nAlignment
))
535 DIE(("Alignment of loadable segment isn't a power of 2\n"));
537 if(nAlignment
< PAGE_SIZE
)
538 fPageAligned
= FALSE
;
540 /* Retrieve the addresses and calculate the adjustment */
541 nFileOffset
= ElfFmtpSafeReadOff(&pphPHdrs
[i
].p_offset
, nData
);
542 nVirtualAddr
= ElfFmtpSafeReadAddr(&pphPHdrs
[i
].p_vaddr
, nData
);
544 nAdj
= ElfFmtpModPow2(nFileOffset
, nAlignment
);
546 if(nAdj
!= ElfFmtpModPow2(nVirtualAddr
, nAlignment
))
547 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
549 /* Retrieve, adjust and align the file size and memory size */
550 if(!ElfFmtpAddSize(&nFileSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_filesz
, nData
), nAdj
))
551 DIE(("Can't adjust the file size of loadable segment\n"));
553 if(!ElfFmtpAddSize(&nVirtualSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_memsz
, nData
), nAdj
))
554 DIE(("Can't adjust the memory size of lodable segment\n"));
556 if(!ElfFmtpAlignUp(&nVirtualSize
, nVirtualSize
, nAlignment
))
557 DIE(("Can't align the memory size of lodable segment\n"));
559 if(nFileSize
> nVirtualSize
)
560 nFileSize
= nVirtualSize
;
562 if(nVirtualSize
> MAXULONG
)
563 DIE(("Virtual image larger than 4GB\n"));
565 ASSERT(nFileSize
<= MAXULONG
);
567 pssSegments
[j
].Length
= (ULONG
)(nVirtualSize
& 0xFFFFFFFF);
568 pssSegments
[j
].RawLength
= (ULONG
)(nFileSize
& 0xFFFFFFFF);
571 nFileOffset
= ElfFmtpAlignDown(nFileOffset
, nAlignment
);
573 #if __ELF_WORD_SIZE >= 64
574 ASSERT(sizeof(nFileOffset
) == sizeof(LONG64
));
576 if(((LONG64
)nFileOffset
) < 0)
577 DIE(("File offset of loadable segment is too large\n"));
580 pssSegments
[j
].FileOffset
= (LONG64
)nFileOffset
;
582 /* Virtual address */
583 nVirtualAddr
= ElfFmtpAlignDown(nVirtualAddr
, nAlignment
);
587 /* First segment: its address is the base address of the image */
588 nImageBase
= nVirtualAddr
;
589 pssSegments
[j
].VirtualAddress
= 0;
591 /* Several places make this assumption */
592 if(pssSegments
[j
].FileOffset
!= 0)
593 DIE(("First loadable segment doesn't contain the ELF header\n"));
597 Elf_Size nVirtualOffset
;
599 /* Other segment: store the offset from the base address */
600 if(nVirtualAddr
<= nImageBase
)
601 DIE(("Loadable segments are not sorted\n"));
603 nVirtualOffset
= nVirtualAddr
- nImageBase
;
605 if(nVirtualOffset
> MAXULONG
)
606 DIE(("Virtual image larger than 4GB\n"));
608 pssSegments
[j
].VirtualAddress
= (ULONG
)(nVirtualOffset
& 0xFFFFFFFF);
610 if(pssSegments
[j
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
611 DIE(("Loadable segments are not sorted and contiguous\n"));
614 /* Memory protection */
615 pssSegments
[j
].Protection
= ProgramHeaderFlagsToProtect
617 ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_flags
, nData
) & (PF_R
| PF_W
| PF_X
)
620 /* Characteristics */
622 TODO: need to add support for the shared, non-pageable, non-cacheable and
623 discardable attributes. This involves extensions to the ELF format, so it's
624 nothing to be taken lightly
626 if(pssSegments
[j
].Protection
& PAGE_IS_EXECUTABLE
)
628 ImageSectionObject
->Executable
= TRUE
;
629 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_CODE
;
631 else if(pssSegments
[j
].RawLength
== 0)
632 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
634 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
637 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
638 now, if a bit wasteful of memory
640 pssSegments
[j
].Characteristics
|= IMAGE_SCN_MEM_NOT_PAGED
;
643 pssSegments
[j
].WriteCopy
= TRUE
;
645 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[j
].VirtualAddress
, pssSegments
[j
].Length
))
646 DIE(("Virtual image larger than 4GB\n"));
655 DIE(("No loadable segments\n"));
657 ImageSectionObject
->NrSegments
= j
;
660 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
|
661 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
664 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
666 nEntryPoint
= ElfFmtpReadAddr(pehHeader
->e_entry
, nData
);
668 if(nEntryPoint
< nImageBase
|| nEntryPoint
- nImageBase
> nPrevVirtualEndOfSegment
)
669 DIE(("Entry point not within the virtual image\n"));
671 ASSERT(nEntryPoint
>= nImageBase
);
672 ASSERT((nEntryPoint
- nImageBase
) <= MAXULONG
);
673 ImageSectionObject
->EntryPoint
= nEntryPoint
- nImageBase
;
675 /* TODO: support Wine executables and read these values from nt_headers */
676 ImageSectionObject
->ImageCharacteristics
|=
677 IMAGE_FILE_EXECUTABLE_IMAGE
|
678 IMAGE_FILE_LINE_NUMS_STRIPPED
|
679 IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
680 (nImageBase
> MAXULONG
? IMAGE_FILE_LARGE_ADDRESS_AWARE
: 0) |
681 IMAGE_FILE_DEBUG_STRIPPED
;
683 if(nData
== ELFDATA2LSB
)
684 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_LO
;
685 else if(nData
== ELFDATA2MSB
)
686 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_HI
;
688 /* Base address outside the possible address space */
689 if(nImageBase
> MAXULONG_PTR
)
690 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_NONE
;
691 /* Position-independent image, base address doesn't matter */
692 else if(nImageBase
== 0)
693 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_ANY
;
694 /* Use the specified base address */
696 ImageSectionObject
->ImageBase
= (ULONG_PTR
)nImageBase
;
699 ImageSectionObject
->Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
700 ImageSectionObject
->MinorSubsystemVersion
= 0;
701 ImageSectionObject
->MajorSubsystemVersion
= 4;
703 /* Success, at last */
704 nStatus
= STATUS_SUCCESS
;