]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf64Convert.c
BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
index 606c7284f7378709ae8d6dd2a97e6de79943ea6a..90351125893d083392947337c058e19d98cb3ac1 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
 /** @file\r
+Elf64 convert solution\r
 \r
 \r
-Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
-Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2018, 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
 under the terms and conditions of the BSD License which accompanies this\r
 \r
 This program and the accompanying materials are licensed and made available\r
 under the terms and conditions of the BSD License which accompanies this\r
@@ -93,15 +94,24 @@ STATIC Elf_Ehdr *mEhdr;
 STATIC Elf_Shdr *mShdrBase;\r
 STATIC Elf_Phdr *mPhdrBase;\r
 \r
 STATIC Elf_Shdr *mShdrBase;\r
 STATIC Elf_Phdr *mPhdrBase;\r
 \r
+//\r
+// GOT information\r
+//\r
+STATIC Elf_Shdr *mGOTShdr = NULL;\r
+STATIC UINT32   mGOTShindex = 0;\r
+STATIC UINT32   *mGOTCoffEntries = NULL;\r
+STATIC UINT32   mGOTMaxCoffEntries = 0;\r
+STATIC UINT32   mGOTNumCoffEntries = 0;\r
+\r
 //\r
 // Coff information\r
 //\r
 //\r
 // Coff information\r
 //\r
-STATIC const UINT32 mCoffAlignment = 0x20;\r
+STATIC UINT32 mCoffAlignment = 0x20;\r
 \r
 //\r
 // PE section alignment.\r
 //\r
 \r
 //\r
 // PE section alignment.\r
 //\r
-STATIC const UINT16 mCoffNbrSections = 5;\r
+STATIC const UINT16 mCoffNbrSections = 4;\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
@@ -116,6 +126,7 @@ STATIC UINT32 mTextOffset;
 STATIC UINT32 mDataOffset;\r
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
 STATIC UINT32 mDataOffset;\r
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
+STATIC UINT32 mDebugOffset;\r
 \r
 //\r
 // Initialization Function\r
 \r
 //\r
 // Initialization Function\r
@@ -169,6 +180,10 @@ InitializeElf64 (
   //\r
   VerboseMsg ("Create COFF Section Offset Buffer");\r
   mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\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
   memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
 \r
   //\r
@@ -195,8 +210,11 @@ GetShdrByIndex (
   UINT32 Num\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 (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
 }\r
 \r
@@ -209,6 +227,15 @@ CoffAlign (
   return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
 }\r
 \r
   return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
 }\r
 \r
+STATIC\r
+UINT32\r
+DebugRvaAlign (\r
+  UINT32 Offset\r
+  )\r
+{\r
+  return (Offset + 3) & ~3;\r
+}\r
+\r
 //\r
 // filter functions\r
 //\r
 //\r
 // filter functions\r
 //\r
@@ -244,6 +271,194 @@ IsDataShdr (
   return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\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
+  Elf_Shdr *StrtabShdr;\r
+  UINT8    *StrtabContents;\r
+  BOOLEAN  foundEnd;\r
+  UINT32   i;\r
+\r
+  if (Sym->st_name == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  StrtabShdr = FindStrtabShdr();\r
+  if (StrtabShdr == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  assert(Sym->st_name < StrtabShdr->sh_size);\r
+\r
+  StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
+\r
+  foundEnd = FALSE;\r
+  for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
+    foundEnd = (BOOLEAN)(StrtabContents[i] == 0);\r
+  }\r
+  assert(foundEnd);\r
+\r
+  return StrtabContents + Sym->st_name;\r
+}\r
+\r
+//\r
+// Find the ELF section hosting the GOT from an ELF Rva\r
+//   of a single GOT entry.  Normally, GOT is placed in\r
+//   ELF .text section, so assume once we find in which\r
+//   section the GOT is, all GOT entries are there, and\r
+//   just verify this.\r
+//\r
+STATIC\r
+VOID\r
+FindElfGOTSectionFromGOTEntryElfRva (\r
+  Elf64_Addr GOTEntryElfRva\r
+  )\r
+{\r
+  UINT32 i;\r
+  if (mGOTShdr != NULL) {\r
+    if (GOTEntryElfRva >= mGOTShdr->sh_addr &&\r
+        GOTEntryElfRva <  mGOTShdr->sh_addr + mGOTShdr->sh_size) {\r
+      return;\r
+    }\r
+    Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");\r
+    exit(EXIT_FAILURE);\r
+  }\r
+  for (i = 0; i < mEhdr->e_shnum; i++) {\r
+    Elf_Shdr *shdr = GetShdrByIndex(i);\r
+    if (GOTEntryElfRva >= shdr->sh_addr &&\r
+        GOTEntryElfRva <  shdr->sh_addr + shdr->sh_size) {\r
+      mGOTShdr = shdr;\r
+      mGOTShindex = i;\r
+      return;\r
+    }\r
+  }\r
+  Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva);\r
+  exit(EXIT_FAILURE);\r
+}\r
+\r
+//\r
+// Stores locations of GOT entries in COFF image.\r
+//   Returns TRUE if GOT entry is new.\r
+//   Simple implementation as number of GOT\r
+//   entries is expected to be low.\r
+//\r
+\r
+STATIC\r
+BOOLEAN\r
+AccumulateCoffGOTEntries (\r
+  UINT32 GOTCoffEntry\r
+  )\r
+{\r
+  UINT32 i;\r
+  if (mGOTCoffEntries != NULL) {\r
+    for (i = 0; i < mGOTNumCoffEntries; i++) {\r
+      if (mGOTCoffEntries[i] == GOTCoffEntry) {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+  if (mGOTCoffEntries == NULL) {\r
+    mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries);\r
+    if (mGOTCoffEntries == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+    }\r
+    assert (mGOTCoffEntries != NULL);\r
+    mGOTMaxCoffEntries = 5;\r
+    mGOTNumCoffEntries = 0;\r
+  } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) {\r
+    mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries);\r
+    if (mGOTCoffEntries == NULL) {\r
+      Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+    }\r
+    assert (mGOTCoffEntries != NULL);\r
+    mGOTMaxCoffEntries += mGOTMaxCoffEntries;\r
+  }\r
+  mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry;\r
+  return TRUE;\r
+}\r
+\r
+//\r
+// 32-bit Unsigned integer comparator for qsort.\r
+//\r
+STATIC\r
+int\r
+UINT32Comparator (\r
+  const void* lhs,\r
+  const void* rhs\r
+  )\r
+{\r
+  if (*(const UINT32*)lhs < *(const UINT32*)rhs) {\r
+    return -1;\r
+  }\r
+  return *(const UINT32*)lhs > *(const UINT32*)rhs;\r
+}\r
+\r
+//\r
+// Emit accumulated Coff GOT entry relocations into\r
+//   Coff image.  This function performs its job\r
+//   once and then releases the entry list, so\r
+//   it can safely be called multiple times.\r
+//\r
+STATIC\r
+VOID\r
+EmitGOTRelocations (\r
+  VOID\r
+  )\r
+{\r
+  UINT32 i;\r
+  if (mGOTCoffEntries == NULL) {\r
+    return;\r
+  }\r
+  //\r
+  // Emit Coff relocations with Rvas ordered.\r
+  //\r
+  qsort(\r
+    mGOTCoffEntries,\r
+    mGOTNumCoffEntries,\r
+    sizeof *mGOTCoffEntries,\r
+    UINT32Comparator);\r
+  for (i = 0; i < mGOTNumCoffEntries; i++) {\r
+    VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]);\r
+    CoffAddFixup(\r
+      mGOTCoffEntries[i],\r
+      EFI_IMAGE_REL_BASED_DIR64);\r
+  }\r
+  free(mGOTCoffEntries);\r
+  mGOTCoffEntries = NULL;\r
+  mGOTMaxCoffEntries = 0;\r
+  mGOTNumCoffEntries = 0;\r
+}\r
+\r
 //\r
 // Elf functions interface implementation\r
 //\r
 //\r
 // Elf functions interface implementation\r
 //\r
@@ -259,12 +474,10 @@ ScanSections64 (
   EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
-  BOOLEAN                         FoundText;\r
+  BOOLEAN                         FoundSection;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
-  mTextOffset = 0;\r
-  FoundText = FALSE;\r
 \r
   //\r
   // Coff file start with a DOS header.\r
 \r
   //\r
   // Coff file start with a DOS header.\r
@@ -278,7 +491,7 @@ ScanSections64 (
     mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
   break;\r
   default:\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
     mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
   break;\r
   }\r
@@ -286,10 +499,45 @@ ScanSections64 (
   mTableOffset = mCoffOffset;\r
   mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
 \r
   mTableOffset = mCoffOffset;\r
   mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
 \r
+  //\r
+  // Set mCoffAlignment to the maximum alignment of the input sections\r
+  // we care about\r
+  //\r
+  for (i = 0; i < mEhdr->e_shnum; i++) {\r
+    Elf_Shdr *shdr = GetShdrByIndex(i);\r
+    if (shdr->sh_addralign <= mCoffAlignment) {\r
+      continue;\r
+    }\r
+    if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
+      mCoffAlignment = (UINT32)shdr->sh_addralign;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT\r
+  //\r
+  if (mCoffAlignment > MAX_COFF_ALIGNMENT) {\r
+    Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT.");\r
+    assert (FALSE);\r
+  }\r
+\r
+\r
+  //\r
+  // Move the PE/COFF header right before the first section. This will help us\r
+  // save space when converting to TE.\r
+  //\r
+  if (mCoffAlignment > mCoffOffset) {\r
+    mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
+    mTableOffset += mCoffAlignment - mCoffOffset;\r
+    mCoffOffset = mCoffAlignment;\r
+  }\r
+\r
   //\r
   // First text sections.\r
   //\r
   mCoffOffset = CoffAlign(mCoffOffset);\r
   //\r
   // First text sections.\r
   //\r
   mCoffOffset = CoffAlign(mCoffOffset);\r
+  mTextOffset = mCoffOffset;\r
+  FoundSection = FALSE;\r
   SectionCount = 0;\r
   for (i = 0; i < mEhdr->e_shnum; i++) {\r
     Elf_Shdr *shdr = GetShdrByIndex(i);\r
   SectionCount = 0;\r
   for (i = 0; i < mEhdr->e_shnum; i++) {\r
     Elf_Shdr *shdr = GetShdrByIndex(i);\r
@@ -299,12 +547,8 @@ ScanSections64 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
 \r
         }\r
       }\r
 \r
@@ -317,9 +561,9 @@ ScanSections64 (
       //\r
       // Set mTextOffset with the offset of the first '.text' section\r
       //\r
       //\r
       // Set mTextOffset with the offset of the first '.text' section\r
       //\r
-      if (!FoundText) {\r
+      if (!FoundSection) {\r
         mTextOffset = mCoffOffset;\r
         mTextOffset = mCoffOffset;\r
-        FoundText = TRUE;\r
+        FoundSection = TRUE;\r
       }\r
 \r
       mCoffSectionsOffset[i] = mCoffOffset;\r
       }\r
 \r
       mCoffSectionsOffset[i] = mCoffOffset;\r
@@ -328,14 +572,13 @@ ScanSections64 (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
-  if (!FoundText) {\r
+  if (!FoundSection) {\r
     Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
     assert (FALSE);\r
   }\r
 \r
     Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
     assert (FALSE);\r
   }\r
 \r
-  if (mEhdr->e_machine != EM_ARM) {\r
-    mCoffOffset = CoffAlign(mCoffOffset);\r
-  }\r
+  mDebugOffset = DebugRvaAlign(mCoffOffset);\r
+  mCoffOffset = CoffAlign(mCoffOffset);\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
@@ -345,6 +588,7 @@ ScanSections64 (
   //  Then data sections.\r
   //\r
   mDataOffset = mCoffOffset;\r
   //  Then data sections.\r
   //\r
   mDataOffset = mCoffOffset;\r
+  FoundSection = FALSE;\r
   SectionCount = 0;\r
   for (i = 0; i < mEhdr->e_shnum; i++) {\r
     Elf_Shdr *shdr = GetShdrByIndex(i);\r
   SectionCount = 0;\r
   for (i = 0; i < mEhdr->e_shnum; i++) {\r
     Elf_Shdr *shdr = GetShdrByIndex(i);\r
@@ -354,20 +598,41 @@ ScanSections64 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
         }\r
       }\r
+\r
+      //\r
+      // Set mDataOffset with the offset of the first '.data' section\r
+      //\r
+      if (!FoundSection) {\r
+        mDataOffset = mCoffOffset;\r
+        FoundSection = TRUE;\r
+      }\r
       mCoffSectionsOffset[i] = mCoffOffset;\r
       mCoffOffset += (UINT32) shdr->sh_size;\r
       SectionCount ++;\r
     }\r
   }\r
       mCoffSectionsOffset[i] = mCoffOffset;\r
       mCoffOffset += (UINT32) shdr->sh_size;\r
       SectionCount ++;\r
     }\r
   }\r
+\r
+  //\r
+  // Make room for .debug data in .data (or .text if .data is empty) instead of\r
+  // putting it in a section of its own. This is explicitly allowed by the\r
+  // PE/COFF spec, and prevents bloat in the binary when using large values for\r
+  // section alignment.\r
+  //\r
+  if (SectionCount > 0) {\r
+    mDebugOffset = DebugRvaAlign(mCoffOffset);\r
+  }\r
+  mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
+                sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
+                strlen(mInImageName) + 1;\r
+\r
   mCoffOffset = CoffAlign(mCoffOffset);\r
   mCoffOffset = CoffAlign(mCoffOffset);\r
+  if (SectionCount == 0) {\r
+    mDataOffset = mCoffOffset;\r
+  }\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
@@ -385,15 +650,12 @@ ScanSections64 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
       if (shdr->sh_size != 0) {\r
         }\r
       }\r
       if (shdr->sh_size != 0) {\r
+        mHiiRsrcOffset = mCoffOffset;\r
         mCoffSectionsOffset[i] = mCoffOffset;\r
         mCoffOffset += (UINT32) shdr->sh_size;\r
         mCoffOffset = CoffAlign(mCoffOffset);\r
         mCoffSectionsOffset[i] = mCoffOffset;\r
         mCoffOffset += (UINT32) shdr->sh_size;\r
         mCoffOffset = CoffAlign(mCoffOffset);\r
@@ -409,6 +671,10 @@ ScanSections64 (
   // Allocate base Coff file.  Will be expanded later for relocations.\r
   //\r
   mCoffFile = (UINT8 *)malloc(mCoffOffset);\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
   memset(mCoffFile, 0, mCoffOffset);\r
 \r
   //\r
@@ -514,6 +780,7 @@ WriteSections64 (
   Elf_Shdr    *SecShdr;\r
   UINT32      SecOffset;\r
   BOOLEAN     (*Filter)(Elf_Shdr *);\r
   Elf_Shdr    *SecShdr;\r
   UINT32      SecOffset;\r
   BOOLEAN     (*Filter)(Elf_Shdr *);\r
+  Elf64_Addr  GOTEntryRva;\r
 \r
   //\r
   // Initialize filter pointer\r
 \r
   //\r
   // Initialize filter pointer\r
@@ -541,6 +808,9 @@ WriteSections64 (
       switch (Shdr->sh_type) {\r
       case SHT_PROGBITS:\r
         /* Copy.  */\r
       switch (Shdr->sh_type) {\r
       case SHT_PROGBITS:\r
         /* Copy.  */\r
+        if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) {\r
+          return FALSE;\r
+        }\r
         memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
               (UINT8*)mEhdr + Shdr->sh_offset,\r
               (size_t) Shdr->sh_size);\r
         memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
               (UINT8*)mEhdr + Shdr->sh_offset,\r
               (size_t) Shdr->sh_size);\r
