X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FC%2FGenFw%2FElf64Convert.c;h=72d6cd16d786f7e8674888c9da648012cbf6f5a6;hp=e7c5d4997a1dc971c37cc041016c2d093de98273;hb=4afd3d042215afe68d00b9ab8c32f063a3a1c03f;hpb=a365eed476687881ce0ed49af7d483fd3cb0c491 diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c index e7c5d4997a..72d6cd16d7 100644 --- a/BaseTools/Source/C/GenFw/Elf64Convert.c +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c @@ -1,6 +1,7 @@ /** @file Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+Portions copyright (c) 2013, ARM Ltd. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this @@ -146,8 +147,8 @@ InitializeElf64 ( Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN"); return FALSE; } - if (!((mEhdr->e_machine == EM_X86_64))) { - Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64"); + if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64))) { + Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64 or EM_AARCH64"); return FALSE; } if (mEhdr->e_version != EV_CURRENT) { @@ -269,6 +270,7 @@ ScanSections64 ( switch (mEhdr->e_machine) { case EM_X86_64: case EM_IA_64: + case EM_AARCH64: mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64); break; default: @@ -412,6 +414,10 @@ ScanSections64 ( NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF; NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; break; + case EM_AARCH64: + NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; default: VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine); NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64; @@ -542,22 +548,55 @@ WriteSections64 ( // VerboseMsg ("Applying Relocations..."); for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { + // + // Determine if this is a relocation section. + // Elf_Shdr *RelShdr = GetShdrByIndex(Idx); if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) { continue; } + + // + // Relocation section found. Now extract section information that the relocations + // apply to in the ELF data and the new COFF data. + // SecShdr = GetShdrByIndex(RelShdr->sh_info); SecOffset = mCoffSectionsOffset[RelShdr->sh_info]; + + // + // Only process relocations for the current filter type. + // if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) { UINT64 RelIdx; + + // + // Determine the symbol table referenced by the relocation data. + // Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link); UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset; + + // + // Process all relocation entries for this section. + // for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) { + + // + // Set pointer to relocation entry + // Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx); + + // + // Set pointer to symbol table entry associated with the relocation entry. + // Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize); + Elf_Shdr *SymShdr; UINT8 *Targ; + // + // Check section header index found in symbol table and get the section + // header location. + // if (Sym->st_shndx == SHN_UNDEF || Sym->st_shndx == SHN_ABS || Sym->st_shndx > mEhdr->e_shnum) { @@ -566,11 +605,20 @@ WriteSections64 ( SymShdr = GetShdrByIndex(Sym->st_shndx); // - // Note: r_offset in a memory address. - // Convert it to a pointer in the coff file. + // Convert the relocation data to a pointer into the coff file. + // + // Note: + // r_offset is the virtual address of the storage unit to be relocated. + // sh_addr is the virtual address for the base of the section. + // + // r_offset in a memory address. + // Convert it to a pointer in the coff file. // Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr); + // + // Determine how to handle each relocation type based on the machine type. + // if (mEhdr->e_machine == EM_X86_64) { switch (ELF_R_TYPE(Rel->r_info)) { case R_X86_64_NONE: @@ -618,8 +666,51 @@ WriteSections64 ( default: Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); } + } else if (mEhdr->e_machine == EM_AARCH64) { + + // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up. + // As opposed to ARM32 using REL. + + switch (ELF_R_TYPE(Rel->r_info)) { + + case R_AARCH64_LD_PREL_LO19: + if (Rel->r_addend != 0 ) { /* TODO */ + Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!."); + } + break; + + case R_AARCH64_CALL26: + if (Rel->r_addend != 0 ) { /* TODO */ + Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CALL26 Need to fixup with addend!."); + } + break; + + case R_AARCH64_JUMP26: + if (Rel->r_addend != 0 ) { /* TODO : AArch64 '-O2' optimisation. */ + Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!."); + } + break; + + case R_AARCH64_ADR_PREL_PG_HI21: + // TODO : AArch64 'small' memory model. + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName); + break; + + case R_AARCH64_ADD_ABS_LO12_NC: + // TODO : AArch64 'small' memory model. + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName); + break; + + // Absolute relocations. + case R_AARCH64_ABS64: + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } } else { - Error (NULL, 0, 3000, "Invalid", "Not EM_X86_X64"); + Error (NULL, 0, 3000, "Invalid", "Not a supported machine type"); } } } @@ -673,6 +764,45 @@ WriteRelocations64 ( default: Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); } + } else if (mEhdr->e_machine == EM_AARCH64) { + // AArch64 GCC uses RELA relocation, so all relocations has to be fixed up. ARM32 uses REL. + switch (ELF_R_TYPE(Rel->r_info)) { + case R_AARCH64_LD_PREL_LO19: + break; + + case R_AARCH64_CALL26: + break; + + case R_AARCH64_JUMP26: + break; + + case R_AARCH64_ADR_PREL_PG_HI21: + // TODO : AArch64 'small' memory model. + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName); + break; + + case R_AARCH64_ADD_ABS_LO12_NC: + // TODO : AArch64 'small' memory model. + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName); + break; + + case R_AARCH64_ABS64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_DIR64); + break; + + case R_AARCH64_ABS32: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_HIGHLOW); + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } } else { Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine); }