]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf64Convert.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
index fb85b3821b38afa044e92541aa762f249baf9ed8..8b50774beb1eebda24d00cea9014d9ec6749cb36 100644 (file)
@@ -1,16 +1,12 @@
 /** @file\r
 Elf64 convert solution\r
 \r
-Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
-Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>\r
+Portions copyright (c) 2013-2022, ARM Ltd. All rights reserved.<BR>\r
+Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
+Portions Copyright (c) 2022, Loongson Technology Corporation Limited. 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
-distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -61,6 +57,12 @@ WriteDebug64 (
   VOID\r
   );\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  );\r
+\r
 STATIC\r
 VOID\r
 SetImageSize64 (\r
@@ -74,7 +76,7 @@ CleanUp64 (
   );\r
 \r
 //\r
-// Rename ELF32 strucutres to common names to help when porting to ELF64.\r
+// Rename ELF32 structures to common names to help when porting to ELF64.\r
 //\r
 typedef Elf64_Shdr Elf_Shdr;\r
 typedef Elf64_Ehdr Elf_Ehdr;\r
@@ -94,6 +96,15 @@ STATIC Elf_Ehdr *mEhdr;
 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
@@ -102,7 +113,7 @@ STATIC UINT32 mCoffAlignment = 0x20;
 //\r
 // PE section alignment.\r
 //\r
-STATIC const UINT16 mCoffNbrSections = 4;\r
+STATIC UINT16 mCoffNbrSections = 4;\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
@@ -118,6 +129,23 @@ STATIC UINT32 mDataOffset;
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
 STATIC UINT32 mDebugOffset;\r
+STATIC UINT32 mExportOffset;\r
+//\r
+// Used for RISC-V relocations.\r
+//\r
+STATIC UINT8       *mRiscVPass1Targ = NULL;\r
+STATIC Elf_Shdr    *mRiscVPass1Sym = NULL;\r
+STATIC Elf64_Half  mRiscVPass1SymSecIndex = 0;\r
+STATIC INT32       mRiscVPass1Offset;\r
+STATIC INT32       mRiscVPass1GotFixup;\r
+\r
+//\r
+// Used for Export section.\r
+//\r
+STATIC UINT32      mExportSize;\r
+STATIC UINT32      mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM];\r
+STATIC UINT32      mExportSymNum;\r
+STATIC CHAR8       mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH];\r
 \r
 //\r
 // Initialization Function\r
@@ -150,15 +178,21 @@ InitializeElf64 (
     Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
     return FALSE;\r
   }\r
-  if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64))) {\r
-    Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64 or EM_AARCH64");\r
-    return FALSE;\r
+  if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64) || (mEhdr->e_machine == EM_RISCV64) || (mEhdr->e_machine == EM_LOONGARCH))) {\r
+    Warning (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine.");\r
   }\r
   if (mEhdr->e_version != EV_CURRENT) {\r
     Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
     return FALSE;\r
   }\r
 \r
+  if (mExportFlag) {\r
+    if ((mEhdr->e_machine != EM_X86_64) && (mEhdr->e_machine != EM_AARCH64)) {\r
+      Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 and AArch64 archs.");\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
   //\r
   // Update section header pointers\r
   //\r
@@ -171,6 +205,10 @@ InitializeElf64 (
   //\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
@@ -184,6 +222,11 @@ InitializeElf64 (
   ElfFunctions->SetImageSize = SetImageSize64;\r
   ElfFunctions->CleanUp = CleanUp64;\r
 \r
+  if (mExportFlag) {\r
+    mCoffNbrSections ++;\r
+    ElfFunctions->WriteExport = WriteExport64;\r
+  }\r
+\r
   return TRUE;\r
 }\r
 \r
@@ -197,8 +240,11 @@ GetShdrByIndex (
   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
@@ -229,7 +275,8 @@ IsTextShdr (
   Elf_Shdr *Shdr\r
   )\r
 {\r
-  return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
+  return (BOOLEAN) (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) ||\r
+                   ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC));\r
 }\r
 \r
 STATIC\r
@@ -243,6 +290,17 @@ IsHiiRsrcShdr (
   return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+IsSymbolShdr (\r
+  Elf_Shdr *Shdr\r
+  )\r
+{\r
+  Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx);\r
+\r
+  return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0);\r
+}\r
+\r
 STATIC\r
 BOOLEAN\r
 IsDataShdr (\r
@@ -252,7 +310,464 @@ IsDataShdr (
   if (IsHiiRsrcShdr(Shdr)) {\r
     return FALSE;\r
   }\r
-  return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
+  return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | 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
+// Get Prm Handler number and name\r
+//\r
+STATIC\r
+VOID\r
+FindPrmHandler (\r
+  UINT64 Offset\r
+  )\r
+{\r
+  PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport;\r
+  PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT       *PrmHandler;\r
+  UINT32   HandlerNum;\r
+\r
+  PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset);\r
+  PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1);\r
+\r
+  for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) {\r
+    strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName);\r
+    mExportSymNum ++;\r
+    PrmHandler += 1;\r
+\r
+    //\r
+    // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)\r
+    //\r
+    if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) {\r
+      Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum);\r
+      exit(EXIT_FAILURE);\r
+    }\r
+  }\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
+// RISC-V 64 specific Elf WriteSection function.\r
+//\r
+STATIC\r
+VOID\r
+WriteSectionRiscV64 (\r
+  Elf_Rela  *Rel,\r
+  UINT8     *Targ,\r
+  Elf_Shdr  *SymShdr,\r
+  Elf_Sym   *Sym\r
+  )\r
+{\r
+  UINT32      Value;\r
+  UINT32      Value2;\r
+  Elf64_Addr  GOTEntryRva;\r
+\r
+  switch (ELF_R_TYPE(Rel->r_info)) {\r
+  case R_RISCV_NONE:\r
+    break;\r
+\r
+  case R_RISCV_32:\r
+    *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
+    break;\r
+\r
+  case R_RISCV_64:\r
+    *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
+    break;\r
+\r
+  case R_RISCV_HI20:\r
+    mRiscVPass1Targ = Targ;\r
+    mRiscVPass1Sym = SymShdr;\r
+    mRiscVPass1SymSecIndex = Sym->st_shndx;\r
+    break;\r
+\r
+  case R_RISCV_LO12_I:\r
+    if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
+      Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
+      Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
+      if (Value2 & (RISCV_IMM_REACH/2)) {\r
+        Value2 |= ~(RISCV_IMM_REACH-1);\r
+      }\r
+      Value += Value2;\r
+      Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
+      Value2 = RISCV_CONST_HIGH_PART (Value);\r
+      *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
+                             (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
+      *(UINT32 *)Targ = (RV_X (Value, 0, 12) << 20) | \\r
+                        (RV_X (*(UINT32 *)Targ, 0, 20));\r
+    }\r
+    mRiscVPass1Sym = NULL;\r
+    mRiscVPass1Targ = NULL;\r
+    mRiscVPass1SymSecIndex = 0;\r
+    break;\r
+\r
+  case R_RISCV_LO12_S:\r
+    if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
+      Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
+      Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5) | (RV_X(*(UINT32 *)Targ, 25, 7) << 5));\r
+      if (Value2 & (RISCV_IMM_REACH/2)) {\r
+        Value2 |= ~(RISCV_IMM_REACH-1);\r
+      }\r
+      Value += Value2;\r
+      Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
+      Value2 = RISCV_CONST_HIGH_PART (Value);\r
+      *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
+                                 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
+      Value2 = *(UINT32 *)Targ & 0x01fff07f;\r
+      Value &= RISCV_IMM_REACH - 1;\r
+      *(UINT32 *)Targ = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));\r
+    }\r
+    mRiscVPass1Sym = NULL;\r
+    mRiscVPass1Targ = NULL;\r
+    mRiscVPass1SymSecIndex = 0;\r
+    break;\r
+\r
+  case R_RISCV_GOT_HI20:\r
+    GOTEntryRva = (Sym->st_value - Rel->r_offset);\r
+    mRiscVPass1Offset = RV_X(GOTEntryRva, 0, 12);\r
+    Value = (UINT32)RV_X(GOTEntryRva, 12, 20);\r
+    *(UINT32 *)Targ = (Value << 12) | (RV_X(*(UINT32*)Targ, 0, 12));\r
+\r
+    mRiscVPass1Targ = Targ;\r
+    mRiscVPass1Sym = SymShdr;\r
+    mRiscVPass1SymSecIndex = Sym->st_shndx;\r
+    mRiscVPass1GotFixup = 1;\r
+    break;\r
+\r
+  case R_RISCV_PCREL_HI20:\r
+    mRiscVPass1Targ = Targ;\r
+    mRiscVPass1Sym = SymShdr;\r
+    mRiscVPass1SymSecIndex = Sym->st_shndx;\r
+\r
+    Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
+    break;\r
+\r
+  case R_RISCV_PCREL_LO12_S:\r
+    if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
+      int i;\r
+      Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
+\r
+      Value = ((UINT32)(RV_X(*(UINT32 *)Targ, 25, 7)) << 5);\r
+      Value = (Value | (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5)));\r
+\r
+      if(Value & (RISCV_IMM_REACH/2)) {\r
+        Value |= ~(RISCV_IMM_REACH-1);\r
+      }\r
+      Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
+\r
+      if(-2048 > (INT32)Value) {\r
+        i = (((INT32)Value * -1) / 4096);\r
+        Value2 -= i;\r
+        Value += 4096 * i;\r
+        if(-2048 > (INT32)Value) {\r
+          Value2 -= 1;\r
+          Value += 4096;\r
+        }\r
+      }\r
+      else if( 2047 < (INT32)Value) {\r
+        i = (Value / 4096);\r
+        Value2 += i;\r
+        Value -= 4096 * i;\r
+        if(2047 < (INT32)Value) {\r
+          Value2 += 1;\r
+          Value -= 4096;\r
+        }\r
+      }\r
+\r
+      // Update the IMM of SD instruction\r
+      //\r
+      // |31      25|24  20|19  15|14   12 |11      7|6     0|\r
+      // |-------------------------------------------|-------|\r
+      // |imm[11:5] | rs2  | rs1  | funct3 |imm[4:0] | opcode|\r
+      //  ---------------------------------------------------\r
+\r
+      // First Zero out current IMM\r
+      *(UINT32 *)Targ &= ~0xfe000f80;\r
+\r
+      // Update with new IMM\r
+      *(UINT32 *)Targ |= (RV_X(Value, 5, 7) << 25);\r
+      *(UINT32 *)Targ |= (RV_X(Value, 0, 5) << 7);\r
+\r
+      // Update previous instruction\r
+      *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
+    }\r
+    mRiscVPass1Sym = NULL;\r
+    mRiscVPass1Targ = NULL;\r
+    mRiscVPass1SymSecIndex = 0;\r
+    break;\r
+\r
+  case R_RISCV_PCREL_LO12_I:\r
+    if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
+      int i;\r
+      Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
+\r
+      if(mRiscVPass1GotFixup) {\r
+        Value = (UINT32)(mRiscVPass1Offset);\r
+      } else {\r
+        Value = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
+        if(Value & (RISCV_IMM_REACH/2)) {\r
+          Value |= ~(RISCV_IMM_REACH-1);\r
+        }\r
+      }\r
+      Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
+\r
+      if(-2048 > (INT32)Value) {\r
+        i = (((INT32)Value * -1) / 4096);\r
+        Value2 -= i;\r
+        Value += 4096 * i;\r
+        if(-2048 > (INT32)Value) {\r
+          Value2 -= 1;\r
+          Value += 4096;\r
+        }\r
+      }\r
+      else if( 2047 < (INT32)Value) {\r
+        i = (Value / 4096);\r
+        Value2 += i;\r
+        Value -= 4096 * i;\r
+        if(2047 < (INT32)Value) {\r
+          Value2 += 1;\r
+          Value -= 4096;\r
+        }\r
+      }\r
+\r
+      if(mRiscVPass1GotFixup) {\r
+        *(UINT32 *)Targ = (RV_X((UINT32)Value, 0, 12) << 20)\r
+                            | (RV_X(*(UINT32*)Targ, 0, 20));\r
+        // Convert LD instruction to ADDI\r
+        //\r
+        // |31      20|19  15|14  12|11   7|6       0|\r
+        // |-----------------------------------------|\r
+        // |imm[11:0] | rs1  | 011  |  rd  | 0000011 | LD\r
+        //  -----------------------------------------\r
+\r
+        // |-----------------------------------------|\r
+        // |imm[11:0] | rs1  | 000  |  rd  | 0010011 | ADDI\r
+        //  -----------------------------------------\r
+\r
+        // To convert, let's first reset bits 12-14 and 0-6 using ~0x707f\r
+        // Then modify the opcode to ADDI (0010011)\r
+        // All other fields will remain same.\r
+\r
+        *(UINT32 *)Targ = ((*(UINT32 *)Targ & ~0x707f) | 0x13);\r
+      } else {\r
+        *(UINT32 *)Targ = (RV_X(Value, 0, 12) << 20) | (RV_X(*(UINT32*)Targ, 0, 20));\r
+      }\r
+      *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
+    }\r
+    mRiscVPass1Sym = NULL;\r
+    mRiscVPass1Targ = NULL;\r
+    mRiscVPass1SymSecIndex = 0;\r
+    mRiscVPass1Offset = 0;\r
+    mRiscVPass1GotFixup = 0;\r
+    break;\r
+\r
+  case R_RISCV_ADD64:\r
+  case R_RISCV_SUB64:\r
+  case R_RISCV_ADD32:\r
+  case R_RISCV_SUB32:\r
+  case R_RISCV_BRANCH:\r
+  case R_RISCV_JAL:\r
+  case R_RISCV_GPREL_I:\r
+  case R_RISCV_GPREL_S:\r
+  case R_RISCV_CALL:\r
+  case R_RISCV_CALL_PLT:\r
+  case R_RISCV_RVC_BRANCH:\r
+  case R_RISCV_RVC_JUMP:\r
+  case R_RISCV_RELAX:\r
+  case R_RISCV_SUB6:\r
+  case R_RISCV_SET6:\r
+  case R_RISCV_SET8:\r
+  case R_RISCV_SET16:\r
+  case R_RISCV_SET32:\r
+    break;\r
+\r
+  default:\r
+    Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
+  }\r
 }\r
 \r
 //\r
@@ -271,6 +786,7 @@ ScanSections64 (
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
   BOOLEAN                         FoundSection;\r
+  UINT32                          Offset;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
@@ -282,12 +798,13 @@ ScanSections64 (
   mNtHdrOffset = mCoffOffset;\r
   switch (mEhdr->e_machine) {\r
   case EM_X86_64:\r
-  case EM_IA_64:\r
   case EM_AARCH64:\r
+  case EM_RISCV64:\r
+  case EM_LOONGARCH:\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
@@ -309,6 +826,15 @@ ScanSections64 (
     }\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
@@ -359,7 +885,7 @@ ScanSections64 (
     }\r
   }\r
 \r
-  if (!FoundSection) {\r
+  if (!FoundSection && mOutImageType != FW_ACPI_IMAGE) {\r
     Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
     assert (FALSE);\r
   }\r
@@ -368,7 +894,7 @@ ScanSections64 (
   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
+    Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
   }\r
 \r
   //\r
@@ -422,7 +948,83 @@ ScanSections64 (
   }\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
+    Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
+  }\r
+\r
+  //\r
+  //  The Symbol sections.\r
+  //\r
+  if (mExportFlag) {\r
+    UINT32      SymIndex;\r
+    Elf_Sym     *Sym;\r
+    UINT64      SymNum;\r
+    const UINT8 *SymName;\r
+\r
+    mExportOffset = mCoffOffset;\r
+    mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1;\r
+\r
+    for (i = 0; i < mEhdr->e_shnum; i++) {\r
+\r
+      //\r
+      // Determine if this is a symbol section.\r
+      //\r
+      Elf_Shdr *shdr = GetShdrByIndex(i);\r
+      if (!IsSymbolShdr(shdr)) {\r
+        continue;\r
+      }\r
+\r
+      UINT8    *Symtab = (UINT8*)mEhdr + shdr->sh_offset;\r
+      SymNum = (shdr->sh_size) / (shdr->sh_entsize);\r
+\r
+      //\r
+      // First Get PrmModuleExportDescriptor\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) {\r
+          //\r
+          // Find PrmHandler Number and Name\r
+          //\r
+          FindPrmHandler(Sym->st_value);\r
+\r
+          strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName);\r
+          mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+          mExportSymNum ++;\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Second Get PrmHandler\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        UINT32   ExpIndex;\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) {\r
+          if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) {\r
+            continue;\r
+          }\r
+          mExportRVA[ExpIndex] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+        }\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    mCoffOffset += mExportSize;\r
+    mCoffOffset = CoffAlign(mCoffOffset);\r
   }\r
 \r
   //\r
@@ -458,6 +1060,10 @@ ScanSections64 (
   // 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
@@ -476,16 +1082,21 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
     NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
     break;\r
-  case EM_IA_64:\r
-    NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;\r
-    NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
-    break;\r
   case EM_AARCH64:\r
     NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
     NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
     break;\r
+  case EM_RISCV64:\r
+    NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_RISCV64;\r
+    NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+    break;\r
+  case EM_LOONGARCH:\r
+    NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_LOONGARCH64;\r
+    NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+    break;\r
+\r
   default:\r
-    VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
+    VerboseMsg ("%u unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
     NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
     NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
   }\r
@@ -529,8 +1140,17 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  //\r
+  // If found symbol, add edata section between data and rsrc section\r
+  //\r
+  if(mExportFlag) {\r
+    Offset = mExportOffset;\r
+  } else {\r
+    Offset = mHiiRsrcOffset;\r
+  }\r
+\r
   if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
-    CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
+    CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
             | EFI_IMAGE_SCN_MEM_WRITE\r
             | EFI_IMAGE_SCN_MEM_READ);\r
@@ -539,6 +1159,20 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  if(mExportFlag) {\r
+    if ((mHiiRsrcOffset - mExportOffset) > 0) {\r
+      CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset,\r
+              EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
+              | EFI_IMAGE_SCN_MEM_READ);\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset;\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset;\r
+\r
+    } else {\r
+      // Don't make a section of size 0.\r
+      NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
+    }\r
+  }\r
+\r
   if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
     CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
@@ -563,6 +1197,7 @@ WriteSections64 (
   Elf_Shdr    *SecShdr;\r
   UINT32      SecOffset;\r
   BOOLEAN     (*Filter)(Elf_Shdr *);\r
+  Elf64_Addr  GOTEntryRva;\r
 \r
   //\r
   // Initialize filter pointer\r
@@ -590,6 +1225,9 @@ WriteSections64 (
       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
@@ -601,9 +1239,9 @@ WriteSections64 (
 \r
       default:\r
         //\r
-        //  Ignore for unkown section type.\r
+        //  Ignore for unknown section type.\r
         //\r
-        VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
+        VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type);\r
         break;\r
       }\r
     }\r
@@ -622,6 +1260,20 @@ WriteSections64 (
       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
@@ -659,14 +1311,46 @@ WriteSections64 (
         Elf_Shdr *SymShdr;\r
         UINT8    *Targ;\r
 \r
+        //\r
+        // The _GLOBAL_OFFSET_TABLE_ symbol is not actually an absolute symbol,\r
+        // but carries the SHN_ABS section index for historical reasons.\r
+        // It must be accompanied by a R_*_GOT_* type relocation on a\r
+        // subsequent instruction, which we handle below, specifically to avoid\r
+        // the GOT indirection, and to refer to the symbol directly. This means\r
+        // we can simply disregard direct references to the GOT symbol itself,\r
+        // as the resulting value will never be used.\r
+        //\r
+        if (Sym->st_shndx == SHN_ABS) {\r
+          const UINT8 *SymName = GetSymName (Sym);\r
+          if (strcmp ((CHAR8 *)SymName, "_GLOBAL_OFFSET_TABLE_") == 0) {\r
+            continue;\r
+          }\r
+        }\r
+\r
         //\r
         // Check section header index found in symbol table and get the section\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
+          //\r
+          // Skip error on EM_RISCV64 and EM_LOONGARCH because no symbol name is built\r
+          // from RISC-V and LoongArch toolchain.\r
+          //\r
+          if ((mEhdr->e_machine != EM_RISCV64) && (mEhdr->e_machine != EM_LOONGARCH)) {\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
+          continue;\r
         }\r
         SymShdr = GetShdrByIndex(Sym->st_shndx);\r
 \r
@@ -694,69 +1378,205 @@ WriteSections64 (
             // 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
-            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
-            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
+\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
-            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
+          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
           switch (ELF_R_TYPE(Rel->r_info)) {\r
+            INT64 Offset;\r
+\r
+          case R_AARCH64_LD64_GOTOFF_LO15:\r
+          case R_AARCH64_LD64_GOTPAGE_LO15:\r
+            //\r
+            // Convert into an ADR instruction that refers to the symbol directly.\r
+            //\r
+            Offset = Sym->st_value - Rel->r_offset;\r
+\r
+            *(UINT32 *)Targ &= 0x1000001f;\r
+            *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
+\r
+            if (Offset < -0x100000 || Offset > 0xfffff) {\r
+              Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s failed to relax GOT based symbol reference - image is too big (>1 MiB).",\r
+                mInImageName);\r
+              break;\r
+            }\r
+            break;\r
+\r
+          case R_AARCH64_LD64_GOT_LO12_NC:\r
+            //\r
+            // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAGE below.\r
+            //\r
+            *(UINT32 *)Targ &= 0x3ff;\r
+            *(UINT32 *)Targ |= 0x91000000 | ((Sym->st_value & 0xfff) << 10);\r
+            break;\r
+\r
+          case R_AARCH64_ADR_GOT_PAGE:\r
+            //\r
+            // This relocation points to the GOT entry that contains the absolute\r
+            // address of the symbol we are referring to. Since EDK2 only uses\r
+            // fully linked binaries, we can avoid the indirection, and simply\r
+            // refer to the symbol directly. This implies having to patch the\r
+            // subsequent LDR instruction (covered by a R_AARCH64_LD64_GOT_LO12_NC\r
+            // relocation) into an ADD instruction - this is handled above.\r
+            //\r
+            Offset = (Sym->st_value - (Rel->r_offset & ~0xfff)) >> 12;\r
+\r
+            *(UINT32 *)Targ &= 0x9000001f;\r
+            *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
+\r
+            /* fall through */\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
+            // In order to handle Cortex-A53 erratum #843419, the LD linker may\r
+            // convert ADRP instructions into ADR instructions, but without\r
+            // updating the static relocation type, and so we may end up here\r
+            // while the instruction in question is actually ADR. So let's\r
+            // just disregard it: the section offset check we apply below to\r
+            // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC\r
+            // companion instruction as well, so it is safe to omit it here.\r
+            //\r
+            if ((*(UINT32 *)Targ & BIT31) == 0) {\r
+              break;\r
+            }\r
+\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
+\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
@@ -799,6 +1619,183 @@ WriteSections64 (
           default:\r
             Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
           }\r