@@ -573,6 +843,20 @@ WriteSections64 (
       continue;\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,\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
     //\r
     // Relocation section found.  Now extract section information that the relocations\r
     // apply to in the ELF data and the new COFF data.\r
@@ -615,9 +899,18 @@ WriteSections64 (
         // header location.\r
         //\r
         if (Sym->st_shndx == SHN_UNDEF\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
         }\r
         SymShdr = GetShdrByIndex(Sym->st_shndx);\r
 \r
@@ -645,79 +938,185 @@ WriteSections64 (
             // Absolute relocation.\r
             //\r
             VerboseMsg ("R_X86_64_64");\r
             // Absolute relocation.\r
             //\r
             VerboseMsg ("R_X86_64_64");\r
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", \r
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
               *(UINT64 *)Targ);\r
             *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
             VerboseMsg ("Relocation:  0x%016LX", *(UINT64*)Targ);\r
             break;\r
           case R_X86_64_32:\r
             VerboseMsg ("R_X86_64_32");\r
               *(UINT64 *)Targ);\r
             *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
             VerboseMsg ("Relocation:  0x%016LX", *(UINT64*)Targ);\r
             break;\r
           case R_X86_64_32:\r
             VerboseMsg ("R_X86_64_32");\r
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
               *(UINT32 *)Targ);\r
             *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
             VerboseMsg ("Relocation:  0x%08X", *(UINT32*)Targ);\r
             break;\r
           case R_X86_64_32S:\r
             VerboseMsg ("R_X86_64_32S");\r
               *(UINT32 *)Targ);\r
             *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
             VerboseMsg ("Relocation:  0x%08X", *(UINT32*)Targ);\r
             break;\r
           case R_X86_64_32S:\r
             VerboseMsg ("R_X86_64_32S");\r
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
               *(UINT32 *)Targ);\r
             *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
             VerboseMsg ("Relocation:  0x%08X", *(UINT32*)Targ);\r
             break;\r
               *(UINT32 *)Targ);\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
             //\r
             VerboseMsg ("R_X86_64_PC32");\r
           case R_X86_64_PC32:\r
             //\r
             // Relative relocation: Symbol - Ip + Addend\r
             //\r
             VerboseMsg ("R_X86_64_PC32");\r
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
               *(UINT32 *)Targ);\r
             *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
               + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
               - (SecOffset - SecShdr->sh_addr));\r
             VerboseMsg ("Relocation:  0x%08X", *(UINT32 *)Targ);\r
             break;\r
               *(UINT32 *)Targ);\r
             *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
               + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
               - (SecOffset - SecShdr->sh_addr));\r
             VerboseMsg ("Relocation:  0x%08X", *(UINT32 *)Targ);\r
             break;\r
