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 ((((char *)(P_)) + (SIZE_)) > (((char *)(&((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
= (PBYTE
)&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
,
270 RtlRetrieveUlong(&nSafeInput
, Input
);
272 if(DataType
== ELF_TARG_DATA
)
275 p
= (PBYTE
)&nSafeInput
;
279 case ELFDATA2LSB
: return ELFFMT_MAKE_ULONG(p
[0], p
[1], p
[2], p
[3]);
280 case ELFDATA2MSB
: return ELFFMT_MAKE_ULONG(p
[3], p
[2], p
[1], p
[0]);
287 static __inline BOOLEAN
ElfFmtpIsPowerOf2(IN Elf_Addr Number
)
292 while((Number
% 2) == 0)
298 static __inline Elf_Addr ElfFmtpModPow2
301 IN Elf_Addr Alignment
304 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
305 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
306 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
307 return Address
& (Alignment
- 1);
310 static __inline Elf_Addr ElfFmtpAlignDown
313 IN Elf_Addr Alignment
316 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Size
));
317 ASSERT(sizeof(Elf_Addr
) == sizeof(Elf_Off
));
318 ASSERT(ElfFmtpIsPowerOf2(Alignment
));
319 return Address
& ~(Alignment
- 1);
322 static __inline BOOLEAN ElfFmtpAlignUp
324 OUT Elf_Addr
* AlignedAddress
,
326 IN Elf_Addr Alignment
329 Elf_Addr nExcess
= ElfFmtpModPow2(Address
, Alignment
);
333 *AlignedAddress
= Address
;
337 return ElfFmtpAddSize(AlignedAddress
, Address
, Alignment
- nExcess
);
342 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
343 (ELF) Specification", Version 1.2
346 #if __ELF_WORD_SIZE == 32
347 Elf32FmtCreateSection
348 #elif __ELF_WORD_SIZE == 64
349 Elf64FmtCreateSection
352 IN CONST VOID
* FileHeader
,
353 IN SIZE_T FileHeaderSize
,
355 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
357 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
358 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
362 const Elf_Ehdr
* pehHeader
;
363 const Elf_Phdr
* pphPHdrs
;
364 BOOLEAN fPageAligned
;
368 Elf_Off cbPHdrOffset
;
370 PMM_SECTION_SEGMENT pssSegments
;
371 Elf_Addr nImageBase
= 0;
372 Elf_Addr nEntryPoint
;
373 ULONG32 nPrevVirtualEndOfSegment
= 0;
377 (void)Intsafe_AddULong64
;
378 (void)Intsafe_MulULong32
;
379 (void)ElfFmtpReadULong64
;
380 (void)ElfFmtpSafeReadULong64
;
381 (void)ElfFmtpReadULong
;
383 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
387 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
389 /* Ensure the file contains the full header */
391 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
392 all the classes defined as of December 2004). If FileHeaderSize is less than
393 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
396 ASSERT(sizeof(Elf_Ehdr
) <= EXEFMT_LOAD_HEADER_SIZE
);
398 if(FileHeaderSize
< sizeof(Elf_Ehdr
))
399 DIE(("The file is truncated, doesn't contain the full header\n"));
401 pehHeader
= FileHeader
;
402 ASSERT(((ULONG_PTR
)pehHeader
% TYPE_ALIGNMENT(Elf_Ehdr
)) == 0);
404 nData
= pehHeader
->e_ident
[EI_DATA
];
406 /* Validate the header */
407 if(ElfFmtpReadUShort(pehHeader
->e_ehsize
, nData
) < sizeof(Elf_Ehdr
))
408 DIE(("Inconsistent value for e_ehsize\n"));
410 /* Calculate size and offset of the program headers */
411 cbPHdrSize
= ElfFmtpReadUShort(pehHeader
->e_phentsize
, nData
);
413 if(cbPHdrSize
!= sizeof(Elf_Phdr
))
414 DIE(("Inconsistent value for e_phentsize\n"));
416 /* MAXUSHORT * MAXUSHORT < MAXULONG */
417 nPHdrCount
= ElfFmtpReadUShort(pehHeader
->e_phnum
, nData
);
418 ASSERT(Intsafe_CanMulULong32(cbPHdrSize
, nPHdrCount
));
419 cbPHdrSize
*= nPHdrCount
;
421 cbPHdrOffset
= ElfFmtpReadOff(pehHeader
->e_phoff
, nData
);
423 /* The initial header doesn't contain the program headers */
424 if(cbPHdrOffset
> FileHeaderSize
|| cbPHdrSize
> (FileHeaderSize
- cbPHdrOffset
))
426 NTSTATUS nReadStatus
;
427 LARGE_INTEGER lnOffset
;
431 /* Will worry about this when ELF128 comes */
432 ASSERT(sizeof(cbPHdrOffset
) <= sizeof(lnOffset
.QuadPart
));
434 lnOffset
.QuadPart
= (LONG64
)cbPHdrOffset
;
437 We can't support executable files larger than 8 Exabytes - it's a limitation
438 of the I/O system (only 63-bit offsets are supported). Quote:
440 [...] the total amount of printed material in the world is estimated to be
441 around a fifth of an exabyte. [...] [Source: Wikipedia]
443 if(lnOffset
.u
.HighPart
< 0)
444 DIE(("The program header is too far into the file\n"));
446 nReadStatus
= ReadFileCb
456 if(!NT_SUCCESS(nReadStatus
))
458 nStatus
= nReadStatus
;
459 DIE(("ReadFile failed, status %08X\n", nStatus
));
464 ASSERT(Intsafe_CanOffsetPointer(pData
, cbReadSize
));
466 if(cbReadSize
< cbPHdrSize
)
467 DIE(("The file didn't contain the program headers\n"));
469 /* Force the buffer to be aligned */
470 if((ULONG_PTR
)pData
% TYPE_ALIGNMENT(Elf_Phdr
))
472 ASSERT(((ULONG_PTR
)pBuffer
% TYPE_ALIGNMENT(Elf_Phdr
)) == 0);
473 RtlMoveMemory(pBuffer
, pData
, cbPHdrSize
);
481 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset
, 0));
482 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbPHdrOffset
));
483 pphPHdrs
= (PVOID
)((ULONG_PTR
)FileHeader
+ (ULONG_PTR
)cbPHdrOffset
);
486 /* Allocate the segments */
487 pssSegments
= AllocateSegmentsCb(nPHdrCount
);
489 if(pssSegments
== NULL
)
491 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
492 DIE(("Out of memory\n"));
495 ImageSectionObject
->Segments
= pssSegments
;
499 /* Fill in the segments */
500 for(i
= 0, j
= 0; i
< nPHdrCount
; ++ i
)
502 switch(ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_type
, nData
))
506 static const ULONG ProgramHeaderFlagsToProtect
[8] =
508 PAGE_NOACCESS
, /* 0 */
509 PAGE_EXECUTE_READ
, /* PF_X */
510 PAGE_READWRITE
, /* PF_W */
511 PAGE_EXECUTE_READWRITE
, /* PF_X | PF_W */
512 PAGE_READONLY
, /* PF_R */
513 PAGE_EXECUTE_READ
, /* PF_X | PF_R */
514 PAGE_READWRITE
, /* PF_W | PF_R */
515 PAGE_EXECUTE_READWRITE
/* PF_X | PF_W | PF_R */
520 Elf_Addr nVirtualAddr
;
522 Elf_Size nVirtualSize
= 0;
523 Elf_Size nFileSize
= 0;
525 ASSERT(j
<= nPHdrCount
);
527 /* Retrieve and validate the segment alignment */
528 nAlignment
= ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_align
, nData
);
532 else if(!ElfFmtpIsPowerOf2(nAlignment
))
533 DIE(("Alignment of loadable segment isn't a power of 2\n"));
535 if(nAlignment
< PAGE_SIZE
)
536 fPageAligned
= FALSE
;
538 /* Retrieve the addresses and calculate the adjustment */
539 nFileOffset
= ElfFmtpSafeReadOff(&pphPHdrs
[i
].p_offset
, nData
);
540 nVirtualAddr
= ElfFmtpSafeReadAddr(&pphPHdrs
[i
].p_vaddr
, nData
);
542 nAdj
= ElfFmtpModPow2(nFileOffset
, nAlignment
);
544 if(nAdj
!= ElfFmtpModPow2(nVirtualAddr
, nAlignment
))
545 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
547 /* Retrieve, adjust and align the file size and memory size */
548 if(!ElfFmtpAddSize(&nFileSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_filesz
, nData
), nAdj
))
549 DIE(("Can't adjust the file size of loadable segment\n"));
551 if(!ElfFmtpAddSize(&nVirtualSize
, ElfFmtpSafeReadSize(&pphPHdrs
[i
].p_memsz
, nData
), nAdj
))
552 DIE(("Can't adjust the memory size of lodable segment\n"));
554 if(!ElfFmtpAlignUp(&nVirtualSize
, nVirtualSize
, nAlignment
))
555 DIE(("Can't align the memory size of lodable segment\n"));
557 if(nFileSize
> nVirtualSize
)
558 nFileSize
= nVirtualSize
;
560 if(nVirtualSize
> MAXULONG
)
561 DIE(("Virtual image larger than 4GB\n"));
563 ASSERT(nFileSize
<= MAXULONG
);
565 pssSegments
[j
].Length
= (ULONG
)(nVirtualSize
& 0xFFFFFFFF);
566 pssSegments
[j
].RawLength
= (ULONG
)(nFileSize
& 0xFFFFFFFF);
569 nFileOffset
= ElfFmtpAlignDown(nFileOffset
, nAlignment
);
571 #if __ELF_WORD_SIZE >= 64
572 ASSERT(sizeof(nFileOffset
) == sizeof(LONG64
));
574 if(((LONG64
)nFileOffset
) < 0)
575 DIE(("File offset of loadable segment is too large\n"));
578 pssSegments
[j
].FileOffset
= (LONG64
)nFileOffset
;
580 /* Virtual address */
581 nVirtualAddr
= ElfFmtpAlignDown(nVirtualAddr
, nAlignment
);
585 /* First segment: its address is the base address of the image */
586 nImageBase
= nVirtualAddr
;
587 pssSegments
[j
].VirtualAddress
= 0;
589 /* Several places make this assumption */
590 if(pssSegments
[j
].FileOffset
!= 0)
591 DIE(("First loadable segment doesn't contain the ELF header\n"));
595 Elf_Size nVirtualOffset
;
597 /* Other segment: store the offset from the base address */
598 if(nVirtualAddr
<= nImageBase
)
599 DIE(("Loadable segments are not sorted\n"));
601 nVirtualOffset
= nVirtualAddr
- nImageBase
;
603 if(nVirtualOffset
> MAXULONG
)
604 DIE(("Virtual image larger than 4GB\n"));
606 pssSegments
[j
].VirtualAddress
= (ULONG
)(nVirtualOffset
& 0xFFFFFFFF);
608 if(pssSegments
[j
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
609 DIE(("Loadable segments are not sorted and contiguous\n"));
612 /* Memory protection */
613 pssSegments
[j
].Protection
= ProgramHeaderFlagsToProtect
615 ElfFmtpSafeReadULong(&pphPHdrs
[i
].p_flags
, nData
) & (PF_R
| PF_W
| PF_X
)
618 /* Characteristics */
620 TODO: need to add support for the shared, non-pageable, non-cacheable and
621 discardable attributes. This involves extensions to the ELF format, so it's
622 nothing to be taken lightly
624 if(pssSegments
[j
].Protection
& PAGE_IS_EXECUTABLE
)
626 ImageSectionObject
->Executable
= TRUE
;
627 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_CODE
;
629 else if(pssSegments
[j
].RawLength
== 0)
630 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
632 pssSegments
[j
].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
635 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
636 now, if a bit wasteful of memory
638 pssSegments
[j
].Characteristics
|= IMAGE_SCN_MEM_NOT_PAGED
;
641 pssSegments
[j
].WriteCopy
= TRUE
;
643 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[j
].VirtualAddress
, pssSegments
[j
].Length
))
644 DIE(("Virtual image larger than 4GB\n"));
653 DIE(("No loadable segments\n"));
655 ImageSectionObject
->NrSegments
= j
;
658 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
|
659 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
662 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
664 nEntryPoint
= ElfFmtpReadAddr(pehHeader
->e_entry
, nData
);
666 if(nEntryPoint
< nImageBase
|| nEntryPoint
- nImageBase
> nPrevVirtualEndOfSegment
)
667 DIE(("Entry point not within the virtual image\n"));
669 ASSERT(nEntryPoint
>= nImageBase
);
670 ASSERT((nEntryPoint
- nImageBase
) <= MAXULONG
);
671 ImageSectionObject
->EntryPoint
= nEntryPoint
- nImageBase
;
673 /* TODO: support Wine executables and read these values from nt_headers */
674 ImageSectionObject
->ImageCharacteristics
|=
675 IMAGE_FILE_EXECUTABLE_IMAGE
|
676 IMAGE_FILE_LINE_NUMS_STRIPPED
|
677 IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
678 (nImageBase
> MAXULONG
? IMAGE_FILE_LARGE_ADDRESS_AWARE
: 0) |
679 IMAGE_FILE_DEBUG_STRIPPED
;
681 if(nData
== ELFDATA2LSB
)
682 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_LO
;
683 else if(nData
== ELFDATA2MSB
)
684 ImageSectionObject
->ImageCharacteristics
|= IMAGE_FILE_BYTES_REVERSED_HI
;
686 /* Base address outside the possible address space */
687 if(nImageBase
> MAXULONG_PTR
)
688 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_NONE
;
689 /* Position-independent image, base address doesn't matter */
690 else if(nImageBase
== 0)
691 ImageSectionObject
->ImageBase
= EXEFMT_LOAD_BASE_ANY
;
692 /* Use the specified base address */
694 ImageSectionObject
->ImageBase
= (ULONG_PTR
)nImageBase
;
697 ImageSectionObject
->Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
698 ImageSectionObject
->MinorSubsystemVersion
= 0;
699 ImageSectionObject
->MajorSubsystemVersion
= 4;
701 /* Success, at last */
702 nStatus
= STATUS_SUCCESS
;