From: "Leif Lindholm" <quic_llindhol@quicinc.com>
To: Ard Biesheuvel <ardb@kernel.org>, Rebecca Cran <rebecca@bsdio.com>
Cc: <devel@edk2.groups.io>, Bob Feng <bob.c.feng@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
"Kinney, Michael D" <michael.d.kinney@intel.com>
Subject: Re: [edk2-devel] [PATCH] BaseTools/GenFw AARCH64: Convert more types of explicit GOT references
Date: Tue, 6 Sep 2022 12:53:50 +0100 [thread overview]
Message-ID: <2d307167-a475-8f75-e897-bd0a99f43c29@quicinc.com> (raw)
In-Reply-To: <CAMj1kXHAmreb1MXiKhahX7Lt_fbGeXv=rB6Hzd419gavV3988A@mail.gmail.com>
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_llindhol@quicinc.com>
> On Sun, 21 Aug 2022 at 16:33, Rebecca Cran <rebecca@bsdio.com> wrote:
>>
>> Tested-by: Rebecca Cran <rebecca@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 <rebecca@bsdio.com>
>>> Cc: Bob Feng <bob.c.feng@intel.com>
>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>>> Cc: "Kinney, Michael D" <michael.d.kinney@intel.com>
>>> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
>>> Signed-off-by: Ard Biesheuvel <ardb@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
next prev parent reply other threads:[~2022-09-06 11:54 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-21 14:16 [PATCH] BaseTools/GenFw AARCH64: Convert more types of explicit GOT references Ard Biesheuvel
2022-08-21 14:33 ` [edk2-devel] " Rebecca Cran
2022-09-06 10:30 ` Ard Biesheuvel
2022-09-06 11:53 ` Leif Lindholm [this message]
2022-09-07 13:04 ` Bob Feng
2022-09-10 6:59 ` Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2d307167-a475-8f75-e897-bd0a99f43c29@quicinc.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox