]> 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 0bb3ead228c9066ec2af015e5b6f391c72c155bf..8b50774beb1eebda24d00cea9014d9ec6749cb36 100644 (file)
@@ -2,8 +2,9 @@
 Elf64 convert solution\r
 \r
 Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>\r
-Portions copyright (c) 2013-2014, ARM Ltd. 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
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -56,6 +57,12 @@ WriteDebug64 (
   VOID\r
   );\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  );\r
+\r
 STATIC\r
 VOID\r
 SetImageSize64 (\r
@@ -106,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
@@ -122,7 +129,7 @@ STATIC UINT32 mDataOffset;
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
 STATIC UINT32 mDebugOffset;\r
-\r
+STATIC UINT32 mExportOffset;\r
 //\r
 // Used for RISC-V relocations.\r
 //\r
@@ -132,6 +139,14 @@ STATIC Elf64_Half  mRiscVPass1SymSecIndex = 0;
 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
 //\r
@@ -163,7 +178,7 @@ 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) || (mEhdr->e_machine == EM_RISCV64))) {\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
@@ -171,6 +186,13 @@ InitializeElf64 (
     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
@@ -200,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
@@ -263,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
@@ -335,6 +373,37 @@ GetSymName (
   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
@@ -717,6 +786,7 @@ ScanSections64 (
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
   BOOLEAN                         FoundSection;\r
+  UINT32                          Offset;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
@@ -730,6 +800,7 @@ ScanSections64 (
   case EM_X86_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
@@ -880,6 +951,82 @@ ScanSections64 (
     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
   //  The HII resource sections.\r
   //\r
@@ -943,9 +1090,13 @@ ScanSections64 (
     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
@@ -989,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
@@ -999,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
@@ -1137,6 +1311,22 @@ 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
@@ -1149,10 +1339,10 @@ WriteSections64 (
           }\r
 \r
           //\r
-          // Skip error on EM_RISCV64 becasue no symble name is built\r
-          // from RISC-V toolchain.\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) {\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
@@ -1280,6 +1470,23 @@ WriteSections64 (
           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
@@ -1417,6 +1624,178 @@ WriteSections64 (
           // 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
@@ -1458,7 +1837,7 @@ WriteRelocations64 (
             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
@@ -1488,7 +1867,7 @@ WriteRelocations64 (
             //\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
@@ -1518,6 +1897,8 @@ WriteRelocations64 (
             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
@@ -1647,6 +2028,113 @@ WriteRelocations64 (
             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
@@ -1757,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