]> 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 35e96dd05bc26f7212d0f80af1ecb998bcb993dd..8b50774beb1eebda24d00cea9014d9ec6749cb36 100644 (file)
@@ -4,6 +4,7 @@ Elf64 convert solution
 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
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -177,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
@@ -799,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
@@ -1088,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
@@ -1305,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
@@ -1317,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
@@ -1448,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
@@ -1585,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
@@ -1626,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
@@ -1656,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
@@ -1686,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
@@ -1815,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