+          case R_X86_64_GOTPCREL:\r
+          case R_X86_64_GOTPCRELX:\r
+          case R_X86_64_REX_GOTPCRELX:\r
+            VerboseMsg ("R_X86_64_GOTPCREL family");\r
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
+              *(UINT32 *)Targ);\r
+            GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ;\r
+            FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva);\r
+            *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
+              + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr)\r
+              - (SecOffset - SecShdr->sh_addr));\r
+            VerboseMsg ("Relocation:  0x%08X", *(UINT32 *)Targ);\r
+            GOTEntryRva += (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr);  // ELF Rva -> COFF Rva\r
+            if (AccumulateCoffGOTEntries((UINT32)GOTEntryRva)) {\r
+              //\r
+              // Relocate GOT entry if it's the first time we run into it\r
+              //\r
+              Targ = mCoffFile + GOTEntryRva;\r
+              //\r
+              // Limitation: The following three statements assume memory\r
+              //   at *Targ is valid because the section containing the GOT\r
+              //   has already been copied from the ELF image to the Coff image.\r
+              //   This pre-condition presently holds because the GOT is placed\r
+              //   in section .text, and the ELF text sections are all copied\r
+              //   prior to reaching this point.\r
+              //   If the pre-condition is violated in the future, this fixup\r
+              //   either needs to be deferred after the GOT section is copied\r
+              //   to the Coff image, or the fixup should be performed on the\r
+              //   source Elf image instead of the destination Coff image.\r
+              //\r
+              VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
+                (UINT32)GOTEntryRva,\r
+                *(UINT64 *)Targ);\r
+              *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
+              VerboseMsg ("Relocation:  0x%016LX", *(UINT64*)Targ);\r
+            }\r
+            break;\r
           default:\r
             Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
           }\r
         } else if (mEhdr->e_machine == EM_AARCH64) {\r
 \r
           default:\r
             Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
           }\r
         } else if (mEhdr->e_machine == EM_AARCH64) {\r
 \r
-          // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up.\r
-          // As opposed to ARM32 using REL.\r
-\r
           switch (ELF_R_TYPE(Rel->r_info)) {\r
 \r
           switch (ELF_R_TYPE(Rel->r_info)) {\r
 \r
-          case R_AARCH64_LD_PREL_LO19:\r
-            if  (Rel->r_addend != 0 ) { /* TODO */\r
-              Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");\r
+          case R_AARCH64_ADR_PREL_PG_HI21:\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
             }\r
-            break;\r
+            /* fall through */\r
 \r
 \r
-          case R_AARCH64_CALL26:\r
-            if  (Rel->r_addend != 0 ) { /* TODO */\r
-              Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CALL26 Need to fixup with addend!.");\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
+              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
             }\r
-            break;\r
+            /* fall through */\r
 \r
 \r
+          case R_AARCH64_ADR_PREL_LO21:\r
+          case R_AARCH64_CONDBR19:\r
+          case R_AARCH64_LD_PREL_LO19:\r
+          case R_AARCH64_CALL26:\r
           case R_AARCH64_JUMP26:\r
           case R_AARCH64_JUMP26:\r
-            if  (Rel->r_addend != 0 ) { /* TODO : AArch64 '-O2' optimisation. */\r
-              Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");\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
+            // binaries. More specifically, they tend to fail to take into\r
+            // account the fact that a '.rodata + XXX' relocation needs to have\r
+            // its addend recalculated once .rodata is merged into the .text\r
+            // section, and the relocation emitted into the .rela.text section.\r
+            //\r
+            // We cannot really recover from this loss of information, so the\r
+            // only workaround is to prevent having to recalculate any relative\r
+            // relocations at all, by using a linker script that ensures that\r
+            // the offset between the Place and the Symbol is the same in both\r
+            // the ELF and the PE/COFF versions of the binary.\r
+            //\r
+            if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
+                (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
+              Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
+                mInImageName);\r
             }\r
             break;\r
 \r
             }\r
             break;\r
 \r
-          case R_AARCH64_ADR_PREL_PG_HI21:\r
-            // TODO : AArch64 'small' memory model.\r
-            Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
-            break;\r
-\r
-          case R_AARCH64_ADD_ABS_LO12_NC:\r
-            // TODO : AArch64 'small' memory model.\r
-            Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
-            break;\r
-\r
           // Absolute relocations.\r
           case R_AARCH64_ABS64:\r
             *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
           // Absolute relocations.\r
           case R_AARCH64_ABS64:\r
             *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
@@ -760,9 +1159,13 @@ WriteRelocations64 (
             switch (ELF_R_TYPE(Rel->r_info)) {\r
             case R_X86_64_NONE:\r
             case R_X86_64_PC32:\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
+            case R_X86_64_GOTPCREL:\r
+            case R_X86_64_GOTPCRELX:\r
+            case R_X86_64_REX_GOTPCRELX:\r
               break;\r
             case R_X86_64_64:\r
               break;\r
             case R_X86_64_64:\r
-              VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
+              VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
@@ -771,7 +1174,7 @@ WriteRelocations64 (
               break;\r
             case R_X86_64_32S:\r
             case R_X86_64_32:\r
               break;\r
             case R_X86_64_32S:\r
             case R_X86_64_32:\r
-              VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
+              VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
@@ -782,25 +1185,29 @@ WriteRelocations64 (
               Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
             }\r
           } else if (mEhdr->e_machine == EM_AARCH64) {\r
               Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
             }\r
           } else if (mEhdr->e_machine == EM_AARCH64) {\r
-            // AArch64 GCC uses RELA relocation, so all relocations has to be fixed up. ARM32 uses REL.\r
+\r
             switch (ELF_R_TYPE(Rel->r_info)) {\r
             switch (ELF_R_TYPE(Rel->r_info)) {\r
+            case R_AARCH64_ADR_PREL_LO21:\r
+            case R_AARCH64_CONDBR19:\r
             case R_AARCH64_LD_PREL_LO19:\r
             case R_AARCH64_LD_PREL_LO19:\r
-              break;\r
-\r
             case R_AARCH64_CALL26:\r
             case R_AARCH64_CALL26:\r
-              break;\r
-\r
             case R_AARCH64_JUMP26:\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_ADR_PREL_PG_HI21:\r
-              // TODO : AArch64 'small' memory model.\r
-              Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
-              break;\r
-\r
             case R_AARCH64_ADD_ABS_LO12_NC:\r
             case R_AARCH64_ADD_ABS_LO12_NC:\r
-              // TODO : AArch64 'small' memory model.\r
-              Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\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
+              // 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
               break;\r
 \r
             case R_AARCH64_ABS64:\r
@@ -824,10 +1231,32 @@ WriteRelocations64 (
             Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);\r
           }\r
         }\r
             Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);\r
           }\r
         }\r
+        if (mEhdr->e_machine == EM_X86_64 && RelShdr->sh_info == mGOTShindex) {\r
+          //\r
+          // Tack relocations for GOT entries after other relocations for\r
+          //   the section the GOT is in, as it's usually found at the end\r
+          //   of the section.  This is done in order to maintain Rva order\r
+          //   of Coff relocations.\r
+          //\r
+          EmitGOTRelocations();\r
+        }\r
       }\r
     }\r
   }\r
 \r
       }\r
     }\r
   }\r
 \r
