]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf64Convert.c
Fix the typo for the structure definition of EFI_ADAPTER_INFO_NETWORK_BOOT in Adapter...
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
index fbe6ff8232e13c81239e18a3effdfb932566c82b..713f8f7e4722f2e2bc7f82296554370032eba5f0 100644 (file)
@@ -1,6 +1,7 @@
 /** @file
 
 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>
 
 This program and the accompanying materials are licensed and made available
 under the terms and conditions of the BSD License which accompanies this
@@ -18,6 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <windows.h>
 #include <io.h>
 #endif
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -146,8 +148,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) {
@@ -257,9 +259,12 @@ ScanSections64 (
   EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
   UINT32                          CoffEntry;
   UINT32                          SectionCount;
+  BOOLEAN                         FoundText;
 
   CoffEntry = 0;
   mCoffOffset = 0;
+  mTextOffset = 0;
+  FoundText = FALSE;
 
   //
   // Coff file start with a DOS header.
@@ -269,6 +274,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:
@@ -284,7 +290,6 @@ ScanSections64 (
   // First text sections.
   //
   mCoffOffset = CoffAlign(mCoffOffset);
-  mTextOffset = mCoffOffset;
   SectionCount = 0;
   for (i = 0; i < mEhdr->e_shnum; i++) {
     Elf_Shdr *shdr = GetShdrByIndex(i);
@@ -308,12 +313,26 @@ ScanSections64 (
           (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
         CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);
       }
+
+      //
+      // Set mTextOffset with the offset of the first '.text' section
+      //
+      if (!FoundText) {
+        mTextOffset = mCoffOffset;
+        FoundText = TRUE;
+      }
+
       mCoffSectionsOffset[i] = mCoffOffset;
       mCoffOffset += (UINT32) shdr->sh_size;
       SectionCount ++;
     }
   }
 
+  if (!FoundText) {
+    Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");
+    assert (FALSE);
+  }
+
   if (mEhdr->e_machine != EM_ARM) {
     mCoffOffset = CoffAlign(mCoffOffset);
   }
@@ -412,6 +431,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 +565,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 +622,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 +683,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");
         }
       }
     }
@@ -637,28 +745,16 @@ WriteRelocations64 (
   UINT32                           Index;
   EFI_IMAGE_OPTIONAL_HEADER_UNION  *NtHdr;
   EFI_IMAGE_DATA_DIRECTORY         *Dir;
-  BOOLEAN                          FoundRelocations;
-  Elf_Sym                          *Sym;
-  Elf_Shdr                         *SymtabShdr;
-  UINT8                            *Symtab;
-
 
-  for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
+  for (Index = 0; Index < mEhdr->e_shnum; Index++) {
     Elf_Shdr *RelShdr = GetShdrByIndex(Index);
     if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
       Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
       if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
         UINT64 RelIdx;
 
-        SymtabShdr = GetShdrByIndex (RelShdr->sh_link);
-        Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
-        FoundRelocations = TRUE;
         for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
           Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
-          Elf_Shdr *SymShdr;
-
-          Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
-          SymShdr = GetShdrByIndex (Sym->st_shndx);
 
           if (mEhdr->e_machine == EM_X86_64) {
             switch (ELF_R_TYPE(Rel->r_info)) {
@@ -685,6 +781,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);
           }