This is an archive of the discontinued LLVM Phabricator instance.

[ELF2] Allow PPC64 to add the TOC-restore after .plt-based relocations
ClosedPublic

Authored by hfinkel on Oct 8 2015, 10:21 AM.

Details

Reviewers
ruiu
rafael
Summary

Under the PPC64 ELF ABI, functions that might call into other modules (and, thus, need to load a different TOC base value into %r2), need to restore the old value after the call. The old value is saved by the .plt code, and the caller only need to include a nop instruction after the call, which the linker will transform into a TOC restore if necessary.

In order to do this the relocation handler needs two things:

  1. It needs to know whether the call instruction it is modifying is targeting a .plt stub that will load a new TOC base value (necessitating a restore after the call).
  2. It needs to know where the buffer ends, so that it does not accidentally run off the end of the buffer when looking for the 'nop' instruction after the call.

Given these two pieces of information, we can insert the restore instruction in place of the following nop when necessary.

Test cases are needed; feedback is otherwise appreciated!

Diff Detail

Event Timeline

hfinkel updated this revision to Diff 36874.Oct 8 2015, 10:21 AM
hfinkel retitled this revision from to [ELF2] Allow PPC64 to add the TOC-restore after .plt-based relocations.
hfinkel updated this object.
hfinkel added reviewers: ruiu, rafael.
hfinkel added a project: lld.
hfinkel added a subscriber: llvm-commits.
ruiu edited edge metadata.Oct 8 2015, 10:51 AM

What if the linker has to write an instruction to restore the register but there's no space at end of function? This patch simply don't do anything for such functions, but if that works without the instruction, then why do we need that in the first place?

In D13565#263097, @ruiu wrote:

What if the linker has to write an instruction to restore the register but there's no space at end of function? This patch simply don't do anything for such functions, but if that works without the instruction, then why do we need that in the first place?

Generically you're correct, however, some code that calls functions that don't return (like _exit) will omit the trailing nop, and furthermore, will appear at the end of a function. Since they don't return, they legitimately don't need the TOC restore.

ruiu added a comment.Oct 8 2015, 11:09 AM

Does writing the instruction only when there's nop there work? I don't like to pass BufEnd for all these functions.

In D13565#263112, @ruiu wrote:

Does writing the instruction only when there's nop there work? I don't like to pass BufEnd for all these functions.

Sure. But how do I avoid running off the end of the buffer checking if the nop is there in the first place?

More generally, however, since we don't otherwise validate the offset member of the relocation field (and probably can't in a completely-target-independent way), it seems like we should be checking that against the end of the buffer anyway for all relocations everywhere.

Nevertheless, I agree this looks somewhat ugly. Would it be better to pass a pair of some kind?

ruiu added a comment.Oct 8 2015, 12:50 PM

For ForPltEntry, you can do

uint64_t Start = Out<ELF64BE>::Plt->getVA();
uint64_t End = Start + Out<ELF64BE>::Plt->getSize();
// Address A is pointing an PLT entry if Start <= A && A < End

By using this you can eliminate one parameter. I removed other parameter from the function, which is GotVA.

I don't think there's an obvious way to eliminate BufEnd, so I can live with that. But the parameter should be used only for that PPC relocation type. We don't want to do boundary check in general because Buf is guaranteed to not overrun.

hfinkel updated this revision to Diff 37128.Oct 12 2015, 9:49 AM
hfinkel edited edge metadata.

Updated to reflect reviewer comments (and added a test case).

ruiu added inline comments.Oct 12 2015, 10:40 AM
ELF/Target.cpp
398–401

Move this just above if (ForPltEntry &&, so that it's apparent that the following four lines don't use these variables.

400

I'd write this like the number line.

bool InPlt = PltStart <= S + A && S + A  < PltEnd;
test/elf2/Inputs/shared-ppc64.s
12

Remove this trailing line.

test/elf2/ppc64-toc-restore.s
47

Ditto

hfinkel updated this revision to Diff 37142.Oct 12 2015, 12:09 PM

Updated to reflect review comments.

ruiu accepted this revision.Oct 12 2015, 12:14 PM
ruiu edited edge metadata.

LGTM with a nit.

ELF/Target.cpp
405

Can you rename InPlt?

This revision is now accepted and ready to land.Oct 12 2015, 12:14 PM
hfinkel closed this revision.Oct 12 2015, 2:21 PM

r250110, thanks!