[PATCH] x86: Properly handle relocation against hidden ABS symbol
H.J. Lu
hjl.tools@gmail.com
Sun May 18 05:44:01 GMT 2025
On Sun, May 18, 2025 at 1:12 PM Fangrui Song <i@maskray.me> wrote:
>
> On Sat, May 17, 2025 at 3:18 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Sun, May 18, 2025 at 2:19 AM Fangrui Song <i@maskray.me> wrote:
> > >
> > > On Thu, May 15, 2025 at 8:28 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > > > On Fri, May 16, 2025 at 10:42 AM Fangrui Song <i@maskray.me> wrote:
> > > > >
> > > > > On Wed, May 14, 2025 at 9:54 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > > > >
> > > > > > On Thu, May 15, 2025, 12:41 PM Fangrui Song <i@maskray.me> wrote:
> > > > > >>
> > > > > >> On Wed, May 14, 2025 at 7:02 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > > > >> >
> > > > > >> > With PIC on x86-64,
> > > > > >> >
> > > > > >> > movq symbol@GOTPCREL(%rip), %rax
> > > > > >> >
> > > > > >> > is used to get the symbol address via GOT. If the symbol turns out to
> > > > > >> > be a hidden symbol, linker normally converts it into
> > > > > >> >
> > > > > >> > leaq symbol(%rip), %rax
> > > > > >> >
> > > > > >> > But if the symbol is an ABS symbol, RAX won't have the correct value at
> > > > > >> > run-time and it will have the symbol value + load address. If the symbol
> > > > > >> > is declared as hidden, compiler will generate
> > > > > >> >
> > > > > >> > leaq symbol(%rip), %rax
> > > > > >> >
> > > > > >> > to get the symbol address. If the hidden symbol is an ABS symbol, RAX
> > > > > >> > will have the same incorrect value at run-time. On i386,
> > > > > >> >
> > > > > >> > movl symbol@GOT(%reg1), %reg2
> > > > > >> >
> > > > > >> > is used to get the symbol address via GOT. If the symbol turns out to
> > > > > >> > be a hidden symbol, linker normally converts it into
> > > > > >> >
> > > > > >> > leal symbol@GOTOFF(%reg1), %reg2
> > > > > >> >
> > > > > >> > If the symbol is declared as hidden, compiler will generate
> > > > > >> >
> > > > > >> > leal symbol@GOTOFF(%reg1), %reg2
> > > > > >> >
> > > > > >> > In both cases, if the hidden symbol is an ABS symbol, REG2 will have the
> > > > > >> > same incorrect value at run-time. This patch changes the x86-64 linker
> > > > > >> > to convert
> > > > > >> >
> > > > > >> > movq symbol@GOTPCREL(%rip), %rax
> > > > > >> > and
> > > > > >> > leaq symbol(%rip), %rax
> > > > > >> > to
> > > > > >> > movq $symbol, %rax
> > > > > >>
> > > > > >> For the instruction `movq symbol@GOTPCREL(%rip), %rax`, where a
> > > > > >> R_X86_64_REX_GOTPCRELX relocation references a SHN_ABS symbol (e.g.,
> > > > > >> 42),
> > > > > >> the transformation should be disabled, and the GOT entry should
> > > > > >> contain the constant value 42.
> > > > > >
> > > > > >
> > > > > > The GOT entry isn't needed in this case if there is no overflow.
> > > > > > Since we know the value, we can keep the GOT entry if there is an overflow.
> > > > > > I will update my patch to do that.
> > > > > >
> > > > > >> (This behavir aligns with all lld/ELF ports that support GOT
> > > > > >> indirection to PC-relative optimization (x86-64, AArch64,
> > > > > >> SystemZ(s390x))
> > > > > >> https://maskray.me/blog/2021-08-29-all-about-global-offset-table#got-optimization
> > > > > >> )
> > > > > >>
> > > > > >> For the instruction `leaq symbol(%rip), %rax`, where a R_X86_64_PC32
> > > > > >> relocation references a SHN_ABS symbol (e.g., 42),
> > > > > >> I don't think we can do code transformation.
> > > > > >>
> > > > > >> Although this may link successfully in -no-pie mode if the
> > > > > >> displacement fits within a 32-bit range, it should be rejected in -pie
> > > > > >> and -shared modes, as the displacement is not a run-time constant.
> > > > > >
> > > > > >
> > > > > > We are discussing hidden ABS symbol here. I will update my patch to check overflow.
> > > > > > For this case, linker will issue an error if there is an overflow.
> > > > > > I will change my patch.
> > > > > >
> > > > > >> (Unless we decide to support text relocations and -z notext is
> > > > > >> specified - we shouldn't)
> > > > > >>
> > > > > >> Accessing a SHN_ABS value from C code requires delicate code
> > > > > >> construct, but I think it's acceptable.
> > > > > >> To generate a GOT-based code sequence, the user should either use
> > > > > >>
> > > > > >> * a STB_WEAK symbol with -fpic or -fpie
> > > > > >> * or a STB_GLOBAL symbol with -fpic or -fpie (exception: gcc
> > > > > >> HAVE_LD_PIE_COPYRELOC builds's -fpie doesn't work)
> > > > > >>
> > > > > >> ```
> > > > > >> // -fno-pic: R_X86_64_PC32
> > > > > >> // -fpie: R_X86_64_REX_GOTPCRELX in clang, but R_X86_64_PC32 in GCC
> > > > > >> (as almost all builds set HAVE_LD_PIE_COPYRELOC)
> > > > > >> // -fpic: R_X86_64_REX_GOTPCRELX
> > > > > >> extern int def __attribute__((visibility("default")));
> > > > > >>
> > > > > >> extern int hid __attribute__((visibility("hidden")));
> > > > > >>
> > > > > >> // guaranteed R_X86_64_REX_GOTPCRELX
> > > > > >> extern int hid_w __attribute__((weak, visibility("hidden")));
> > > > > >>
> > > > > >> int *r_def() { return &def; }
> > > > > >> int *r_hid() { return &hid; }
> > > > > >> int *r_hid_w() { return &hid_w; }
> > > > > >> ```
> > > > > >>
> > > > > >> To align GCC x86-64's behavior with other GCC ports and Clang, I hope
> > > > > >> that we can take this HAVE_LD_PIE_COPYRELOC removal patch
> > > > > >> https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570139.html :)
> > > > > >>
> > > > > >>
> > > > > >>
> > > > > >> > and changes the i386 linker to convert
> > > > > >> >
> > > > > >> > movl symbol@GOT(%reg1), %reg2
> > > > > >> > and
> > > > > >> > leal symbol@GOTOFF(%reg1), %reg2
> > > > > >> > to
> > > > > >> > movl $symbol, %reg2
> > > > > >> >
> > > > > >> > for hidden ABS symbols.
> > > > > >> >
> > > > > >> > bfd/
> > > > > >> >
> > > > > >> > PR ld/32443
> > > > > >> > * elf32-i386.c (elf_i386_convert_load_reloc): Skip relocation
> > > > > >> > against linker-script hidden absolute symbol in PIC.
> > > > > >> > (elf_i386_finish_dynamic_symbol): Don't generate dynamic
> > > > > >> > relocation against inker-script hidden absolute symbol.
> > > > > >> > * elf64-x86-64.c (elf_x86_64_convert_load_reloc): Skip
> > > > > >> > relocation against linker-script hidden absolute symbol in PIC.
> > > > > >> > (elf_x86_64_finish_dynamic_symbol): Don't generate dynamic
> > > > > >> > relocation against inker-script hidden absolute symbol.
> > > > > >> > * elfxx-x86.c (elf_x86_allocate_dynrelocs): Don't allocate
> > > > > >> > dynamic relocation against inker-script hidden absolute symbol.
> > > > > >> > * elfxx-x86.h (HIDDEN_ABS_SYMBOL_P): New.
> > > > > >> >
> > > > > >> > ld/
> > > > > >> >
> > > > > >> > PR ld/32443
> > > > > >> > * testsuite/ld-elf/linux-x86.exp: Run PR ld/32443 tests. Allow
> > > > > >> > PC32 relocation against hidden ABS symbol in PIE.
> > > > > >> > * testsuite/ld-elf/pr32443-hidden.rd: New file.
> > > > > >> > * testsuite/ld-elf/pr32443-hidden.t: Likewise.
> > > > > >> > * testsuite/ld-elf/pr32443.t: Likewise.
> > > > > >> > * testsuite/ld-elf/pr32443a.c: Likewise.
> > > > > >> > * testsuite/ld-elf/pr32443b.c: Likewise.
> > > > > >> > * testsuite/ld-i386/i386.exp: Run lea2, mov4a and mov4b.
> > > > > >> > * testsuite/ld-i386/lea2.d: New file.
> > > > > >> > * testsuite/ld-i386/lea2.s: Likewise.
> > > > > >> > * testsuite/ld-i386/mov4.s: Likewise.
> > > > > >> > * testsuite/ld-i386/mov4a.d: Likewise.
> > > > > >> > * testsuite/ld-i386/mov4b.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/lea2-x32.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/lea2.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/lea2.s: Likewise.
> > > > > >> > * testsuite/ld-x86-64/mov3.s: Likewise.
> > > > > >> > * testsuite/ld-x86-64/mov3a-x32.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/mov3a.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/mov3b-x32.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/mov3b.d: Likewise.
> > > > > >> > * testsuite/ld-x86-64/x86-64.exp: Run lea2, lea2-x32, mov3a,
> > > > > >> > mov3a-x32, mov3b and mov3b-x32.
> > > > > >> >
> > > > > >> > --
> > > > > >> > H.J.
> > > > >
> > > > > ## Regarding R_X86_64_PC32
> > > > >
> > > > > Recalling the discussion in
> > > > > https://sourceware.org/bugzilla/show_bug.cgi?id=25749 , the command
> > > > > ./ld -shared -o liba.so a.o x.o should be rejected (as you implemented
> > > > > in 2020, thanks!), consistent with lld's behavior.
> > > > >
> > > > > ld.lld -shared -o liba.so a.o x.o
> > > > > ld.lld: error: relocation R_X86_64_PC32 cannot refer to absolute
> > > > > symbol: _binary_a_c_size
> > > > > >>> defined in x.o
> > > > > >>> referenced by a.c:5
> > > > > >>> a.o:(foo)
> > > > >
> > > > > This patch will patch this instruction to `movq $0x98, %rax`, which
> > > > > should not be allowed.
> > > >
> > > > Why shouldn't it be allowed? Does "movq $0x98, %rax" give
> > > > the wrong value? Do you have a testcase to show the incorrect
> > > > behavior?
> > >
> > > R_X86_64_PC32 can be used in data directives where the transformation
> > > is not feasible
> > >
> > > .data
> > > .long .text -. # R_X86_64_PC32
> >
> > Good point.
> >
> > > Making relocation behavior depend on the SHF_EXECINSTR flag is
> > > generally discouraged. (I have seen no example in the LLD codebase.)
> >
> > But rewriting opcode can depend on the SHF_EXECINSTR flag.
> > I sent out the v4 patch to do that, plus checking MODRM for (%rip).
>
> Users may include .long func - . in a SHF_EXECINSTR section, for
> instance, by placing such data before a function entry label, ensuring
> it remains unreachable by normal control flow.
> If func is local, the assembler will not generate a relocation, which
> makes this metadata use preferable in some scenarios.
>
> Alternatively, users can adopt the constant island approach common in
> RISC architectures. While unusual, this practice is not prohibited.
>
> PC32 code transformation would create a significant pitfall. I
> strongly object to it.
>
For
leaq abs_symbol(%rip), %rax
what should RAX caintain when abs_symbol is a local ABS symbol which is
0x100? I think it should be 0x100 and you believe that it should have
a different
value. This is generated by compiler from
extern int value __attribute__ ((visibility("hidden")));
void *
foo (void)
{
return &value;
}
when compiled with -fPIE.
--
H.J.
More information about the Binutils
mailing list