]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf64Convert.c
Sync BaseTool trunk (version r2599) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
index e7c5d4997a1dc971c37cc041016c2d093de98273..72d6cd16d786f7e8674888c9da648012cbf6f5a6 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
@@ -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);
           }