From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by mx.groups.io with SMTP id smtpd.web12.7104.1661091422999018997 for ; Sun, 21 Aug 2022 07:17:03 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=rkWKOpKT; spf=pass (domain: kernel.org, ip: 139.178.84.217, mailfrom: ardb@kernel.org) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 326A060A67; Sun, 21 Aug 2022 14:17:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id EE598C433D6; Sun, 21 Aug 2022 14:16:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1661091421; bh=/qarzs5Ubpk6IbtJdv0I2as9W5BCvpw7tO1SHVIuyGo=; h=From:To:Cc:Subject:Date:From; b=rkWKOpKTKrh33Y/LYWccmzCTGVdX1LFBqwRnfcj5a37zUSK/KdJK4vSEsn+WAt5Li 4oaY+nN6ffXwtRAjUY5v4vY/1hiovtqeGexVFeYDev/qbKawfejGGSk0u4Atsemb9i +0KKWs4a0wgrzIm9+84JU6cRE78awCkBPzC8ofzeIYIm/c9FLnSK9W7Xhxspeazxpb aIegJVb0/05EJ9pOxYK6fJxWik2g+IROURHWWRyDG3QD3bsoGvjVE22PA4k/JUp7mV 8Q+/s/0US25pTiH7c6mImwD+m/ECqB1QYcQ6Wd1WX5rpL07l6Cwj+188qQGYYzArFw fnAdmQqckDk2w== From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: Ard Biesheuvel , Rebecca Cran , Bob Feng , Liming Gao , "Kinney, Michael D" , Leif Lindholm Subject: [PATCH] BaseTools/GenFw AARCH64: Convert more types of explicit GOT references Date: Sun, 21 Aug 2022 16:16:37 +0200 Message-Id: <20220821141637.2531871-1-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Rebecca reports that builds of AArch64 DSCs that involve PIE linking=0D when using ELF based toolchains are failing in some cases, resulting in=0D an error message like=0D =0D bad definition for symbol '_GLOBAL_OFFSET_TABLE_'@0x72d8 or=0D unsupported symbol type. For example, absolute and undefined symbols=0D are not supported.=0D =0D The reason turns out to be that, while GenFw does carry some logic to=0D convert GOT based symbol references into direct ones (which is always=0D possible given that our ELF to PE/COFF conversion only supports fully=0D linked executables), it does not support all possible combinations of=0D relocations that the linker may emit to load symbol addresses from the=0D GOT.=0D =0D In particular, when performing a non-LTO link on object code built with=0D GCC using -fpie, we may end up with GOT based references such as the one=0D below, where the address of the GOT itself is taken, and the ofset of=0D the symbol in the GOT is reflected in the immediate offset of the=0D subsequent LDR instruction.=0D =0D 838: adrp x0, 16000=0D 838: R_AARCH64_ADR_PREL_PG_HI21 _GLOBAL_OFFSET_TABLE_=0D 83c: ldr x0, [x0, #2536]=0D 83c: R_AARCH64_LD64_GOTPAGE_LO15 _gPcd_BinaryPatch_PcdFdBaseAddres= s=0D =0D The reason that we omit GOT based symbol references when performing ELF to= =0D PE/COFF conversion is that the GOT is not described by static ELF=0D relocations, which means that the ELF file lacks the metadata to=0D generate the PE/COFF relocations covering the GOT table in the PE/COFF=0D executable. Given that none of the usual motivations for using a GOT=0D (copy on write footprint, shared libraries) apply to EFI executables in=0D the first place, the easiest way around this is to convert all GOT based=0D symbol address loads to PC relative ADR/ADRP instructions.=0D =0D So implement this handling for R_AARCH64_LD64_GOTPAGE_LO15 and=0D R_AARCH64_LD64_GOTOFF_LO15 relocations as well, and turn the LDR=0D instructions in question into ADR instructions that generate the=0D address immediately.=0D =0D This leaves the reference to _GLOBAL_OFFSET_TABLE_ itself, which is what=0D generated the error to begin with. Considering that this symbol is never=0D referenced (i.e., it doesn't appear anywhere in the code) and is only=0D meaningful in combination with R_*_GOT_* based relocations that follow=0D it, we can just disregard any references to it entirely, given that we=0D convert all of those followup relocations into direct references.=0D =0D Cc: Rebecca Cran =0D Cc: Bob Feng =0D Cc: Liming Gao =0D Cc: "Kinney, Michael D" =0D Cc: Leif Lindholm =0D Signed-off-by: Ard Biesheuvel =0D ---=0D =0D This patch can be tested using the following method:=0D =0D - add the following lines to ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatabl= e.inf=0D =0D [BuildOptions]=0D GCC:*_*_AARCH64_CC_FLAGS =3D -fpie=0D GCC:*_*_AARCH64_DLINK_FLAGS =3D -Wl,-Bsymbolic,-pie=0D =0D - build ArmVirtPkg/ArmVirtQemuKernel.dsc in DEBUG mode using GCC49=0D (other combos might work as well) and observe the build failure=0D =0D - apply this patch and observe that the build failure is gone=0D =0D - boot the resulting image in QEMU using the -kernel ../QEMU_EFI.fd=0D command line option and observe that the image boots as usual=0D =0D BaseTools/Source/C/GenFw/Elf64Convert.c | 35 ++++++++++++++++++++=0D 1 file changed, 35 insertions(+)=0D =0D diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/G= enFw/Elf64Convert.c=0D index 35e96dd05bc2..3173ca9280f4 100644=0D --- a/BaseTools/Source/C/GenFw/Elf64Convert.c=0D +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c=0D @@ -1305,6 +1305,22 @@ WriteSections64 (=0D Elf_Shdr *SymShdr;=0D UINT8 *Targ;=0D =0D + //=0D + // The _GLOBAL_OFFSET_TABLE_ symbol is not actually an absolute sy= mbol,=0D + // but carries the SHN_ABS section index for historical reasons.=0D + // It must be accompanied by a R_*_GOT_* type relocation on a=0D + // subsequent instruction, which we handle below, specifically to = avoid=0D + // the GOT indirection, and to refer to the symbol directly. This = means=0D + // we can simply disregard direct references to the GOT symbol its= elf,=0D + // as the resulting value will never be used.=0D + //=0D + if (Sym->st_shndx =3D=3D SHN_ABS) {=0D + const UINT8 *SymName =3D GetSymName (Sym);=0D + if (strcmp ((CHAR8 *)SymName, "_GLOBAL_OFFSET_TABLE_") =3D=3D 0)= {=0D + continue;=0D + }=0D + }=0D +=0D //=0D // Check section header index found in symbol table and get the se= ction=0D // header location.=0D @@ -1448,6 +1464,23 @@ WriteSections64 (=0D switch (ELF_R_TYPE(Rel->r_info)) {=0D INT64 Offset;=0D =0D + case R_AARCH64_LD64_GOTOFF_LO15:=0D + case R_AARCH64_LD64_GOTPAGE_LO15:=0D + //=0D + // Convert into an ADR instruction that refers to the symbol d= irectly.=0D + //=0D + Offset =3D Sym->st_value - Rel->r_offset;=0D +=0D + *(UINT32 *)Targ &=3D 0x1000001f;=0D + *(UINT32 *)Targ |=3D ((Offset & 0x1ffffc) << (5 - 2)) | ((Offs= et & 0x3) << 29);=0D +=0D + if (Offset < -0x100000 || Offset > 0xfffff) {=0D + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s fail= ed to relax GOT based symbol reference - image is too big (>1 MiB).",=0D + mInImageName);=0D + break;=0D + }=0D + break;=0D +=0D case R_AARCH64_LD64_GOT_LO12_NC:=0D //=0D // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAG= E below.=0D @@ -1686,6 +1719,8 @@ WriteRelocations64 (=0D case R_AARCH64_LDST128_ABS_LO12_NC:=0D case R_AARCH64_ADR_GOT_PAGE:=0D case R_AARCH64_LD64_GOT_LO12_NC:=0D + case R_AARCH64_LD64_GOTOFF_LO15:=0D + case R_AARCH64_LD64_GOTPAGE_LO15:=0D //=0D // No fixups are required for relative relocations, provided= that=0D // the relative offsets between sections have been preserved= in=0D -- =0D 2.35.1=0D =0D