+        } else if (mEhdr->e_machine == EM_RISCV64) {\r
+          //\r
+          // Write section for RISC-V 64 architecture.\r
+          //\r
+          WriteSectionRiscV64 (Rel, Targ, SymShdr, Sym);\r
+        } else if (mEhdr->e_machine == EM_LOONGARCH) {\r
+          switch (ELF_R_TYPE(Rel->r_info)) {\r
+            INT64 Offset;\r
+            INT32 Lo, Hi;\r
+\r
+          case R_LARCH_SOP_PUSH_ABSOLUTE:\r
+            //\r
+            // Absolute relocation.\r
+            //\r
+            *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
+            break;\r
+\r
+          case R_LARCH_MARK_LA:\r
+          case R_LARCH_64:\r
+          case R_LARCH_NONE:\r
+          case R_LARCH_32:\r
+          case R_LARCH_RELATIVE:\r
+          case R_LARCH_COPY:\r
+          case R_LARCH_JUMP_SLOT:\r
+          case R_LARCH_TLS_DTPMOD32:\r
+          case R_LARCH_TLS_DTPMOD64:\r
+          case R_LARCH_TLS_DTPREL32:\r
+          case R_LARCH_TLS_DTPREL64:\r
+          case R_LARCH_TLS_TPREL32:\r
+          case R_LARCH_TLS_TPREL64:\r
+          case R_LARCH_IRELATIVE:\r
+          case R_LARCH_MARK_PCREL:\r
+          case R_LARCH_SOP_PUSH_PCREL:\r
+          case R_LARCH_SOP_PUSH_DUP:\r
+          case R_LARCH_SOP_PUSH_GPREL:\r
+          case R_LARCH_SOP_PUSH_TLS_TPREL:\r
+          case R_LARCH_SOP_PUSH_TLS_GOT:\r
+          case R_LARCH_SOP_PUSH_TLS_GD:\r
+          case R_LARCH_SOP_PUSH_PLT_PCREL:\r
+          case R_LARCH_SOP_ASSERT:\r
+          case R_LARCH_SOP_NOT:\r
+          case R_LARCH_SOP_SUB:\r
+          case R_LARCH_SOP_SL:\r
+          case R_LARCH_SOP_SR:\r
+          case R_LARCH_SOP_ADD:\r
+          case R_LARCH_SOP_AND:\r
+          case R_LARCH_SOP_IF_ELSE:\r
+          case R_LARCH_SOP_POP_32_S_10_5:\r
+          case R_LARCH_SOP_POP_32_U_10_12:\r
+          case R_LARCH_SOP_POP_32_S_10_12:\r
+          case R_LARCH_SOP_POP_32_S_10_16:\r
+          case R_LARCH_SOP_POP_32_S_10_16_S2:\r
+          case R_LARCH_SOP_POP_32_S_5_20:\r
+          case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:\r
+          case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:\r
+          case R_LARCH_SOP_POP_32_U:\r
+          case R_LARCH_ADD8:\r
+          case R_LARCH_ADD16:\r
+          case R_LARCH_ADD24:\r
+          case R_LARCH_ADD32:\r
+          case R_LARCH_ADD64:\r
+          case R_LARCH_SUB8:\r
+          case R_LARCH_SUB16:\r
+          case R_LARCH_SUB24:\r
+          case R_LARCH_SUB32:\r
+          case R_LARCH_SUB64:\r
+          case R_LARCH_GNU_VTINHERIT:\r
+          case R_LARCH_GNU_VTENTRY:\r
+          case R_LARCH_B16:\r
+          case R_LARCH_B21:\r
+          case R_LARCH_B26:\r
+          case R_LARCH_ABS_HI20:\r
+          case R_LARCH_ABS_LO12:\r
+          case R_LARCH_ABS64_LO20:\r
+          case R_LARCH_ABS64_HI12:\r
+          case R_LARCH_PCALA_LO12:\r
+          case R_LARCH_PCALA64_LO20:\r
+          case R_LARCH_PCALA64_HI12:\r
+          case R_LARCH_GOT_PC_LO12:\r
+          case R_LARCH_GOT64_PC_LO20:\r
+          case R_LARCH_GOT64_PC_HI12:\r
+          case R_LARCH_GOT64_HI20:\r
+          case R_LARCH_GOT64_LO12:\r
+          case R_LARCH_GOT64_LO20:\r
+          case R_LARCH_GOT64_HI12:\r
+          case R_LARCH_TLS_LE_HI20:\r
+          case R_LARCH_TLS_LE_LO12:\r
+          case R_LARCH_TLS_LE64_LO20:\r
+          case R_LARCH_TLS_LE64_HI12:\r
+          case R_LARCH_TLS_IE_PC_HI20:\r
+          case R_LARCH_TLS_IE_PC_LO12:\r
+          case R_LARCH_TLS_IE64_PC_LO20:\r
+          case R_LARCH_TLS_IE64_PC_HI12:\r
+          case R_LARCH_TLS_IE64_HI20:\r
+          case R_LARCH_TLS_IE64_LO12:\r
+          case R_LARCH_TLS_IE64_LO20:\r
+          case R_LARCH_TLS_IE64_HI12:\r
+          case R_LARCH_TLS_LD_PC_HI20:\r
+          case R_LARCH_TLS_LD64_HI20:\r
+          case R_LARCH_TLS_GD_PC_HI20:\r
+          case R_LARCH_TLS_GD64_HI20:\r
+          case R_LARCH_RELAX:\r
+            //\r
+            // These types are not used or do not require fixup.\r
+            //\r
+            break;\r
+\r
+          case R_LARCH_GOT_PC_HI20:\r
+            Offset = Sym->st_value - (UINTN)(Targ - mCoffFile);\r
+            if (Offset < 0) {\r
+              Offset = (UINTN)(Targ - mCoffFile) - Sym->st_value;\r
+              Hi = Offset & ~0xfff;\r
+              Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
+              if ((Lo < 0) && (Lo > -2048)) {\r
+                Hi += 0x1000;\r
+                Lo = ~(0x1000 - Lo) + 1;\r
+              }\r
+              Hi = ~Hi + 1;\r
+              Lo = ~Lo + 1;\r
+            } else {\r
+              Hi = Offset & ~0xfff;\r
+              Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
+              if (Lo < 0) {\r
+                Hi += 0x1000;\r
+                Lo = ~(0x1000 - Lo) + 1;\r
+              }\r
+            }\r
+            // Re-encode the offset as PCADDU12I + ADDI.D(Convert LD.D) instruction\r
+            *(UINT32 *)Targ &= 0x1f;\r
+            *(UINT32 *)Targ |= 0x1c000000;\r
+            *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5);\r
+            *(UINT32 *)(Targ + 4) &= 0x3ff;\r
+            *(UINT32 *)(Targ + 4) |= 0x2c00000 | ((Lo & 0xfff) << 10);\r
+            break;\r
+\r
+          //\r
+          // Attempt to convert instruction.\r
+          //\r
+          case R_LARCH_PCALA_HI20:\r
+            // Decode the PCALAU12I instruction and the instruction that following it.\r
+            Offset = ((INT32)((*(UINT32 *)Targ & 0x1ffffe0) << 7));\r
+            Offset += ((INT32)((*(UINT32 *)(Targ + 4) & 0x3ffc00) << 10) >> 20);\r
+            //\r
+            // PCALA offset is relative to the previous page boundary,\r
+            // whereas PCADD 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
+            if (Offset < 0) {\r
+              Offset = -Offset;\r
+              Hi = Offset & ~0xfff;\r
+              Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
+              if ((Lo < 0) && (Lo > -2048)) {\r
+                Hi += 0x1000;\r
+                Lo = ~(0x1000 - Lo) + 1;\r
+              }\r
+              Hi = ~Hi + 1;\r
+              Lo = ~Lo + 1;\r
+            } else {\r
+              Hi = Offset & ~0xfff;\r
+              Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
+              if (Lo < 0) {\r
+                Hi += 0x1000;\r
+                Lo = ~(0x1000 - Lo) + 1;\r
+              }\r
+            }\r
+            // Convert the first instruction from PCALAU12I to PCADDU12I and re-encode the offset into them.\r
+            *(UINT32 *)Targ &= 0x1f;\r
+            *(UINT32 *)Targ |= 0x1c000000;\r
+            *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5);\r
+            *(UINT32 *)(Targ + 4) &= 0xffc003ff;\r
+            *(UINT32 *)(Targ + 4) |= (Lo & 0xfff) << 10;\r
+            break;\r
+          default:\r
+            Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info));\r
+          }\r
         } else {\r
           Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
         }\r
