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
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
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
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
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
\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
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
// 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
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
//\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
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
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