Acked-by: Bob Feng <bob.c.f...@intel.com> -----Original Message----- From: Leif Lindholm <quic_llind...@quicinc.com> Sent: Tuesday, September 6, 2022 7:54 PM To: Ard Biesheuvel <a...@kernel.org>; Rebecca Cran <rebe...@bsdio.com> Cc: devel@edk2.groups.io; Feng, Bob C <bob.c.f...@intel.com>; Gao, Liming <gaolim...@byosoft.com.cn>; Kinney, Michael D <michael.d.kin...@intel.com> Subject: Re: [edk2-devel] [PATCH] BaseTools/GenFw AARCH64: Convert more types of explicit GOT references
On 2022-09-06 11:30, Ard Biesheuvel wrote: > Bob, Liming, Leif: any thoughts? I'm happy with this. (Spotted one typo - "ofset".) Acked-by: Leif Lindholm <quic_llind...@quicinc.com> > On Sun, 21 Aug 2022 at 16:33, Rebecca Cran <rebe...@bsdio.com> wrote: >> >> Tested-by: Rebecca Cran <rebe...@bsdio.com> >> >> >> On 8/21/22 08:16, Ard Biesheuvel wrote: >>> Rebecca reports that builds of AArch64 DSCs that involve PIE linking >>> when using ELF based toolchains are failing in some cases, resulting >>> in an error message like >>> >>> bad definition for symbol '_GLOBAL_OFFSET_TABLE_'@0x72d8 or >>> unsupported symbol type. For example, absolute and undefined symbols >>> are not supported. >>> >>> The reason turns out to be that, while GenFw does carry some logic >>> to convert GOT based symbol references into direct ones (which is >>> always possible given that our ELF to PE/COFF conversion only >>> supports fully linked executables), it does not support all possible >>> combinations of relocations that the linker may emit to load symbol >>> addresses from the GOT. >>> >>> In particular, when performing a non-LTO link on object code built >>> with GCC using -fpie, we may end up with GOT based references such >>> as the one below, where the address of the GOT itself is taken, and >>> the ofset of the symbol in the GOT is reflected in the immediate >>> offset of the subsequent LDR instruction. >>> >>> 838: adrp x0, 16000 >>> 838: R_AARCH64_ADR_PREL_PG_HI21 _GLOBAL_OFFSET_TABLE_ >>> 83c: ldr x0, [x0, #2536] >>> 83c: R_AARCH64_LD64_GOTPAGE_LO15 >>> _gPcd_BinaryPatch_PcdFdBaseAddress >>> >>> The reason that we omit GOT based symbol references when performing >>> ELF to PE/COFF conversion is that the GOT is not described by static >>> ELF relocations, which means that the ELF file lacks the metadata to >>> generate the PE/COFF relocations covering the GOT table in the >>> PE/COFF executable. Given that none of the usual motivations for >>> using a GOT (copy on write footprint, shared libraries) apply to EFI >>> executables in the first place, the easiest way around this is to >>> convert all GOT based symbol address loads to PC relative ADR/ADRP >>> instructions. >>> >>> So implement this handling for R_AARCH64_LD64_GOTPAGE_LO15 and >>> R_AARCH64_LD64_GOTOFF_LO15 relocations as well, and turn the LDR >>> instructions in question into ADR instructions that generate the >>> address immediately. >>> >>> This leaves the reference to _GLOBAL_OFFSET_TABLE_ itself, which is >>> what generated the error to begin with. Considering that this symbol >>> is never referenced (i.e., it doesn't appear anywhere in the code) >>> and is only meaningful in combination with R_*_GOT_* based >>> relocations that follow it, we can just disregard any references to >>> it entirely, given that we convert all of those followup relocations into >>> direct references. >>> >>> Cc: Rebecca Cran <rebe...@bsdio.com> >>> Cc: Bob Feng <bob.c.f...@intel.com> >>> Cc: Liming Gao <gaolim...@byosoft.com.cn> >>> Cc: "Kinney, Michael D" <michael.d.kin...@intel.com> >>> Cc: Leif Lindholm <quic_llind...@quicinc.com> >>> Signed-off-by: Ard Biesheuvel <a...@kernel.org> >>> --- >>> >>> This patch can be tested using the following method: >>> >>> - add the following lines to >>> ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf >>> >>> [BuildOptions] >>> GCC:*_*_AARCH64_CC_FLAGS = -fpie >>> GCC:*_*_AARCH64_DLINK_FLAGS = -Wl,-Bsymbolic,-pie >>> >>> - build ArmVirtPkg/ArmVirtQemuKernel.dsc in DEBUG mode using GCC49 >>> (other combos might work as well) and observe the build failure >>> >>> - apply this patch and observe that the build failure is gone >>> >>> - boot the resulting image in QEMU using the -kernel ../QEMU_EFI.fd >>> command line option and observe that the image boots as usual >>> >>> BaseTools/Source/C/GenFw/Elf64Convert.c | 35 ++++++++++++++++++++ >>> 1 file changed, 35 insertions(+) >>> >>> diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c >>> b/BaseTools/Source/C/GenFw/Elf64Convert.c >>> index 35e96dd05bc2..3173ca9280f4 100644 >>> --- a/BaseTools/Source/C/GenFw/Elf64Convert.c >>> +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c >>> @@ -1305,6 +1305,22 @@ WriteSections64 ( >>> Elf_Shdr *SymShdr; >>> UINT8 *Targ; >>> >>> + // >>> + // The _GLOBAL_OFFSET_TABLE_ symbol is not actually an absolute >>> symbol, >>> + // but carries the SHN_ABS section index for historical reasons. >>> + // It must be accompanied by a R_*_GOT_* type relocation on a >>> + // subsequent instruction, which we handle below, specifically to >>> avoid >>> + // the GOT indirection, and to refer to the symbol directly. This >>> means >>> + // we can simply disregard direct references to the GOT symbol >>> itself, >>> + // as the resulting value will never be used. >>> + // >>> + if (Sym->st_shndx == SHN_ABS) { >>> + const UINT8 *SymName = GetSymName (Sym); >>> + if (strcmp ((CHAR8 *)SymName, "_GLOBAL_OFFSET_TABLE_") == 0) { >>> + continue; >>> + } >>> + } >>> + >>> // >>> // Check section header index found in symbol table and get the >>> section >>> // header location. >>> @@ -1448,6 +1464,23 @@ WriteSections64 ( >>> switch (ELF_R_TYPE(Rel->r_info)) { >>> INT64 Offset; >>> >>> + case R_AARCH64_LD64_GOTOFF_LO15: >>> + case R_AARCH64_LD64_GOTPAGE_LO15: >>> + // >>> + // Convert into an ADR instruction that refers to the symbol >>> directly. >>> + // >>> + Offset = Sym->st_value - Rel->r_offset; >>> + >>> + *(UINT32 *)Targ &= 0x1000001f; >>> + *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | >>> + ((Offset & 0x3) << 29); >>> + >>> + if (Offset < -0x100000 || Offset > 0xfffff) { >>> + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s >>> failed to relax GOT based symbol reference - image is too big (>1 MiB).", >>> + mInImageName); >>> + break; >>> + } >>> + break; >>> + >>> case R_AARCH64_LD64_GOT_LO12_NC: >>> // >>> // Convert into an ADD instruction - see >>> R_AARCH64_ADR_GOT_PAGE below. >>> @@ -1686,6 +1719,8 @@ WriteRelocations64 ( >>> case R_AARCH64_LDST128_ABS_LO12_NC: >>> case R_AARCH64_ADR_GOT_PAGE: >>> case R_AARCH64_LD64_GOT_LO12_NC: >>> + case R_AARCH64_LD64_GOTOFF_LO15: >>> + case R_AARCH64_LD64_GOTPAGE_LO15: >>> // >>> // No fixups are required for relative relocations, >>> provided that >>> // the relative offsets between sections have been >>> preserved in -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#93418): https://edk2.groups.io/g/devel/message/93418 Mute This Topic: https://groups.io/mt/93162057/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-