@@ -818,6 +1815,7 @@ WriteRelocations64 (
   UINT32                           Index;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION  *NtHdr;\r
   EFI_IMAGE_DATA_DIRECTORY         *Dir;\r
+  UINT32 RiscVRelType;\r
 \r
   for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
     Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
@@ -833,18 +1831,43 @@ WriteRelocations64 (
             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
-              VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
+              VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08llX",\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
                 + (Rel->r_offset - SecShdr->sh_addr)),\r
                 EFI_IMAGE_REL_BASED_DIR64);\r
               break;\r
-            case R_X86_64_32S:\r
+            //\r
+            // R_X86_64_32 and R_X86_64_32S are ELF64 relocations emitted when using\r
+            //   the SYSV X64 ABI small non-position-independent code model.\r
+            //   R_X86_64_32 is used for unsigned 32-bit immediates with a 32-bit operand\r
+            //   size.  The value is either not extended, or zero-extended to 64 bits.\r
+            //   R_X86_64_32S is used for either signed 32-bit non-rip-relative displacements\r
+            //   or signed 32-bit immediates with a 64-bit operand size.  The value is\r
+            //   sign-extended to 64 bits.\r
+            //   EFI_IMAGE_REL_BASED_HIGHLOW is a PE relocation that uses 32-bit arithmetic\r
+            //   for rebasing an image.\r
+            //   EFI PE binaries declare themselves EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE and\r
+            //   may load above 2GB.  If an EFI PE binary with a converted R_X86_64_32S\r
+            //   relocation is loaded above 2GB, the value will get sign-extended to the\r
+            //   negative part of the 64-bit address space.  The negative part of the 64-bit\r
+            //   address space is unmapped, so accessing such an address page-faults.\r
+            //   In order to support R_X86_64_32S, it is necessary to unset\r
+            //   EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE, and the EFI PE loader must implement\r
+            //   this flag and abstain from loading such a PE binary above 2GB.\r
+            //   Since this feature is not supported, support for R_X86_64_32S (and hence\r
+            //   the small non-position-independent code model) is disabled.\r
+            //\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%08llX",\r
                 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
               CoffAddFixup(\r
                 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
@@ -872,6 +1895,10 @@ WriteRelocations64 (
             case R_AARCH64_LDST32_ABS_LO12_NC:\r
             case R_AARCH64_LDST64_ABS_LO12_NC:\r
             case R_AARCH64_LDST128_ABS_LO12_NC:\r
+            case R_AARCH64_ADR_GOT_PAGE:\r
+            case R_AARCH64_LD64_GOT_LO12_NC:\r
+            case R_AARCH64_LD64_GOTOFF_LO15:\r
+            case R_AARCH64_LD64_GOTPAGE_LO15:\r
               //\r
               // No fixups are required for relative relocations, provided that\r
               // the relative offsets between sections have been preserved in\r
@@ -897,14 +1924,247 @@ WriteRelocations64 (
             default:\r
                 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
             }\r
+          } else if (mEhdr->e_machine == EM_RISCV64) {\r
+            RiscVRelType = ELF_R_TYPE(Rel->r_info);\r
+            switch (RiscVRelType) {\r
+            case R_RISCV_NONE:\r
+              break;\r
+\r
+            case R_RISCV_32:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_HIGHLOW);\r
+              break;\r
+\r
+            case R_RISCV_64:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_DIR64);\r
+              break;\r
+\r
+            case R_RISCV_HI20:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_RISCV_HI20);\r
+              break;\r
+\r
+            case R_RISCV_LO12_I:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_RISCV_LOW12I);\r
+              break;\r
+\r
+            case R_RISCV_LO12_S:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_RISCV_LOW12S);\r
+              break;\r
+\r
+            case R_RISCV_ADD64:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_SUB64:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_ADD32:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_SUB32:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_BRANCH:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_JAL:\r
+              CoffAddFixup(\r
+                (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                + (Rel->r_offset - SecShdr->sh_addr)),\r
+                EFI_IMAGE_REL_BASED_ABSOLUTE);\r
+              break;\r
+\r
+            case R_RISCV_GPREL_I:\r
+            case R_RISCV_GPREL_S:\r
+            case R_RISCV_CALL:\r
+            case R_RISCV_CALL_PLT:\r
+            case R_RISCV_RVC_BRANCH:\r
+            case R_RISCV_RVC_JUMP:\r
+            case R_RISCV_RELAX:\r
+            case R_RISCV_SUB6:\r
+            case R_RISCV_SET6:\r
+            case R_RISCV_SET8:\r
+            case R_RISCV_SET16:\r
+            case R_RISCV_SET32:\r
+            case R_RISCV_PCREL_HI20:\r
+            case R_RISCV_GOT_HI20:\r
+            case R_RISCV_PCREL_LO12_I:\r
+            case R_RISCV_PCREL_LO12_S:\r
+              break;\r
+\r
+            default:\r
+              Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
+            }\r
+          } else if (mEhdr->e_machine == EM_LOONGARCH) {\r
+            switch (ELF_R_TYPE(Rel->r_info)) {\r
+              case R_LARCH_MARK_LA:\r
+                CoffAddFixup(\r
+                  (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                  + (Rel->r_offset - SecShdr->sh_addr)),\r
+                  EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA);\r
+                break;\r
+              case R_LARCH_64:\r
+                CoffAddFixup(\r
+                  (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
+                  + (Rel->r_offset - SecShdr->sh_addr)),\r
+                  EFI_IMAGE_REL_BASED_DIR64);\r
+                break;\r
+              case R_LARCH_NONE:\r
+              case R_LARCH_32:\r
+              case R_LARCH_RELATIVE:\r
+              case R_LARCH_COPY:\r
+              case R_LARCH_JUMP_SLOT:\r
+              case R_LARCH_TLS_DTPMOD32:\r
+              case R_LARCH_TLS_DTPMOD64:\r
+              case R_LARCH_TLS_DTPREL32:\r
+              case R_LARCH_TLS_DTPREL64:\r
+              case R_LARCH_TLS_TPREL32:\r
+              case R_LARCH_TLS_TPREL64:\r
+              case R_LARCH_IRELATIVE:\r
+              case R_LARCH_MARK_PCREL:\r
+              case R_LARCH_SOP_PUSH_PCREL:\r
+              case R_LARCH_SOP_PUSH_ABSOLUTE:\r
+              case R_LARCH_SOP_PUSH_DUP:\r
+              case R_LARCH_SOP_PUSH_GPREL:\r
+              case R_LARCH_SOP_PUSH_TLS_TPREL:\r
+              case R_LARCH_SOP_PUSH_TLS_GOT:\r
+              case R_LARCH_SOP_PUSH_TLS_GD:\r
+              case R_LARCH_SOP_PUSH_PLT_PCREL:\r
+              case R_LARCH_SOP_ASSERT:\r
+              case R_LARCH_SOP_NOT:\r
+              case R_LARCH_SOP_SUB:\r
+              case R_LARCH_SOP_SL:\r
+              case R_LARCH_SOP_SR:\r
+              case R_LARCH_SOP_ADD:\r
+              case R_LARCH_SOP_AND:\r
+              case R_LARCH_SOP_IF_ELSE:\r
+              case R_LARCH_SOP_POP_32_S_10_5:\r
+              case R_LARCH_SOP_POP_32_U_10_12:\r
+              case R_LARCH_SOP_POP_32_S_10_12:\r
+              case R_LARCH_SOP_POP_32_S_10_16:\r
+              case R_LARCH_SOP_POP_32_S_10_16_S2:\r
+              case R_LARCH_SOP_POP_32_S_5_20:\r
+              case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:\r
+              case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:\r
+              case R_LARCH_SOP_POP_32_U:\r
+              case R_LARCH_ADD8:\r
+              case R_LARCH_ADD16:\r
+              case R_LARCH_ADD24:\r
+              case R_LARCH_ADD32:\r
+              case R_LARCH_ADD64:\r
+              case R_LARCH_SUB8:\r
+              case R_LARCH_SUB16:\r
+              case R_LARCH_SUB24:\r
+              case R_LARCH_SUB32:\r
+              case R_LARCH_SUB64:\r
+              case R_LARCH_GNU_VTINHERIT:\r
+              case R_LARCH_GNU_VTENTRY:\r
+              case R_LARCH_B16:\r
+              case R_LARCH_B21:\r
+              case R_LARCH_B26:\r
+              case R_LARCH_ABS_HI20:\r
+              case R_LARCH_ABS_LO12:\r
+              case R_LARCH_ABS64_LO20:\r
+              case R_LARCH_ABS64_HI12:\r
+              case R_LARCH_PCALA_HI20:\r
+              case R_LARCH_PCALA_LO12:\r
+              case R_LARCH_PCALA64_LO20:\r
+              case R_LARCH_PCALA64_HI12:\r
+              case R_LARCH_GOT_PC_HI20:\r
+              case R_LARCH_GOT_PC_LO12:\r
+              case R_LARCH_GOT64_PC_LO20:\r
+              case R_LARCH_GOT64_PC_HI12:\r
+              case R_LARCH_GOT64_HI20:\r
+              case R_LARCH_GOT64_LO12:\r
+              case R_LARCH_GOT64_LO20:\r
+              case R_LARCH_GOT64_HI12:\r
+              case R_LARCH_TLS_LE_HI20:\r
+              case R_LARCH_TLS_LE_LO12:\r
+              case R_LARCH_TLS_LE64_LO20:\r
+              case R_LARCH_TLS_LE64_HI12:\r
+              case R_LARCH_TLS_IE_PC_HI20:\r
+              case R_LARCH_TLS_IE_PC_LO12:\r
+              case R_LARCH_TLS_IE64_PC_LO20:\r
+              case R_LARCH_TLS_IE64_PC_HI12:\r
+              case R_LARCH_TLS_IE64_HI20:\r
+              case R_LARCH_TLS_IE64_LO12:\r
+              case R_LARCH_TLS_IE64_LO20:\r
+              case R_LARCH_TLS_IE64_HI12:\r
+              case R_LARCH_TLS_LD_PC_HI20:\r
+              case R_LARCH_TLS_LD64_HI20:\r
+              case R_LARCH_TLS_GD_PC_HI20:\r
+              case R_LARCH_TLS_GD64_HI20:\r
+              case R_LARCH_RELAX:\r
+                //\r
+                // These types are not used or do not require fixup in PE format files.\r
+                //\r
+                break;\r
+              default:\r
+                  Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info));\r
+            }\r
           } else {\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
+  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
@@ -956,7 +2216,7 @@ WriteDebug64 (
   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
   DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
   DataDir->VirtualAddress = mDebugOffset;\r
-  DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+  DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
 }\r
 \r
 STATIC\r
@@ -985,4 +2245,72 @@ CleanUp64 (
   }\r
 }\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  )\r
