Bug 29551 - Wrong relocations against _GLOBAL_OFFSET_TABLE_
Summary: Wrong relocations against _GLOBAL_OFFSET_TABLE_
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.40
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-09-06 15:53 UTC by H.J. Lu
Modified: 2022-09-07 11:51 UTC (History)
3 users (show)

See Also:
Host:
Target: i386,x86-64
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2022-09-06 15:53:01 UTC
[hjl@gnu-tgl-3 tmp]$ cat 32.s 
	.text
	movl $_GLOBAL_OFFSET_TABLE_, %eax
	.data
	.long _GLOBAL_OFFSET_TABLE_
[hjl@gnu-tgl-3 tmp]$ gcc -c 32.s -m32 
[hjl@gnu-tgl-3 tmp]$ readelf -r 32.o

Relocation section '.rel.text' at offset 0xa0 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
00000001  0000010a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_

Relocation section '.rel.data' at offset 0xa8 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
00000000  0000010a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_
[hjl@gnu-tgl-3 tmp]$ 

R_386_32 should be used.

[hjl@gnu-tgl-3 tmp]$ cat 64.s 
	.text
	movl $_GLOBAL_OFFSET_TABLE_, %eax
	movq _GLOBAL_OFFSET_TABLE_@GOTPCREL(%rip), %rax
	.data
	.quad _GLOBAL_OFFSET_TABLE_
[hjl@gnu-tgl-3 tmp]$ gcc -c 64.s
[hjl@gnu-tgl-3 tmp]$ readelf -rW 64.o

Relocation section '.rela.text' at offset 0xd0 contains 2 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000001  000000010000001a R_X86_64_GOTPC32       0000000000000000 _GLOBAL_OFFSET_TABLE_ + 1
0000000000000008  0000000100000019 R_X86_64_GOTOFF64      0000000000000000 _GLOBAL_OFFSET_TABLE_ - 4

Relocation section '.rela.data' at offset 0x100 contains 1 entry:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000000  000000010000001d R_X86_64_GOTPC64       0000000000000000 _GLOBAL_OFFSET_TABLE_ + 0
[hjl@gnu-tgl-3 tmp]$ 

Relocations should be

[hjl@gnu-tgl-3 tmp]$ readelf -rW 64x.o 

Relocation section '.rela.text' at offset 0xe8 contains 2 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000001  000000010000000a R_X86_64_32            0000000000000000 _GLOBAL_OFFSET_TABLE_ + 0
0000000000000008  000000010000002a R_X86_64_REX_GOTPCRELX 0000000000000000 _GLOBAL_OFFSET_TABLE_ - 4

Relocation section '.rela.data' at offset 0x118 contains 1 entry:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000000  0000000100000001 R_X86_64_64            0000000000000000 _GLOBAL_OFFSET_TABLE_ + 0
[hjl@gnu-tgl-3 tmp]$
Comment 1 H.J. Lu 2022-09-06 16:58:01 UTC
GCC generates

	call	__x86.get_pc_thunk.bx
	addl	$_GLOBAL_OFFSET_TABLE_, %ebx

to load the address of _GLOBAL_OFFSET_TABLE_ into EBX with R_386_GOTPC relocation.
Comment 2 H.J. Lu 2022-09-06 19:46:46 UTC
We can't change _GLOBAL_OFFSET_TABLE_ nor _GLOBAL_OFFSET_TABLE_(%rip).
_GLOBAL_OFFSET_TABLE_ generates GOTPC32 relocation.  _GLOBAL_OFFSET_TABLE_(%rip)
generates GOTPC32 relocation which is the same as PC32 since symbol is GOT.

But we should handle _GLOBAL_OFFSET_TABLE_@GOTPCREL(%rip).
i386_displacement first generates BFD_RELOC_X86_64_GOTPCREL for
symbol@GOTPCREL(%rip).  Then i386_finalize_displacement changes it
to BFD_RELOC_32_PCREL.  Before i386_validate_fix changes BFD_RELOC_32_PCREL
back to BFD_RELOC_X86_64_GOTPCREL, output_disp changes BFD_RELOC_32_PCREL
to BFD_RELOC_X86_64_GOTPC32 because symbol == _GLOBAL_OFFSET_TABLE_.
Comment 3 H.J. Lu 2022-09-07 01:22:57 UTC
commit d6ab8113e32876e3d8ca06ad090d3160d51c8e16
Author: Jan Beulich <jbeulich@novell.com>
Date:   Fri Jun 17 08:03:59 2005 +0000

has

            (output_disp): Do GOTPC conversion also for BFD_RELOC_X86_64_32S
            and BFD_RELOC_32_PCREL. Use BFD_RELOC_X86_64_GOTPC32 instead of
            aborting.

Remove || reloc_type == BFD_RELOC_32_PCREL) seems to work.
Comment 4 Jan Beulich 2022-09-07 07:09:28 UTC
If that also allows _GLOBAL_OFFSET_TABLE_-. to work as expected, perhaps that's the way to go. It's been a long time, but I expect that form of expression was what I had in mind when adding the check for BFD_RELOC_32_PCREL.

What I'm unsure about is whether _GLOBAL_OFFSET_TABLE_@GOTPCREL is actually a legitimate construct. We're way to lax with (not) rejecting invalid <symbol>@<reloc> constructs anyway, so us not currently rejecting this means about nothing.