This is an archive of the discontinued LLVM Phabricator instance.

[ELF][X86] Support R_X86_64_PLTOFF64
ClosedPublic

Authored by MaskRay on Oct 24 2021, 12:07 PM.

Details

Summary

For a function call (using the default -fplt), GCC -mcmodel=large generates an assembly modifier which
leads to an R_X86_64_PLTOFF64 relocation. In real world,
http://git.ageinghacker.net/jitter (used by GNU poke) uses -mcmodel=large.

R_X86_64_PLTOFF64's formula is (if preemptible) L - GOT + A or (if non-preemptible) S - GOT + A
where GOT is (confusingly) the address of .got.plt

Diff Detail

Event Timeline

MaskRay created this revision.Oct 24 2021, 12:07 PM
MaskRay requested review of this revision.Oct 24 2021, 12:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 24 2021, 12:07 PM
MaskRay edited the summary of this revision. (Show Details)Oct 24 2021, 12:15 PM
MaskRay updated this revision to Diff 381793.Oct 24 2021, 12:17 PM

adjust RelExpr member order

MaskRay edited the summary of this revision. (Show Details)Oct 24 2021, 12:20 PM

FWIW this looks like it matches the description in https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf . Would be good to get this checked over by someone that knows x86_64 better than me. If there's no-one left I can approve.

This may be a naive question, just thinking of Arm/AArch64 where the code often loads the base of the GOT with the GLOBAL_OFFSET_TABLE symbol. It may be worth checking on GOT being .got.plt. I'm guessing that in the large-code model some bit of code loads the base of the .got.plt. Is that done via the GLOBAL_OFFSET_TABLE symbol or some other more direct method? Just thinking of the case where GLOBAL_OFFSET_TABLE is not placed in between .got or .got.plt, this wouldn't be a problem if LLD always placed GLOBAL_OFFSET_TABLE at the base of the .got.plt if it existed. No problems if there is a more direct method for the code to get the base of the .got.plt.

lld/ELF/Relocations.cpp
1398–1399

// The 5 types ?

MaskRay added a comment.EditedOct 25 2021, 10:49 AM

FWIW this looks like it matches the description in https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf . Would be good to get this checked over by someone that knows x86_64 better than me.

// a.c
void bar();
int main() { bar(); }

// b.c
#include <stdio.h>
void foo() { puts("foo"); }
void bar() { foo(); }
.MAKE.MODE = meta curDirOk=true

all: a b.so

a: a.c b.so
        $(CC) a.c ./b.so -ldl -o $@ -g

# Add or omit -Wl,-Bsymbolic
# Create a symlink /usr/local/bin/ld pointing to the newly built lld
b.so: b.c
        $(CC) -shared -fpic -mcmodel=large -O2 -g $> -o $@

I have verified that bmake; ./a works. (With an incorrect computation for R_X86_64_PLTOFF64 ./a would segfault.)

Clang -mcmodel=large always uses -fno-plt like code generation with R_X86_64_GOTOFF64 instead of R_X86_64_PLTOFF64, so GCC must be used for verification.

If there's no-one left I can approve.

It's more or less the case now but fortunately not many changes are needed...

This may be a naive question, just thinking of Arm/AArch64 where the code often loads the base of the GOT with the GLOBAL_OFFSET_TABLE symbol. It may be worth checking on GOT being .got.plt. I'm guessing that in the large-code model some bit of code loads the base of the .got.plt. Is that done via the GLOBAL_OFFSET_TABLE symbol or some other more direct method? Just thinking of the case where GLOBAL_OFFSET_TABLE is not placed in between .got or .got.plt, this wouldn't be a problem if LLD always placed GLOBAL_OFFSET_TABLE at the base of the .got.plt if it existed. No problems if there is a more direct method for the code to get the base of the .got.plt.

LLD defines __GLOBAL_OFFSET_TABLE__ only when it is referenced. R_X86_64_PLTOFF64 does not force creation of the symbol (LLD matches GNU ld).

global-offset-table-position.s checks that __GLOBAL_OFFSET_TABLE__ is placed at .got.plt for x86-64.
__GLOBAL_OFFSET_TABLE__ is either at start(.got) or start(.got.plt). All our RelExpr formulae use either start(.got) or start(.got.plt), not __GLOBAL_OFFSET_TABLE__.

So I think it is fine not to check the symbol in the new test.

MaskRay updated this revision to Diff 382055.Oct 25 2021, 10:51 AM
MaskRay marked an inline comment as done.

update a stale comment

peter.smith accepted this revision.Oct 25 2021, 11:14 AM

Thanks for confirming the placement of GLOBAL_OFFSET_TABLE. I've set approved.

This revision is now accepted and ready to land.Oct 25 2021, 11:14 AM
This revision was automatically updated to reflect the committed changes.