+  if (mEhdr->e_machine == EM_X86_64) {\r
+    //\r
+    // This is a safety net just in case the GOT is in a section\r
+    //   with no other relocations and the first invocation of\r
+    //   EmitGOTRelocations() above was skipped.  This invocation\r
+    //   does not maintain Rva order of Coff relocations.\r
+    //   At present, with a single text section, all references to\r
+    //   the GOT and the GOT itself reside in section .text, so\r
+    //   if there's a GOT at all, the first invocation above\r
+    //   is executed.\r
+    //\r
+    EmitGOTRelocations();\r
+  }\r
   //\r
   // Pad by adding empty entries.\r
   //\r
   //\r
   // Pad by adding empty entries.\r
   //\r
@@ -858,28 +1287,18 @@ WriteDebug64 (
   )\r
 {\r
   UINT32                              Len;\r
   )\r
 {\r
   UINT32                              Len;\r
-  UINT32                              DebugOffset;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
   EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY     *Dir;\r
   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
 \r
   Len = strlen(mInImageName) + 1;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
   EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY     *Dir;\r
   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
 \r
   Len = strlen(mInImageName) + 1;\r
-  DebugOffset = mCoffOffset;\r
-\r
-  mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)\r
-    + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)\r
-    + Len;\r
-  mCoffOffset = CoffAlign(mCoffOffset);\r
-\r
-  mCoffFile = realloc(mCoffFile, mCoffOffset);\r
-  memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);\r
 \r
 \r
-  Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);\r
+  Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
-  Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
-  Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+  Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+  Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
 \r
   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
 \r
   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
@@ -888,20 +1307,8 @@ WriteDebug64 (
 \r
   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
   DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
 \r
   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
   DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
-  DataDir->VirtualAddress = DebugOffset;\r
-  DataDir->Size = mCoffOffset - DebugOffset;\r
-  if (DataDir->Size == 0) {\r
-    // If no debug, null out the directory entry and don't add the .debug section\r
-    DataDir->VirtualAddress = 0;\r
-    NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
-  } else {\r
-    DataDir->VirtualAddress = DebugOffset;\r
-    CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,\r
-            EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
-            | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
-            | EFI_IMAGE_SCN_MEM_READ);\r
-\r
-  }\r
+  DataDir->VirtualAddress = mDebugOffset;\r
+  DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
 }\r
 \r
 STATIC\r
 }\r
 \r
 STATIC\r