4 Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2013-2022, ARM Ltd. All rights reserved.<BR>
6 Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "WinNtInclude.h"
25 #include <Common/UefiBaseTypes.h>
26 #include <IndustryStandard/PeImage.h>
28 #include "PeCoffLib.h"
29 #include "EfiUtilityMsgs.h"
32 #include "ElfConvert.h"
33 #include "Elf64Convert.h"
44 SECTION_FILTER_TYPES FilterType
78 // Rename ELF32 structures to common names to help when porting to ELF64.
80 typedef Elf64_Shdr Elf_Shdr
;
81 typedef Elf64_Ehdr Elf_Ehdr
;
82 typedef Elf64_Rel Elf_Rel
;
83 typedef Elf64_Rela Elf_Rela
;
84 typedef Elf64_Sym Elf_Sym
;
85 typedef Elf64_Phdr Elf_Phdr
;
86 typedef Elf64_Dyn Elf_Dyn
;
87 #define ELFCLASS ELFCLASS64
88 #define ELF_R_TYPE(r) ELF64_R_TYPE(r)
89 #define ELF_R_SYM(r) ELF64_R_SYM(r)
92 // Well known ELF structures.
94 STATIC Elf_Ehdr
*mEhdr
;
95 STATIC Elf_Shdr
*mShdrBase
;
96 STATIC Elf_Phdr
*mPhdrBase
;
101 STATIC Elf_Shdr
*mGOTShdr
= NULL
;
102 STATIC UINT32 mGOTShindex
= 0;
103 STATIC UINT32
*mGOTCoffEntries
= NULL
;
104 STATIC UINT32 mGOTMaxCoffEntries
= 0;
105 STATIC UINT32 mGOTNumCoffEntries
= 0;
110 STATIC UINT32 mCoffAlignment
= 0x20;
113 // PE section alignment.
115 STATIC UINT16 mCoffNbrSections
= 4;
118 // ELF sections to offset in Coff file.
120 STATIC UINT32
*mCoffSectionsOffset
= NULL
;
123 // Offsets in COFF file
125 STATIC UINT32 mNtHdrOffset
;
126 STATIC UINT32 mTextOffset
;
127 STATIC UINT32 mDataOffset
;
128 STATIC UINT32 mHiiRsrcOffset
;
129 STATIC UINT32 mRelocOffset
;
130 STATIC UINT32 mDebugOffset
;
131 STATIC UINT32 mExportOffset
;
133 // Used for RISC-V relocations.
135 STATIC UINT8
*mRiscVPass1Targ
= NULL
;
136 STATIC Elf_Shdr
*mRiscVPass1Sym
= NULL
;
137 STATIC Elf64_Half mRiscVPass1SymSecIndex
= 0;
138 STATIC INT32 mRiscVPass1Offset
;
139 STATIC INT32 mRiscVPass1GotFixup
;
142 // Used for Export section.
144 STATIC UINT32 mExportSize
;
145 STATIC UINT32 mExportRVA
[PRM_MODULE_EXPORT_SYMBOL_NUM
];
146 STATIC UINT32 mExportSymNum
;
147 STATIC CHAR8 mExportSymName
[PRM_MODULE_EXPORT_SYMBOL_NUM
][PRM_HANDLER_NAME_MAXIMUM_LENGTH
];
150 // Initialization Function
155 ELF_FUNCTION_TABLE
*ElfFunctions
159 // Initialize data pointer and structures.
161 VerboseMsg ("Set EHDR");
162 mEhdr
= (Elf_Ehdr
*) FileBuffer
;
165 // Check the ELF64 specific header information.
167 VerboseMsg ("Check ELF64 Header Information");
168 if (mEhdr
->e_ident
[EI_CLASS
] != ELFCLASS64
) {
169 Error (NULL
, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");
172 if (mEhdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
) {
173 Error (NULL
, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");
176 if ((mEhdr
->e_type
!= ET_EXEC
) && (mEhdr
->e_type
!= ET_DYN
)) {
177 Error (NULL
, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");
180 if (!((mEhdr
->e_machine
== EM_X86_64
) || (mEhdr
->e_machine
== EM_AARCH64
) || (mEhdr
->e_machine
== EM_RISCV64
))) {
181 Warning (NULL
, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine.");
183 if (mEhdr
->e_version
!= EV_CURRENT
) {
184 Error (NULL
, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr
->e_version
, EV_CURRENT
);
189 if ((mEhdr
->e_machine
!= EM_X86_64
) && (mEhdr
->e_machine
!= EM_AARCH64
)) {
190 Error (NULL
, 0, 3000, "Unsupported", "--prm option currently only supports X64 and AArch64 archs.");
196 // Update section header pointers
198 VerboseMsg ("Update Header Pointers");
199 mShdrBase
= (Elf_Shdr
*)((UINT8
*)mEhdr
+ mEhdr
->e_shoff
);
200 mPhdrBase
= (Elf_Phdr
*)((UINT8
*)mEhdr
+ mEhdr
->e_phoff
);
203 // Create COFF Section offset buffer and zero.
205 VerboseMsg ("Create COFF Section Offset Buffer");
206 mCoffSectionsOffset
= (UINT32
*)malloc(mEhdr
->e_shnum
* sizeof (UINT32
));
207 if (mCoffSectionsOffset
== NULL
) {
208 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
211 memset(mCoffSectionsOffset
, 0, mEhdr
->e_shnum
* sizeof(UINT32
));
214 // Fill in function pointers.
216 VerboseMsg ("Fill in Function Pointers");
217 ElfFunctions
->ScanSections
= ScanSections64
;
218 ElfFunctions
->WriteSections
= WriteSections64
;
219 ElfFunctions
->WriteRelocations
= WriteRelocations64
;
220 ElfFunctions
->WriteDebug
= WriteDebug64
;
221 ElfFunctions
->SetImageSize
= SetImageSize64
;
222 ElfFunctions
->CleanUp
= CleanUp64
;
226 ElfFunctions
->WriteExport
= WriteExport64
;
234 // Header by Index functions
242 if (Num
>= mEhdr
->e_shnum
) {
243 Error (NULL
, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num
);
247 return (Elf_Shdr
*)((UINT8
*)mShdrBase
+ Num
* mEhdr
->e_shentsize
);
256 return (Offset
+ mCoffAlignment
- 1) & ~(mCoffAlignment
- 1);
265 return (Offset
+ 3) & ~3;
277 return (BOOLEAN
) (((Shdr
->sh_flags
& (SHF_EXECINSTR
| SHF_ALLOC
)) == (SHF_EXECINSTR
| SHF_ALLOC
)) ||
278 ((Shdr
->sh_flags
& (SHF_WRITE
| SHF_ALLOC
)) == SHF_ALLOC
));
287 Elf_Shdr
*Namedr
= GetShdrByIndex(mEhdr
->e_shstrndx
);
289 return (BOOLEAN
) (strcmp((CHAR8
*)mEhdr
+ Namedr
->sh_offset
+ Shdr
->sh_name
, ELF_HII_SECTION_NAME
) == 0);
298 Elf_Shdr
*Namehdr
= GetShdrByIndex(mEhdr
->e_shstrndx
);
300 return (BOOLEAN
) (strcmp((CHAR8
*)mEhdr
+ Namehdr
->sh_offset
+ Shdr
->sh_name
, ELF_SYMBOL_SECTION_NAME
) == 0);
309 if (IsHiiRsrcShdr(Shdr
)) {
312 return (BOOLEAN
) (Shdr
->sh_flags
& (SHF_EXECINSTR
| SHF_WRITE
| SHF_ALLOC
)) == (SHF_ALLOC
| SHF_WRITE
);
321 Elf_Shdr
*Namedr
= GetShdrByIndex(mEhdr
->e_shstrndx
);
323 return (BOOLEAN
) (strcmp((CHAR8
*)mEhdr
+ Namedr
->sh_offset
+ Shdr
->sh_name
, ELF_STRTAB_SECTION_NAME
) == 0);
333 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
334 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
335 if (IsStrtabShdr(shdr
)) {
348 Elf_Shdr
*StrtabShdr
;
349 UINT8
*StrtabContents
;
353 if (Sym
->st_name
== 0) {
357 StrtabShdr
= FindStrtabShdr();
358 if (StrtabShdr
== NULL
) {
362 assert(Sym
->st_name
< StrtabShdr
->sh_size
);
364 StrtabContents
= (UINT8
*)mEhdr
+ StrtabShdr
->sh_offset
;
367 for (i
= Sym
->st_name
; (i
< StrtabShdr
->sh_size
) && !foundEnd
; i
++) {
368 foundEnd
= (BOOLEAN
)(StrtabContents
[i
] == 0);
372 return StrtabContents
+ Sym
->st_name
;
376 // Get Prm Handler number and name
384 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER
*PrmExport
;
385 PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT
*PrmHandler
;
388 PrmExport
= (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER
*)((UINT8
*)mEhdr
+ Offset
);
389 PrmHandler
= (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT
*)(PrmExport
+ 1);
391 for (HandlerNum
= 0; HandlerNum
< PrmExport
->NumberPrmHandlers
; HandlerNum
++) {
392 strcpy(mExportSymName
[mExportSymNum
], PrmHandler
->PrmHandlerName
);
397 // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)
399 if (mExportSymNum
>= (PRM_MODULE_EXPORT_SYMBOL_NUM
- 1)) {
400 Error (NULL
, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum
);
407 // Find the ELF section hosting the GOT from an ELF Rva
408 // of a single GOT entry. Normally, GOT is placed in
409 // ELF .text section, so assume once we find in which
410 // section the GOT is, all GOT entries are there, and
415 FindElfGOTSectionFromGOTEntryElfRva (
416 Elf64_Addr GOTEntryElfRva
420 if (mGOTShdr
!= NULL
) {
421 if (GOTEntryElfRva
>= mGOTShdr
->sh_addr
&&
422 GOTEntryElfRva
< mGOTShdr
->sh_addr
+ mGOTShdr
->sh_size
) {
425 Error (NULL
, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");
428 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
429 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
430 if (GOTEntryElfRva
>= shdr
->sh_addr
&&
431 GOTEntryElfRva
< shdr
->sh_addr
+ shdr
->sh_size
) {
437 Error (NULL
, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva
);
442 // Stores locations of GOT entries in COFF image.
443 // Returns TRUE if GOT entry is new.
444 // Simple implementation as number of GOT
445 // entries is expected to be low.
450 AccumulateCoffGOTEntries (
455 if (mGOTCoffEntries
!= NULL
) {
456 for (i
= 0; i
< mGOTNumCoffEntries
; i
++) {
457 if (mGOTCoffEntries
[i
] == GOTCoffEntry
) {
462 if (mGOTCoffEntries
== NULL
) {
463 mGOTCoffEntries
= (UINT32
*)malloc(5 * sizeof *mGOTCoffEntries
);
464 if (mGOTCoffEntries
== NULL
) {
465 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
467 assert (mGOTCoffEntries
!= NULL
);
468 mGOTMaxCoffEntries
= 5;
469 mGOTNumCoffEntries
= 0;
470 } else if (mGOTNumCoffEntries
== mGOTMaxCoffEntries
) {
471 mGOTCoffEntries
= (UINT32
*)realloc(mGOTCoffEntries
, 2 * mGOTMaxCoffEntries
* sizeof *mGOTCoffEntries
);
472 if (mGOTCoffEntries
== NULL
) {
473 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
475 assert (mGOTCoffEntries
!= NULL
);
476 mGOTMaxCoffEntries
+= mGOTMaxCoffEntries
;
478 mGOTCoffEntries
[mGOTNumCoffEntries
++] = GOTCoffEntry
;
483 // 32-bit Unsigned integer comparator for qsort.
492 if (*(const UINT32
*)lhs
< *(const UINT32
*)rhs
) {
495 return *(const UINT32
*)lhs
> *(const UINT32
*)rhs
;
499 // Emit accumulated Coff GOT entry relocations into
500 // Coff image. This function performs its job
501 // once and then releases the entry list, so
502 // it can safely be called multiple times.
511 if (mGOTCoffEntries
== NULL
) {
515 // Emit Coff relocations with Rvas ordered.
520 sizeof *mGOTCoffEntries
,
522 for (i
= 0; i
< mGOTNumCoffEntries
; i
++) {
523 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries
[i
]);
526 EFI_IMAGE_REL_BASED_DIR64
);
528 free(mGOTCoffEntries
);
529 mGOTCoffEntries
= NULL
;
530 mGOTMaxCoffEntries
= 0;
531 mGOTNumCoffEntries
= 0;
534 // RISC-V 64 specific Elf WriteSection function.
538 WriteSectionRiscV64 (
547 Elf64_Addr GOTEntryRva
;
549 switch (ELF_R_TYPE(Rel
->r_info
)) {
554 *(UINT64
*)Targ
= Sym
->st_value
+ Rel
->r_addend
;
558 *(UINT64
*)Targ
= Sym
->st_value
+ Rel
->r_addend
;
562 mRiscVPass1Targ
= Targ
;
563 mRiscVPass1Sym
= SymShdr
;
564 mRiscVPass1SymSecIndex
= Sym
->st_shndx
;
568 if (mRiscVPass1Sym
== SymShdr
&& mRiscVPass1Targ
!= NULL
&& mRiscVPass1SymSecIndex
== Sym
->st_shndx
&& mRiscVPass1SymSecIndex
!= 0) {
569 Value
= (UINT32
)(RV_X(*(UINT32
*)mRiscVPass1Targ
, 12, 20) << 12);
570 Value2
= (UINT32
)(RV_X(*(UINT32
*)Targ
, 20, 12));
571 if (Value2
& (RISCV_IMM_REACH
/2)) {
572 Value2
|= ~(RISCV_IMM_REACH
-1);
575 Value
= Value
- (UINT32
)SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
];
576 Value2
= RISCV_CONST_HIGH_PART (Value
);
577 *(UINT32
*)mRiscVPass1Targ
= (RV_X (Value2
, 12, 20) << 12) | \
578 (RV_X (*(UINT32
*)mRiscVPass1Targ
, 0, 12));
579 *(UINT32
*)Targ
= (RV_X (Value
, 0, 12) << 20) | \
580 (RV_X (*(UINT32
*)Targ
, 0, 20));
582 mRiscVPass1Sym
= NULL
;
583 mRiscVPass1Targ
= NULL
;
584 mRiscVPass1SymSecIndex
= 0;
588 if (mRiscVPass1Sym
== SymShdr
&& mRiscVPass1Targ
!= NULL
&& mRiscVPass1SymSecIndex
== Sym
->st_shndx
&& mRiscVPass1SymSecIndex
!= 0) {
589 Value
= (UINT32
)(RV_X(*(UINT32
*)mRiscVPass1Targ
, 12, 20) << 12);
590 Value2
= (UINT32
)(RV_X(*(UINT32
*)Targ
, 7, 5) | (RV_X(*(UINT32
*)Targ
, 25, 7) << 5));
591 if (Value2
& (RISCV_IMM_REACH
/2)) {
592 Value2
|= ~(RISCV_IMM_REACH
-1);
595 Value
= Value
- (UINT32
)SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
];
596 Value2
= RISCV_CONST_HIGH_PART (Value
);
597 *(UINT32
*)mRiscVPass1Targ
= (RV_X (Value2
, 12, 20) << 12) | \
598 (RV_X (*(UINT32
*)mRiscVPass1Targ
, 0, 12));
599 Value2
= *(UINT32
*)Targ
& 0x01fff07f;
600 Value
&= RISCV_IMM_REACH
- 1;
601 *(UINT32
*)Targ
= Value2
| (UINT32
)(((RV_X(Value
, 0, 5) << 7) | (RV_X(Value
, 5, 7) << 25)));
603 mRiscVPass1Sym
= NULL
;
604 mRiscVPass1Targ
= NULL
;
605 mRiscVPass1SymSecIndex
= 0;
608 case R_RISCV_GOT_HI20
:
609 GOTEntryRva
= (Sym
->st_value
- Rel
->r_offset
);
610 mRiscVPass1Offset
= RV_X(GOTEntryRva
, 0, 12);
611 Value
= (UINT32
)RV_X(GOTEntryRva
, 12, 20);
612 *(UINT32
*)Targ
= (Value
<< 12) | (RV_X(*(UINT32
*)Targ
, 0, 12));
614 mRiscVPass1Targ
= Targ
;
615 mRiscVPass1Sym
= SymShdr
;
616 mRiscVPass1SymSecIndex
= Sym
->st_shndx
;
617 mRiscVPass1GotFixup
= 1;
620 case R_RISCV_PCREL_HI20
:
621 mRiscVPass1Targ
= Targ
;
622 mRiscVPass1Sym
= SymShdr
;
623 mRiscVPass1SymSecIndex
= Sym
->st_shndx
;
625 Value
= (UINT32
)(RV_X(*(UINT32
*)mRiscVPass1Targ
, 12, 20));
628 case R_RISCV_PCREL_LO12_S
:
629 if (mRiscVPass1Targ
!= NULL
&& mRiscVPass1Sym
!= NULL
&& mRiscVPass1SymSecIndex
!= 0) {
631 Value2
= (UINT32
)(RV_X(*(UINT32
*)mRiscVPass1Targ
, 12, 20));
633 Value
= ((UINT32
)(RV_X(*(UINT32
*)Targ
, 25, 7)) << 5);
634 Value
= (Value
| (UINT32
)(RV_X(*(UINT32
*)Targ
, 7, 5)));
636 if(Value
& (RISCV_IMM_REACH
/2)) {
637 Value
|= ~(RISCV_IMM_REACH
-1);
639 Value
= Value
- (UINT32
)mRiscVPass1Sym
->sh_addr
+ mCoffSectionsOffset
[mRiscVPass1SymSecIndex
];
641 if(-2048 > (INT32
)Value
) {
642 i
= (((INT32
)Value
* -1) / 4096);
645 if(-2048 > (INT32
)Value
) {
650 else if( 2047 < (INT32
)Value
) {
654 if(2047 < (INT32
)Value
) {
660 // Update the IMM of SD instruction
662 // |31 25|24 20|19 15|14 12 |11 7|6 0|
663 // |-------------------------------------------|-------|
664 // |imm[11:5] | rs2 | rs1 | funct3 |imm[4:0] | opcode|
665 // ---------------------------------------------------
667 // First Zero out current IMM
668 *(UINT32
*)Targ
&= ~0xfe000f80;
670 // Update with new IMM
671 *(UINT32
*)Targ
|= (RV_X(Value
, 5, 7) << 25);
672 *(UINT32
*)Targ
|= (RV_X(Value
, 0, 5) << 7);
674 // Update previous instruction
675 *(UINT32
*)mRiscVPass1Targ
= (RV_X(Value2
, 0, 20)<<12) | (RV_X(*(UINT32
*)mRiscVPass1Targ
, 0, 12));
677 mRiscVPass1Sym
= NULL
;
678 mRiscVPass1Targ
= NULL
;
679 mRiscVPass1SymSecIndex
= 0;
682 case R_RISCV_PCREL_LO12_I
:
683 if (mRiscVPass1Targ
!= NULL
&& mRiscVPass1Sym
!= NULL
&& mRiscVPass1SymSecIndex
!= 0) {
685 Value2
= (UINT32
)(RV_X(*(UINT32
*)mRiscVPass1Targ
, 12, 20));
687 if(mRiscVPass1GotFixup
) {
688 Value
= (UINT32
)(mRiscVPass1Offset
);
690 Value
= (UINT32
)(RV_X(*(UINT32
*)Targ
, 20, 12));
691 if(Value
& (RISCV_IMM_REACH
/2)) {
692 Value
|= ~(RISCV_IMM_REACH
-1);
695 Value
= Value
- (UINT32
)mRiscVPass1Sym
->sh_addr
+ mCoffSectionsOffset
[mRiscVPass1SymSecIndex
];
697 if(-2048 > (INT32
)Value
) {
698 i
= (((INT32
)Value
* -1) / 4096);
701 if(-2048 > (INT32
)Value
) {
706 else if( 2047 < (INT32
)Value
) {
710 if(2047 < (INT32
)Value
) {
716 if(mRiscVPass1GotFixup
) {
717 *(UINT32
*)Targ
= (RV_X((UINT32
)Value
, 0, 12) << 20)
718 | (RV_X(*(UINT32
*)Targ
, 0, 20));
719 // Convert LD instruction to ADDI
721 // |31 20|19 15|14 12|11 7|6 0|
722 // |-----------------------------------------|
723 // |imm[11:0] | rs1 | 011 | rd | 0000011 | LD
724 // -----------------------------------------
726 // |-----------------------------------------|
727 // |imm[11:0] | rs1 | 000 | rd | 0010011 | ADDI
728 // -----------------------------------------
730 // To convert, let's first reset bits 12-14 and 0-6 using ~0x707f
731 // Then modify the opcode to ADDI (0010011)
732 // All other fields will remain same.
734 *(UINT32
*)Targ
= ((*(UINT32
*)Targ
& ~0x707f) | 0x13);
736 *(UINT32
*)Targ
= (RV_X(Value
, 0, 12) << 20) | (RV_X(*(UINT32
*)Targ
, 0, 20));
738 *(UINT32
*)mRiscVPass1Targ
= (RV_X(Value2
, 0, 20)<<12) | (RV_X(*(UINT32
*)mRiscVPass1Targ
, 0, 12));
740 mRiscVPass1Sym
= NULL
;
741 mRiscVPass1Targ
= NULL
;
742 mRiscVPass1SymSecIndex
= 0;
743 mRiscVPass1Offset
= 0;
744 mRiscVPass1GotFixup
= 0;
753 case R_RISCV_GPREL_I
:
754 case R_RISCV_GPREL_S
:
756 case R_RISCV_CALL_PLT
:
757 case R_RISCV_RVC_BRANCH
:
758 case R_RISCV_RVC_JUMP
:
768 Error (NULL
, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
773 // Elf functions interface implementation
783 EFI_IMAGE_DOS_HEADER
*DosHdr
;
784 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
787 BOOLEAN FoundSection
;
794 // Coff file start with a DOS header.
796 mCoffOffset
= sizeof(EFI_IMAGE_DOS_HEADER
) + 0x40;
797 mNtHdrOffset
= mCoffOffset
;
798 switch (mEhdr
->e_machine
) {
802 mCoffOffset
+= sizeof (EFI_IMAGE_NT_HEADERS64
);
805 VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName
, mEhdr
->e_machine
);
806 mCoffOffset
+= sizeof (EFI_IMAGE_NT_HEADERS64
);
810 mTableOffset
= mCoffOffset
;
811 mCoffOffset
+= mCoffNbrSections
* sizeof(EFI_IMAGE_SECTION_HEADER
);
814 // Set mCoffAlignment to the maximum alignment of the input sections
817 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
818 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
819 if (shdr
->sh_addralign
<= mCoffAlignment
) {
822 if (IsTextShdr(shdr
) || IsDataShdr(shdr
) || IsHiiRsrcShdr(shdr
)) {
823 mCoffAlignment
= (UINT32
)shdr
->sh_addralign
;
828 // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT
830 if (mCoffAlignment
> MAX_COFF_ALIGNMENT
) {
831 Error (NULL
, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT.");
837 // Move the PE/COFF header right before the first section. This will help us
838 // save space when converting to TE.
840 if (mCoffAlignment
> mCoffOffset
) {
841 mNtHdrOffset
+= mCoffAlignment
- mCoffOffset
;
842 mTableOffset
+= mCoffAlignment
- mCoffOffset
;
843 mCoffOffset
= mCoffAlignment
;
847 // First text sections.
849 mCoffOffset
= CoffAlign(mCoffOffset
);
850 mTextOffset
= mCoffOffset
;
851 FoundSection
= FALSE
;
853 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
854 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
855 if (IsTextShdr(shdr
)) {
856 if ((shdr
->sh_addralign
!= 0) && (shdr
->sh_addralign
!= 1)) {
857 // the alignment field is valid
858 if ((shdr
->sh_addr
& (shdr
->sh_addralign
- 1)) == 0) {
859 // if the section address is aligned we must align PE/COFF
860 mCoffOffset
= (UINT32
) ((mCoffOffset
+ shdr
->sh_addralign
- 1) & ~(shdr
->sh_addralign
- 1));
862 Error (NULL
, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
866 /* Relocate entry. */
867 if ((mEhdr
->e_entry
>= shdr
->sh_addr
) &&
868 (mEhdr
->e_entry
< shdr
->sh_addr
+ shdr
->sh_size
)) {
869 CoffEntry
= (UINT32
) (mCoffOffset
+ mEhdr
->e_entry
- shdr
->sh_addr
);
873 // Set mTextOffset with the offset of the first '.text' section
876 mTextOffset
= mCoffOffset
;
880 mCoffSectionsOffset
[i
] = mCoffOffset
;
881 mCoffOffset
+= (UINT32
) shdr
->sh_size
;
886 if (!FoundSection
&& mOutImageType
!= FW_ACPI_IMAGE
) {
887 Error (NULL
, 0, 3000, "Invalid", "Did not find any '.text' section.");
891 mDebugOffset
= DebugRvaAlign(mCoffOffset
);
892 mCoffOffset
= CoffAlign(mCoffOffset
);
894 if (SectionCount
> 1 && mOutImageType
== FW_EFI_IMAGE
) {
895 Warning (NULL
, 0, 0, NULL
, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName
);
899 // Then data sections.
901 mDataOffset
= mCoffOffset
;
902 FoundSection
= FALSE
;
904 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
905 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
906 if (IsDataShdr(shdr
)) {
907 if ((shdr
->sh_addralign
!= 0) && (shdr
->sh_addralign
!= 1)) {
908 // the alignment field is valid
909 if ((shdr
->sh_addr
& (shdr
->sh_addralign
- 1)) == 0) {
910 // if the section address is aligned we must align PE/COFF
911 mCoffOffset
= (UINT32
) ((mCoffOffset
+ shdr
->sh_addralign
- 1) & ~(shdr
->sh_addralign
- 1));
913 Error (NULL
, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
918 // Set mDataOffset with the offset of the first '.data' section
921 mDataOffset
= mCoffOffset
;
924 mCoffSectionsOffset
[i
] = mCoffOffset
;
925 mCoffOffset
+= (UINT32
) shdr
->sh_size
;
931 // Make room for .debug data in .data (or .text if .data is empty) instead of
932 // putting it in a section of its own. This is explicitly allowed by the
933 // PE/COFF spec, and prevents bloat in the binary when using large values for
934 // section alignment.
936 if (SectionCount
> 0) {
937 mDebugOffset
= DebugRvaAlign(mCoffOffset
);
939 mCoffOffset
= mDebugOffset
+ sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
) +
940 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
) +
941 strlen(mInImageName
) + 1;
943 mCoffOffset
= CoffAlign(mCoffOffset
);
944 if (SectionCount
== 0) {
945 mDataOffset
= mCoffOffset
;
948 if (SectionCount
> 1 && mOutImageType
== FW_EFI_IMAGE
) {
949 Warning (NULL
, 0, 0, NULL
, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName
);
953 // The Symbol sections.
959 const UINT8
*SymName
;
961 mExportOffset
= mCoffOffset
;
962 mExportSize
= sizeof(EFI_IMAGE_EXPORT_DIRECTORY
) + strlen(mInImageName
) + 1;
964 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
967 // Determine if this is a symbol section.
969 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
970 if (!IsSymbolShdr(shdr
)) {
974 UINT8
*Symtab
= (UINT8
*)mEhdr
+ shdr
->sh_offset
;
975 SymNum
= (shdr
->sh_size
) / (shdr
->sh_entsize
);
978 // First Get PrmModuleExportDescriptor
980 for (SymIndex
= 0; SymIndex
< SymNum
; SymIndex
++) {
981 Sym
= (Elf_Sym
*)(Symtab
+ SymIndex
* shdr
->sh_entsize
);
982 SymName
= GetSymName(Sym
);
983 if (SymName
== NULL
) {
987 if (strcmp((CHAR8
*)SymName
, PRM_MODULE_EXPORT_DESCRIPTOR_NAME
) == 0) {
989 // Find PrmHandler Number and Name
991 FindPrmHandler(Sym
->st_value
);
993 strcpy(mExportSymName
[mExportSymNum
], (CHAR8
*)SymName
);
994 mExportRVA
[mExportSymNum
] = (UINT32
)(Sym
->st_value
);
995 mExportSize
+= 2 * EFI_IMAGE_EXPORT_ADDR_SIZE
+ EFI_IMAGE_EXPORT_ORDINAL_SIZE
+ strlen((CHAR8
*)SymName
) + 1;
1002 // Second Get PrmHandler
1004 for (SymIndex
= 0; SymIndex
< SymNum
; SymIndex
++) {
1006 Sym
= (Elf_Sym
*)(Symtab
+ SymIndex
* shdr
->sh_entsize
);
1007 SymName
= GetSymName(Sym
);
1008 if (SymName
== NULL
) {
1012 for (ExpIndex
= 0; ExpIndex
< (mExportSymNum
-1); ExpIndex
++) {
1013 if (strcmp((CHAR8
*)SymName
, mExportSymName
[ExpIndex
]) != 0) {
1016 mExportRVA
[ExpIndex
] = (UINT32
)(Sym
->st_value
);
1017 mExportSize
+= 2 * EFI_IMAGE_EXPORT_ADDR_SIZE
+ EFI_IMAGE_EXPORT_ORDINAL_SIZE
+ strlen((CHAR8
*)SymName
) + 1;
1024 mCoffOffset
+= mExportSize
;
1025 mCoffOffset
= CoffAlign(mCoffOffset
);
1029 // The HII resource sections.
1031 mHiiRsrcOffset
= mCoffOffset
;
1032 for (i
= 0; i
< mEhdr
->e_shnum
; i
++) {
1033 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
1034 if (IsHiiRsrcShdr(shdr
)) {
1035 if ((shdr
->sh_addralign
!= 0) && (shdr
->sh_addralign
!= 1)) {
1036 // the alignment field is valid
1037 if ((shdr
->sh_addr
& (shdr
->sh_addralign
- 1)) == 0) {
1038 // if the section address is aligned we must align PE/COFF
1039 mCoffOffset
= (UINT32
) ((mCoffOffset
+ shdr
->sh_addralign
- 1) & ~(shdr
->sh_addralign
- 1));
1041 Error (NULL
, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
1044 if (shdr
->sh_size
!= 0) {
1045 mHiiRsrcOffset
= mCoffOffset
;
1046 mCoffSectionsOffset
[i
] = mCoffOffset
;
1047 mCoffOffset
+= (UINT32
) shdr
->sh_size
;
1048 mCoffOffset
= CoffAlign(mCoffOffset
);
1049 SetHiiResourceHeader ((UINT8
*) mEhdr
+ shdr
->sh_offset
, mHiiRsrcOffset
);
1055 mRelocOffset
= mCoffOffset
;
1058 // Allocate base Coff file. Will be expanded later for relocations.
1060 mCoffFile
= (UINT8
*)malloc(mCoffOffset
);
1061 if (mCoffFile
== NULL
) {
1062 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
1064 assert (mCoffFile
!= NULL
);
1065 memset(mCoffFile
, 0, mCoffOffset
);
1070 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)mCoffFile
;
1071 DosHdr
->e_magic
= EFI_IMAGE_DOS_SIGNATURE
;
1072 DosHdr
->e_lfanew
= mNtHdrOffset
;
1074 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)(mCoffFile
+ mNtHdrOffset
);
1076 NtHdr
->Pe32Plus
.Signature
= EFI_IMAGE_NT_SIGNATURE
;
1078 switch (mEhdr
->e_machine
) {
1080 NtHdr
->Pe32Plus
.FileHeader
.Machine
= EFI_IMAGE_MACHINE_X64
;
1081 NtHdr
->Pe32Plus
.OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1084 NtHdr
->Pe32Plus
.FileHeader
.Machine
= EFI_IMAGE_MACHINE_AARCH64
;
1085 NtHdr
->Pe32Plus
.OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1088 NtHdr
->Pe32Plus
.FileHeader
.Machine
= EFI_IMAGE_MACHINE_RISCV64
;
1089 NtHdr
->Pe32Plus
.OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1093 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN
)mEhdr
->e_machine
);
1094 NtHdr
->Pe32Plus
.FileHeader
.Machine
= EFI_IMAGE_MACHINE_X64
;
1095 NtHdr
->Pe32Plus
.OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1098 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
= mCoffNbrSections
;
1099 NtHdr
->Pe32Plus
.FileHeader
.TimeDateStamp
= (UINT32
) time(NULL
);
1100 mImageTimeStamp
= NtHdr
->Pe32Plus
.FileHeader
.TimeDateStamp
;
1101 NtHdr
->Pe32Plus
.FileHeader
.PointerToSymbolTable
= 0;
1102 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSymbols
= 0;
1103 NtHdr
->Pe32Plus
.FileHeader
.SizeOfOptionalHeader
= sizeof(NtHdr
->Pe32Plus
.OptionalHeader
);
1104 NtHdr
->Pe32Plus
.FileHeader
.Characteristics
= EFI_IMAGE_FILE_EXECUTABLE_IMAGE
1105 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
1106 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
1107 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE
;
1109 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfCode
= mDataOffset
- mTextOffset
;
1110 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfInitializedData
= mRelocOffset
- mDataOffset
;
1111 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfUninitializedData
= 0;
1112 NtHdr
->Pe32Plus
.OptionalHeader
.AddressOfEntryPoint
= CoffEntry
;
1114 NtHdr
->Pe32Plus
.OptionalHeader
.BaseOfCode
= mTextOffset
;
1116 NtHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= 0;
1117 NtHdr
->Pe32Plus
.OptionalHeader
.SectionAlignment
= mCoffAlignment
;
1118 NtHdr
->Pe32Plus
.OptionalHeader
.FileAlignment
= mCoffAlignment
;
1119 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfImage
= 0;
1121 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfHeaders
= mTextOffset
;
1122 NtHdr
->Pe32Plus
.OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
1127 if ((mDataOffset
- mTextOffset
) > 0) {
1128 CreateSectionHeader (".text", mTextOffset
, mDataOffset
- mTextOffset
,
1129 EFI_IMAGE_SCN_CNT_CODE
1130 | EFI_IMAGE_SCN_MEM_EXECUTE
1131 | EFI_IMAGE_SCN_MEM_READ
);
1133 // Don't make a section of size 0.
1134 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
--;
1138 // If found symbol, add edata section between data and rsrc section
1141 Offset
= mExportOffset
;
1143 Offset
= mHiiRsrcOffset
;
1146 if ((mHiiRsrcOffset
- mDataOffset
) > 0) {
1147 CreateSectionHeader (".data", mDataOffset
, Offset
- mDataOffset
,
1148 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1149 | EFI_IMAGE_SCN_MEM_WRITE
1150 | EFI_IMAGE_SCN_MEM_READ
);
1152 // Don't make a section of size 0.
1153 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
--;
1157 if ((mHiiRsrcOffset
- mExportOffset
) > 0) {
1158 CreateSectionHeader (".edata", mExportOffset
, mHiiRsrcOffset
- mExportOffset
,
1159 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1160 | EFI_IMAGE_SCN_MEM_READ
);
1161 NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
].Size
= mHiiRsrcOffset
- mExportOffset
;
1162 NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
].VirtualAddress
= mExportOffset
;
1165 // Don't make a section of size 0.
1166 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
--;
1170 if ((mRelocOffset
- mHiiRsrcOffset
) > 0) {
1171 CreateSectionHeader (".rsrc", mHiiRsrcOffset
, mRelocOffset
- mHiiRsrcOffset
,
1172 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1173 | EFI_IMAGE_SCN_MEM_READ
);
1175 NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
].Size
= mRelocOffset
- mHiiRsrcOffset
;
1176 NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
= mHiiRsrcOffset
;
1178 // Don't make a section of size 0.
1179 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
--;
1187 SECTION_FILTER_TYPES FilterType
1193 BOOLEAN (*Filter
)(Elf_Shdr
*);
1194 Elf64_Addr GOTEntryRva
;
1197 // Initialize filter pointer
1199 switch (FilterType
) {
1201 Filter
= IsTextShdr
;
1204 Filter
= IsHiiRsrcShdr
;
1207 Filter
= IsDataShdr
;
1214 // First: copy sections.
1216 for (Idx
= 0; Idx
< mEhdr
->e_shnum
; Idx
++) {
1217 Elf_Shdr
*Shdr
= GetShdrByIndex(Idx
);
1218 if ((*Filter
)(Shdr
)) {
1219 switch (Shdr
->sh_type
) {
1222 if (Shdr
->sh_offset
+ Shdr
->sh_size
> mFileBufferSize
) {
1225 memcpy(mCoffFile
+ mCoffSectionsOffset
[Idx
],
1226 (UINT8
*)mEhdr
+ Shdr
->sh_offset
,
1227 (size_t) Shdr
->sh_size
);
1231 memset(mCoffFile
+ mCoffSectionsOffset
[Idx
], 0, (size_t) Shdr
->sh_size
);
1236 // Ignore for unknown section type.
1238 VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName
, (unsigned)Shdr
->sh_type
);
1245 // Second: apply relocations.
1247 VerboseMsg ("Applying Relocations...");
1248 for (Idx
= 0; Idx
< mEhdr
->e_shnum
; Idx
++) {
1250 // Determine if this is a relocation section.
1252 Elf_Shdr
*RelShdr
= GetShdrByIndex(Idx
);
1253 if ((RelShdr
->sh_type
!= SHT_REL
) && (RelShdr
->sh_type
!= SHT_RELA
)) {
1258 // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA
1259 // section that applies to the entire binary, and which will have its section
1260 // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared).
1262 // In the absence of GOT based relocations,
1263 // this RELA section will contain redundant R_xxx_RELATIVE relocations, one
1264 // for every R_xxx_xx64 relocation appearing in the per-section RELA sections.
1265 // (i.e., .rela.text and .rela.data)
1267 if (RelShdr
->sh_info
== 0) {
1272 // Relocation section found. Now extract section information that the relocations
1273 // apply to in the ELF data and the new COFF data.
1275 SecShdr
= GetShdrByIndex(RelShdr
->sh_info
);
1276 SecOffset
= mCoffSectionsOffset
[RelShdr
->sh_info
];
1279 // Only process relocations for the current filter type.
1281 if (RelShdr
->sh_type
== SHT_RELA
&& (*Filter
)(SecShdr
)) {
1285 // Determine the symbol table referenced by the relocation data.
1287 Elf_Shdr
*SymtabShdr
= GetShdrByIndex(RelShdr
->sh_link
);
1288 UINT8
*Symtab
= (UINT8
*)mEhdr
+ SymtabShdr
->sh_offset
;
1291 // Process all relocation entries for this section.
1293 for (RelIdx
= 0; RelIdx
< RelShdr
->sh_size
; RelIdx
+= (UINT32
) RelShdr
->sh_entsize
) {
1296 // Set pointer to relocation entry
1298 Elf_Rela
*Rel
= (Elf_Rela
*)((UINT8
*)mEhdr
+ RelShdr
->sh_offset
+ RelIdx
);
1301 // Set pointer to symbol table entry associated with the relocation entry.
1303 Elf_Sym
*Sym
= (Elf_Sym
*)(Symtab
+ ELF_R_SYM(Rel
->r_info
) * SymtabShdr
->sh_entsize
);
1309 // Check section header index found in symbol table and get the section
1312 if (Sym
->st_shndx
== SHN_UNDEF
1313 || Sym
->st_shndx
>= mEhdr
->e_shnum
) {
1314 const UINT8
*SymName
= GetSymName(Sym
);
1315 if (SymName
== NULL
) {
1316 SymName
= (const UINT8
*)"<unknown>";
1320 // Skip error on EM_RISCV64 becasue no symble name is built
1321 // from RISC-V toolchain.
1323 if (mEhdr
->e_machine
!= EM_RISCV64
) {
1324 Error (NULL
, 0, 3000, "Invalid",
1325 "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "
1326 "For example, absolute and undefined symbols are not supported.",
1327 mInImageName
, SymName
, Sym
->st_value
);
1333 SymShdr
= GetShdrByIndex(Sym
->st_shndx
);
1336 // Convert the relocation data to a pointer into the coff file.
1339 // r_offset is the virtual address of the storage unit to be relocated.
1340 // sh_addr is the virtual address for the base of the section.
1342 // r_offset in a memory address.
1343 // Convert it to a pointer in the coff file.
1345 Targ
= mCoffFile
+ SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
);
1348 // Determine how to handle each relocation type based on the machine type.
1350 if (mEhdr
->e_machine
== EM_X86_64
) {
1351 switch (ELF_R_TYPE(Rel
->r_info
)) {
1356 // Absolute relocation.
1358 VerboseMsg ("R_X86_64_64");
1359 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",
1360 (UINT32
)(SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
)),
1362 *(UINT64
*)Targ
= *(UINT64
*)Targ
- SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
];
1363 VerboseMsg ("Relocation: 0x%016LX", *(UINT64
*)Targ
);
1366 VerboseMsg ("R_X86_64_32");
1367 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
1368 (UINT32
)(SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
)),
1370 *(UINT32
*)Targ
= (UINT32
)((UINT64
)(*(UINT32
*)Targ
) - SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
]);
1371 VerboseMsg ("Relocation: 0x%08X", *(UINT32
*)Targ
);
1374 VerboseMsg ("R_X86_64_32S");
1375 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
1376 (UINT32
)(SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
)),
1378 *(INT32
*)Targ
= (INT32
)((INT64
)(*(INT32
*)Targ
) - SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
]);
1379 VerboseMsg ("Relocation: 0x%08X", *(UINT32
*)Targ
);
1382 case R_X86_64_PLT32
:
1384 // Treat R_X86_64_PLT32 relocations as R_X86_64_PC32: this is
1385 // possible since we know all code symbol references resolve to
1386 // definitions in the same module (UEFI has no shared libraries),
1387 // and so there is never a reason to jump via a PLT entry,
1388 // allowing us to resolve the reference using the symbol directly.
1390 VerboseMsg ("Treating R_X86_64_PLT32 as R_X86_64_PC32 ...");
1394 // Relative relocation: Symbol - Ip + Addend
1396 VerboseMsg ("R_X86_64_PC32");
1397 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
1398 (UINT32
)(SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
)),
1400 *(UINT32
*)Targ
= (UINT32
) (*(UINT32
*)Targ
1401 + (mCoffSectionsOffset
[Sym
->st_shndx
] - SymShdr
->sh_addr
)
1402 - (SecOffset
- SecShdr
->sh_addr
));
1403 VerboseMsg ("Relocation: 0x%08X", *(UINT32
*)Targ
);
1405 case R_X86_64_GOTPCREL
:
1406 case R_X86_64_GOTPCRELX
:
1407 case R_X86_64_REX_GOTPCRELX
:
1408 VerboseMsg ("R_X86_64_GOTPCREL family");
1409 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
1410 (UINT32
)(SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
)),
1412 GOTEntryRva
= Rel
->r_offset
- Rel
->r_addend
+ *(INT32
*)Targ
;
1413 FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva
);
1414 *(UINT32
*)Targ
= (UINT32
) (*(UINT32
*)Targ
1415 + (mCoffSectionsOffset
[mGOTShindex
] - mGOTShdr
->sh_addr
)
1416 - (SecOffset
- SecShdr
->sh_addr
));
1417 VerboseMsg ("Relocation: 0x%08X", *(UINT32
*)Targ
);
1418 GOTEntryRva
+= (mCoffSectionsOffset
[mGOTShindex
] - mGOTShdr
->sh_addr
); // ELF Rva -> COFF Rva
1419 if (AccumulateCoffGOTEntries((UINT32
)GOTEntryRva
)) {
1421 // Relocate GOT entry if it's the first time we run into it
1423 Targ
= mCoffFile
+ GOTEntryRva
;
1425 // Limitation: The following three statements assume memory
1426 // at *Targ is valid because the section containing the GOT
1427 // has already been copied from the ELF image to the Coff image.
1428 // This pre-condition presently holds because the GOT is placed
1429 // in section .text, and the ELF text sections are all copied
1430 // prior to reaching this point.
1431 // If the pre-condition is violated in the future, this fixup
1432 // either needs to be deferred after the GOT section is copied
1433 // to the Coff image, or the fixup should be performed on the
1434 // source Elf image instead of the destination Coff image.
1436 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",
1437 (UINT32
)GOTEntryRva
,
1439 *(UINT64
*)Targ
= *(UINT64
*)Targ
- SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
];
1440 VerboseMsg ("Relocation: 0x%016LX", *(UINT64
*)Targ
);
1444 Error (NULL
, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
1446 } else if (mEhdr
->e_machine
== EM_AARCH64
) {
1448 switch (ELF_R_TYPE(Rel
->r_info
)) {
1451 case R_AARCH64_LD64_GOT_LO12_NC
:
1453 // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAGE below.
1455 *(UINT32
*)Targ
&= 0x3ff;
1456 *(UINT32
*)Targ
|= 0x91000000 | ((Sym
->st_value
& 0xfff) << 10);
1459 case R_AARCH64_ADR_GOT_PAGE
:
1461 // This relocation points to the GOT entry that contains the absolute
1462 // address of the symbol we are referring to. Since EDK2 only uses
1463 // fully linked binaries, we can avoid the indirection, and simply
1464 // refer to the symbol directly. This implies having to patch the
1465 // subsequent LDR instruction (covered by a R_AARCH64_LD64_GOT_LO12_NC
1466 // relocation) into an ADD instruction - this is handled above.
1468 Offset
= (Sym
->st_value
- (Rel
->r_offset
& ~0xfff)) >> 12;
1470 *(UINT32
*)Targ
&= 0x9000001f;
1471 *(UINT32
*)Targ
|= ((Offset
& 0x1ffffc) << (5 - 2)) | ((Offset
& 0x3) << 29);
1475 case R_AARCH64_ADR_PREL_PG_HI21
:
1477 // In order to handle Cortex-A53 erratum #843419, the LD linker may
1478 // convert ADRP instructions into ADR instructions, but without
1479 // updating the static relocation type, and so we may end up here
1480 // while the instruction in question is actually ADR. So let's
1481 // just disregard it: the section offset check we apply below to
1482 // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC
1483 // companion instruction as well, so it is safe to omit it here.
1485 if ((*(UINT32
*)Targ
& BIT31
) == 0) {
1490 // AArch64 PG_H21 relocations are typically paired with ABS_LO12
1491 // relocations, where a PC-relative reference with +/- 4 GB range is
1492 // split into a relative high part and an absolute low part. Since
1493 // the absolute low part represents the offset into a 4 KB page, we
1494 // either have to convert the ADRP into an ADR instruction, or we
1495 // need to use a section alignment of at least 4 KB, so that the
1496 // binary appears at a correct offset at runtime. In any case, we
1497 // have to make sure that the 4 KB relative offsets of both the
1498 // section containing the reference as well as the section to which
1499 // it refers have not been changed during PE/COFF conversion (i.e.,
1500 // in ScanSections64() above).
1502 if (mCoffAlignment
< 0x1000) {
1504 // Attempt to convert the ADRP into an ADR instruction.
1505 // This is only possible if the symbol is within +/- 1 MB.
1508 // Decode the ADRP instruction
1509 Offset
= (INT32
)((*(UINT32
*)Targ
& 0xffffe0) << 8);
1510 Offset
= (Offset
<< (6 - 5)) | ((*(UINT32
*)Targ
& 0x60000000) >> (29 - 12));
1513 // ADRP offset is relative to the previous page boundary,
1514 // whereas ADR offset is relative to the instruction itself.
1515 // So fix up the offset so it points to the page containing
1518 Offset
-= (UINTN
)(Targ
- mCoffFile
) & 0xfff;
1520 if (Offset
< -0x100000 || Offset
> 0xfffff) {
1521 Error (NULL
, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.",
1526 // Re-encode the offset as an ADR instruction
1527 *(UINT32
*)Targ
&= 0x1000001f;
1528 *(UINT32
*)Targ
|= ((Offset
& 0x1ffffc) << (5 - 2)) | ((Offset
& 0x3) << 29);
1532 case R_AARCH64_ADD_ABS_LO12_NC
:
1533 case R_AARCH64_LDST8_ABS_LO12_NC
:
1534 case R_AARCH64_LDST16_ABS_LO12_NC
:
1535 case R_AARCH64_LDST32_ABS_LO12_NC
:
1536 case R_AARCH64_LDST64_ABS_LO12_NC
:
1537 case R_AARCH64_LDST128_ABS_LO12_NC
:
1538 if (((SecShdr
->sh_addr
^ SecOffset
) & 0xfff) != 0 ||
1539 ((SymShdr
->sh_addr
^ mCoffSectionsOffset
[Sym
->st_shndx
]) & 0xfff) != 0) {
1540 Error (NULL
, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB.",
1546 case R_AARCH64_ADR_PREL_LO21
:
1547 case R_AARCH64_CONDBR19
:
1548 case R_AARCH64_LD_PREL_LO19
:
1549 case R_AARCH64_CALL26
:
1550 case R_AARCH64_JUMP26
:
1551 case R_AARCH64_PREL64
:
1552 case R_AARCH64_PREL32
:
1553 case R_AARCH64_PREL16
:
1555 // The GCC toolchains (i.e., binutils) may corrupt section relative
1556 // relocations when emitting relocation sections into fully linked
1557 // binaries. More specifically, they tend to fail to take into
1558 // account the fact that a '.rodata + XXX' relocation needs to have
1559 // its addend recalculated once .rodata is merged into the .text
1560 // section, and the relocation emitted into the .rela.text section.
1562 // We cannot really recover from this loss of information, so the
1563 // only workaround is to prevent having to recalculate any relative
1564 // relocations at all, by using a linker script that ensures that
1565 // the offset between the Place and the Symbol is the same in both
1566 // the ELF and the PE/COFF versions of the binary.
1568 if ((SymShdr
->sh_addr
- SecShdr
->sh_addr
) !=
1569 (mCoffSectionsOffset
[Sym
->st_shndx
] - SecOffset
)) {
1570 Error (NULL
, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",
1575 // Absolute relocations.
1576 case R_AARCH64_ABS64
:
1577 *(UINT64
*)Targ
= *(UINT64
*)Targ
- SymShdr
->sh_addr
+ mCoffSectionsOffset
[Sym
->st_shndx
];
1581 Error (NULL
, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
1583 } else if (mEhdr
->e_machine
== EM_RISCV64
) {
1585 // Write section for RISC-V 64 architecture.
1587 WriteSectionRiscV64 (Rel
, Targ
, SymShdr
, Sym
);
1589 Error (NULL
, 0, 3000, "Invalid", "Not a supported machine type");
1600 WriteRelocations64 (
1605 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
1606 EFI_IMAGE_DATA_DIRECTORY
*Dir
;
1607 UINT32 RiscVRelType
;
1609 for (Index
= 0; Index
< mEhdr
->e_shnum
; Index
++) {
1610 Elf_Shdr
*RelShdr
= GetShdrByIndex(Index
);
1611 if ((RelShdr
->sh_type
== SHT_REL
) || (RelShdr
->sh_type
== SHT_RELA
)) {
1612 Elf_Shdr
*SecShdr
= GetShdrByIndex (RelShdr
->sh_info
);
1613 if (IsTextShdr(SecShdr
) || IsDataShdr(SecShdr
)) {
1616 for (RelIdx
= 0; RelIdx
< RelShdr
->sh_size
; RelIdx
+= RelShdr
->sh_entsize
) {
1617 Elf_Rela
*Rel
= (Elf_Rela
*)((UINT8
*)mEhdr
+ RelShdr
->sh_offset
+ RelIdx
);
1619 if (mEhdr
->e_machine
== EM_X86_64
) {
1620 switch (ELF_R_TYPE(Rel
->r_info
)) {
1623 case R_X86_64_PLT32
:
1624 case R_X86_64_GOTPCREL
:
1625 case R_X86_64_GOTPCRELX
:
1626 case R_X86_64_REX_GOTPCRELX
:
1629 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",
1630 mCoffSectionsOffset
[RelShdr
->sh_info
] + (Rel
->r_offset
- SecShdr
->sh_addr
));
1632 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1633 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1634 EFI_IMAGE_REL_BASED_DIR64
);
1637 // R_X86_64_32 and R_X86_64_32S are ELF64 relocations emitted when using
1638 // the SYSV X64 ABI small non-position-independent code model.
1639 // R_X86_64_32 is used for unsigned 32-bit immediates with a 32-bit operand
1640 // size. The value is either not extended, or zero-extended to 64 bits.
1641 // R_X86_64_32S is used for either signed 32-bit non-rip-relative displacements
1642 // or signed 32-bit immediates with a 64-bit operand size. The value is
1643 // sign-extended to 64 bits.
1644 // EFI_IMAGE_REL_BASED_HIGHLOW is a PE relocation that uses 32-bit arithmetic
1645 // for rebasing an image.
1646 // EFI PE binaries declare themselves EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE and
1647 // may load above 2GB. If an EFI PE binary with a converted R_X86_64_32S
1648 // relocation is loaded above 2GB, the value will get sign-extended to the
1649 // negative part of the 64-bit address space. The negative part of the 64-bit
1650 // address space is unmapped, so accessing such an address page-faults.
1651 // In order to support R_X86_64_32S, it is necessary to unset
1652 // EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE, and the EFI PE loader must implement
1653 // this flag and abstain from loading such a PE binary above 2GB.
1654 // Since this feature is not supported, support for R_X86_64_32S (and hence
1655 // the small non-position-independent code model) is disabled.
1657 // case R_X86_64_32S:
1659 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",
1660 mCoffSectionsOffset
[RelShdr
->sh_info
] + (Rel
->r_offset
- SecShdr
->sh_addr
));
1662 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1663 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1664 EFI_IMAGE_REL_BASED_HIGHLOW
);
1667 Error (NULL
, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
1669 } else if (mEhdr
->e_machine
== EM_AARCH64
) {
1671 switch (ELF_R_TYPE(Rel
->r_info
)) {
1672 case R_AARCH64_ADR_PREL_LO21
:
1673 case R_AARCH64_CONDBR19
:
1674 case R_AARCH64_LD_PREL_LO19
:
1675 case R_AARCH64_CALL26
:
1676 case R_AARCH64_JUMP26
:
1677 case R_AARCH64_PREL64
:
1678 case R_AARCH64_PREL32
:
1679 case R_AARCH64_PREL16
:
1680 case R_AARCH64_ADR_PREL_PG_HI21
:
1681 case R_AARCH64_ADD_ABS_LO12_NC
:
1682 case R_AARCH64_LDST8_ABS_LO12_NC
:
1683 case R_AARCH64_LDST16_ABS_LO12_NC
:
1684 case R_AARCH64_LDST32_ABS_LO12_NC
:
1685 case R_AARCH64_LDST64_ABS_LO12_NC
:
1686 case R_AARCH64_LDST128_ABS_LO12_NC
:
1687 case R_AARCH64_ADR_GOT_PAGE
:
1688 case R_AARCH64_LD64_GOT_LO12_NC
:
1690 // No fixups are required for relative relocations, provided that
1691 // the relative offsets between sections have been preserved in
1692 // the ELF to PE/COFF conversion. We have already asserted that
1693 // this is the case in WriteSections64 ().
1697 case R_AARCH64_ABS64
:
1699 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1700 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1701 EFI_IMAGE_REL_BASED_DIR64
);
1704 case R_AARCH64_ABS32
:
1706 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1707 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1708 EFI_IMAGE_REL_BASED_HIGHLOW
);
1712 Error (NULL
, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
1714 } else if (mEhdr
->e_machine
== EM_RISCV64
) {
1715 RiscVRelType
= ELF_R_TYPE(Rel
->r_info
);
1716 switch (RiscVRelType
) {
1722 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1723 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1724 EFI_IMAGE_REL_BASED_HIGHLOW
);
1729 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1730 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1731 EFI_IMAGE_REL_BASED_DIR64
);
1736 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1737 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1738 EFI_IMAGE_REL_BASED_RISCV_HI20
);
1741 case R_RISCV_LO12_I
:
1743 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1744 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1745 EFI_IMAGE_REL_BASED_RISCV_LOW12I
);
1748 case R_RISCV_LO12_S
:
1750 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1751 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1752 EFI_IMAGE_REL_BASED_RISCV_LOW12S
);
1757 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1758 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1759 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1764 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1765 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1766 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1771 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1772 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1773 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1778 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1779 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1780 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1783 case R_RISCV_BRANCH
:
1785 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1786 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1787 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1792 (UINT32
) ((UINT64
) mCoffSectionsOffset
[RelShdr
->sh_info
]
1793 + (Rel
->r_offset
- SecShdr
->sh_addr
)),
1794 EFI_IMAGE_REL_BASED_ABSOLUTE
);
1797 case R_RISCV_GPREL_I
:
1798 case R_RISCV_GPREL_S
:
1800 case R_RISCV_CALL_PLT
:
1801 case R_RISCV_RVC_BRANCH
:
1802 case R_RISCV_RVC_JUMP
:
1809 case R_RISCV_PCREL_HI20
:
1810 case R_RISCV_GOT_HI20
:
1811 case R_RISCV_PCREL_LO12_I
:
1812 case R_RISCV_PCREL_LO12_S
:
1816 Error (NULL
, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName
, (unsigned) ELF_R_TYPE(Rel
->r_info
));
1819 Error (NULL
, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr
->e_machine
);
1822 if (mEhdr
->e_machine
== EM_X86_64
&& RelShdr
->sh_info
== mGOTShindex
) {
1824 // Tack relocations for GOT entries after other relocations for
1825 // the section the GOT is in, as it's usually found at the end
1826 // of the section. This is done in order to maintain Rva order
1827 // of Coff relocations.
1829 EmitGOTRelocations();
1835 if (mEhdr
->e_machine
== EM_X86_64
) {
1837 // This is a safety net just in case the GOT is in a section
1838 // with no other relocations and the first invocation of
1839 // EmitGOTRelocations() above was skipped. This invocation
1840 // does not maintain Rva order of Coff relocations.
1841 // At present, with a single text section, all references to
1842 // the GOT and the GOT itself reside in section .text, so
1843 // if there's a GOT at all, the first invocation above
1846 EmitGOTRelocations();
1849 // Pad by adding empty entries.
1851 while (mCoffOffset
& (mCoffAlignment
- 1)) {
1852 CoffAddFixupEntry(0);
1855 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)(mCoffFile
+ mNtHdrOffset
);
1856 Dir
= &NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1857 Dir
->Size
= mCoffOffset
- mRelocOffset
;
1858 if (Dir
->Size
== 0) {
1859 // If no relocations, null out the directory entry and don't add the .reloc section
1860 Dir
->VirtualAddress
= 0;
1861 NtHdr
->Pe32Plus
.FileHeader
.NumberOfSections
--;
1863 Dir
->VirtualAddress
= mRelocOffset
;
1864 CreateSectionHeader (".reloc", mRelocOffset
, mCoffOffset
- mRelocOffset
,
1865 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1866 | EFI_IMAGE_SCN_MEM_DISCARDABLE
1867 | EFI_IMAGE_SCN_MEM_READ
);
1878 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
1879 EFI_IMAGE_DATA_DIRECTORY
*DataDir
;
1880 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*Dir
;
1881 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
*Nb10
;
1883 Len
= strlen(mInImageName
) + 1;
1885 Dir
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(mCoffFile
+ mDebugOffset
);
1886 Dir
->Type
= EFI_IMAGE_DEBUG_TYPE_CODEVIEW
;
1887 Dir
->SizeOfData
= sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
) + Len
;
1888 Dir
->RVA
= mDebugOffset
+ sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
1889 Dir
->FileOffset
= mDebugOffset
+ sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
1891 Nb10
= (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
*)(Dir
+ 1);
1892 Nb10
->Signature
= CODEVIEW_SIGNATURE_NB10
;
1893 strcpy ((char *)(Nb10
+ 1), mInImageName
);
1896 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)(mCoffFile
+ mNtHdrOffset
);
1897 DataDir
= &NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1898 DataDir
->VirtualAddress
= mDebugOffset
;
1899 DataDir
->Size
= sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
1908 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
1913 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)(mCoffFile
+ mNtHdrOffset
);
1914 NtHdr
->Pe32Plus
.OptionalHeader
.SizeOfImage
= mCoffOffset
;
1923 if (mCoffSectionsOffset
!= NULL
) {
1924 free (mCoffSectionsOffset
);
1934 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
1935 EFI_IMAGE_EXPORT_DIRECTORY
*ExportDir
;
1936 EFI_IMAGE_DATA_DIRECTORY
*DataDir
;
1937 UINT32 FileNameOffset
;
1940 UINT8
*Tdata
= NULL
;
1942 ExportDir
= (EFI_IMAGE_EXPORT_DIRECTORY
*)(mCoffFile
+ mExportOffset
);
1943 ExportDir
->Characteristics
= 0;
1944 ExportDir
->TimeDateStamp
= 0;
1945 ExportDir
->MajorVersion
= 0;
1946 ExportDir
->MinorVersion
=0;
1947 ExportDir
->Name
= 0;
1948 ExportDir
->NumberOfFunctions
= mExportSymNum
;
1949 ExportDir
->NumberOfNames
= mExportSymNum
;
1950 ExportDir
->Base
= EFI_IMAGE_EXPORT_ORDINAL_BASE
;
1951 ExportDir
->AddressOfFunctions
= mExportOffset
+ sizeof(EFI_IMAGE_EXPORT_DIRECTORY
);
1952 ExportDir
->AddressOfNames
= ExportDir
->AddressOfFunctions
+ EFI_IMAGE_EXPORT_ADDR_SIZE
* mExportSymNum
;
1953 ExportDir
->AddressOfNameOrdinals
= ExportDir
->AddressOfNames
+ EFI_IMAGE_EXPORT_ADDR_SIZE
* mExportSymNum
;
1955 FileNameOffset
= ExportDir
->AddressOfNameOrdinals
+ EFI_IMAGE_EXPORT_ORDINAL_SIZE
* mExportSymNum
;
1956 NameOffset
= FileNameOffset
+ strlen(mInImageName
) + 1;
1958 // Write Input image Name RVA
1959 ExportDir
->Name
= FileNameOffset
;
1961 // Write Input image Name
1962 strcpy((char *)(mCoffFile
+ FileNameOffset
), mInImageName
);
1964 for (Index
= 0; Index
< mExportSymNum
; Index
++) {
1966 // Write Export Address Table
1968 Tdata
= mCoffFile
+ ExportDir
->AddressOfFunctions
+ Index
* EFI_IMAGE_EXPORT_ADDR_SIZE
;
1969 *(UINT32
*)Tdata
= mExportRVA
[Index
];
1972 // Write Export Name Pointer Table
1974 Tdata
= mCoffFile
+ ExportDir
->AddressOfNames
+ Index
* EFI_IMAGE_EXPORT_ADDR_SIZE
;
1975 *(UINT32
*)Tdata
= NameOffset
;
1978 // Write Export Ordinal table
1980 Tdata
= mCoffFile
+ ExportDir
->AddressOfNameOrdinals
+ Index
* EFI_IMAGE_EXPORT_ORDINAL_SIZE
;
1981 *(UINT16
*)Tdata
= Index
;
1984 // Write Export Name Table
1986 strcpy((char *)(mCoffFile
+ NameOffset
), mExportSymName
[Index
]);
1987 NameOffset
+= strlen(mExportSymName
[Index
]) + 1;
1990 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)(mCoffFile
+ mNtHdrOffset
);
1991 DataDir
= &NtHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
];
1992 DataDir
->VirtualAddress
= mExportOffset
;
1993 DataDir
->Size
= mExportSize
;