+{\r
+  EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
+  EFI_IMAGE_EXPORT_DIRECTORY          *ExportDir;\r
+  EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
+  UINT32                              FileNameOffset;\r
+  UINT32                              NameOffset;\r
+  UINT16                              Index;\r
+  UINT8                               *Tdata = NULL;\r
+\r
+  ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset);\r
+  ExportDir->Characteristics = 0;\r
+  ExportDir->TimeDateStamp = 0;\r
+  ExportDir->MajorVersion = 0;\r
+  ExportDir->MinorVersion =0;\r
+  ExportDir->Name = 0;\r
+  ExportDir->NumberOfFunctions = mExportSymNum;\r
+  ExportDir->NumberOfNames = mExportSymNum;\r
+  ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE;\r
+  ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY);\r
+  ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+  ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+\r
+  FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum;\r
+  NameOffset = FileNameOffset + strlen(mInImageName) + 1;\r
+\r
+  // Write Input image Name RVA\r
+  ExportDir->Name = FileNameOffset;\r
+\r
+  // Write Input image Name\r
+  strcpy((char *)(mCoffFile + FileNameOffset), mInImageName);\r
+\r
+  for (Index = 0; Index < mExportSymNum; Index++) {\r
+    //\r
+    // Write Export Address Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = mExportRVA[Index];\r
+\r
+    //\r
+    // Write Export Name Pointer Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = NameOffset;\r
+\r
+    //\r
+    // Write Export Ordinal table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE;\r
+    *(UINT16 *)Tdata = Index;\r
+\r
+    //\r
+    // Write Export Name Table\r
+    //\r
+    strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]);\r
+    NameOffset += strlen(mExportSymName[Index]) + 1;\r
+  }\r
+\r
+  NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
+  DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT];\r
+  DataDir->VirtualAddress = mExportOffset;\r
+  DataDir->Size = mExportSize;\r
+\r
+}\r
 \r