/** @file\r
Elf64 convert solution\r
\r
-Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>\r
Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
\r
This program and the accompanying materials are licensed and made available\r
#include <io.h>\r
#endif\r
#include <assert.h>\r
+#include <stdbool.h>\r
#include <stdio.h>\r
#include <stdlib.h>\r
#include <string.h>\r
//\r
VerboseMsg ("Create COFF Section Offset Buffer");\r
mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
+ if (mCoffSectionsOffset == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return FALSE;\r
+ }\r
memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
\r
//\r
UINT32 Num\r
)\r
{\r
- if (Num >= mEhdr->e_shnum)\r
- return NULL;\r
+ if (Num >= mEhdr->e_shnum) {\r
+ Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
+ exit(EXIT_FAILURE);\r
+ }\r
+\r
return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
}\r
\r
return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
}\r
\r
+STATIC\r
+BOOLEAN\r
+IsStrtabShdr (\r
+ Elf_Shdr *Shdr\r
+ )\r
+{\r
+ Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
+\r
+ return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
+}\r
+\r
+STATIC\r
+Elf_Shdr *\r
+FindStrtabShdr (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 i;\r
+ for (i = 0; i < mEhdr->e_shnum; i++) {\r
+ Elf_Shdr *shdr = GetShdrByIndex(i);\r
+ if (IsStrtabShdr(shdr)) {\r
+ return shdr;\r
+ }\r
+ }\r
+ return NULL;\r
+}\r
+\r
+STATIC\r
+const UINT8 *\r
+GetSymName (\r
+ Elf_Sym *Sym\r
+ )\r
+{\r
+ if (Sym->st_name == 0) {\r
+ return NULL;\r
+ }\r
+\r
+ Elf_Shdr *StrtabShdr = FindStrtabShdr();\r
+ if (StrtabShdr == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ assert(Sym->st_name < StrtabShdr->sh_size);\r
+\r
+ UINT8* StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
+\r
+ bool foundEnd = false;\r
+ UINT32 i;\r
+ for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
+ foundEnd = StrtabContents[i] == 0;\r
+ }\r
+ assert(foundEnd);\r
+\r
+ return StrtabContents + Sym->st_name;\r
+}\r
+\r
//\r
// Elf functions interface implementation\r
//\r
mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
break;\r
default:\r
- VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
+ VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine);\r
mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
break;\r
}\r
// Allocate base Coff file. Will be expanded later for relocations.\r
//\r
mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
+ if (mCoffFile == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ }\r
+ assert (mCoffFile != NULL);\r
memset(mCoffFile, 0, mCoffOffset);\r
\r
//\r
continue;\r
}\r
\r
+ //\r
+ // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA\r
+ // section that applies to the entire binary, and which will have its section\r
+ // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared).\r
+ //\r
+ // In the absence of GOT based relocations (which we currently don't support),\r
+ // this RELA section will contain redundant R_xxx_RELATIVE relocations, one\r
+ // for every R_xxx_xx64 relocation appearing in the per-section RELA sections.\r
+ // (i.e., .rela.text and .rela.data)\r
+ //\r
+ if (RelShdr->sh_info == 0) {\r
+ continue;\r
+ }\r
+\r
//\r
// Relocation section found. Now extract section information that the relocations\r
// apply to in the ELF data and the new COFF data.\r
// header location.\r
//\r
if (Sym->st_shndx == SHN_UNDEF\r
- || Sym->st_shndx == SHN_ABS\r
- || Sym->st_shndx > mEhdr->e_shnum) {\r
- Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
+ || Sym->st_shndx >= mEhdr->e_shnum) {\r
+ const UINT8 *SymName = GetSymName(Sym);\r
+ if (SymName == NULL) {\r
+ SymName = (const UINT8 *)"<unknown>";\r
+ }\r
+\r
+ Error (NULL, 0, 3000, "Invalid",\r
+ "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "\r
+ "For example, absolute and undefined symbols are not supported.",\r
+ mInImageName, SymName, Sym->st_value);\r
+\r
+ exit(EXIT_FAILURE);\r
}\r
SymShdr = GetShdrByIndex(Sym->st_shndx);\r
\r
*(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
break;\r
+\r
+ case R_X86_64_PLT32:\r
+ //\r
+ // Treat R_X86_64_PLT32 relocations as R_X86_64_PC32: this is\r
+ // possible since we know all code symbol references resolve to\r
+ // definitions in the same module (UEFI has no shared libraries),\r
+ // and so there is never a reason to jump via a PLT entry,\r
+ // allowing us to resolve the reference using the symbol directly.\r
+ //\r
+ VerboseMsg ("Treating R_X86_64_PLT32 as R_X86_64_PC32 ...");\r
+ /* fall through */\r
case R_X86_64_PC32:\r
//\r
// Relative relocation: Symbol - Ip + Addend\r
switch (ELF_R_TYPE(Rel->r_info)) {\r
\r
case R_AARCH64_ADR_PREL_PG_HI21:\r
- case R_AARCH64_ADD_ABS_LO12_NC:\r
- case R_AARCH64_LDST8_ABS_LO12_NC:\r
- case R_AARCH64_LDST16_ABS_LO12_NC:\r
- case R_AARCH64_LDST32_ABS_LO12_NC:\r
- case R_AARCH64_LDST64_ABS_LO12_NC:\r
- case R_AARCH64_LDST128_ABS_LO12_NC:\r
//\r
// AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
// relocations, where a PC-relative reference with +/- 4 GB range is\r
// split into a relative high part and an absolute low part. Since\r
// the absolute low part represents the offset into a 4 KB page, we\r
+ // either have to convert the ADRP into an ADR instruction, or we\r
+ // need to use a section alignment of at least 4 KB, so that the\r
+ // binary appears at a correct offset at runtime. In any case, we\r
// have to make sure that the 4 KB relative offsets of both the\r
// section containing the reference as well as the section to which\r
// it refers have not been changed during PE/COFF conversion (i.e.,\r
// in ScanSections64() above).\r
//\r
+ if (mCoffAlignment < 0x1000) {\r
+ //\r
+ // Attempt to convert the ADRP into an ADR instruction.\r
+ // This is only possible if the symbol is within +/- 1 MB.\r
+ //\r
+ INT64 Offset;\r
+\r
+ // Decode the ADRP instruction\r
+ Offset = (INT32)((*(UINT32 *)Targ & 0xffffe0) << 8);\r
+ Offset = (Offset << (6 - 5)) | ((*(UINT32 *)Targ & 0x60000000) >> (29 - 12));\r
+\r
+ //\r
+ // ADRP offset is relative to the previous page boundary,\r
+ // whereas ADR offset is relative to the instruction itself.\r
+ // So fix up the offset so it points to the page containing\r
+ // the symbol.\r
+ //\r
+ Offset -= (UINTN)(Targ - mCoffFile) & 0xfff;\r
+\r
+ if (Offset < -0x100000 || Offset > 0xfffff) {\r
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.",\r
+ mInImageName);\r
+ break;\r
+ }\r
+\r
+ // Re-encode the offset as an ADR instruction\r
+ *(UINT32 *)Targ &= 0x1000001f;\r
+ *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
+ }\r
+ /* fall through */\r
+\r
+ case R_AARCH64_ADD_ABS_LO12_NC:\r
+ case R_AARCH64_LDST8_ABS_LO12_NC:\r
+ case R_AARCH64_LDST16_ABS_LO12_NC:\r
+ case R_AARCH64_LDST32_ABS_LO12_NC:\r
+ case R_AARCH64_LDST64_ABS_LO12_NC:\r
+ case R_AARCH64_LDST128_ABS_LO12_NC:\r
if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
- ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0 ||\r
- mCoffAlignment < 0x1000) {\r
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires 4 KB section alignment.",\r
+ ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0) {\r
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB.",\r
mInImageName);\r
break;\r
}\r
case R_AARCH64_LD_PREL_LO19:\r
case R_AARCH64_CALL26:\r
case R_AARCH64_JUMP26:\r
+ case R_AARCH64_PREL64:\r
+ case R_AARCH64_PREL32:\r
+ case R_AARCH64_PREL16:\r
//\r
// The GCC toolchains (i.e., binutils) may corrupt section relative\r
// relocations when emitting relocation sections into fully linked\r
switch (ELF_R_TYPE(Rel->r_info)) {\r
case R_X86_64_NONE:\r
case R_X86_64_PC32:\r
+ case R_X86_64_PLT32:\r
break;\r
case R_X86_64_64:\r
VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
\r
switch (ELF_R_TYPE(Rel->r_info)) {\r
case R_AARCH64_ADR_PREL_LO21:\r
- break;\r
-\r
case R_AARCH64_CONDBR19:\r
- break;\r
-\r
case R_AARCH64_LD_PREL_LO19:\r
- break;\r
-\r
case R_AARCH64_CALL26:\r
- break;\r
-\r
case R_AARCH64_JUMP26:\r
- break;\r
-\r
+ case R_AARCH64_PREL64:\r
+ case R_AARCH64_PREL32:\r
+ case R_AARCH64_PREL16:\r
case R_AARCH64_ADR_PREL_PG_HI21:\r
case R_AARCH64_ADD_ABS_LO12_NC:\r
case R_AARCH64_LDST8_ABS_LO12_NC:\r
case R_AARCH64_LDST32_ABS_LO12_NC:\r
case R_AARCH64_LDST64_ABS_LO12_NC:\r
case R_AARCH64_LDST128_ABS_LO12_NC:\r
+ //\r
+ // No fixups are required for relative relocations, provided that\r
+ // the relative offsets between sections have been preserved in\r
+ // the ELF to PE/COFF conversion. We have already asserted that\r
+ // this is the case in WriteSections64 ().\r
+ //\r
break;\r
\r
case R_AARCH64_ABS64:\r