This is an archive of the discontinued LLVM Phabricator instance.

[PPC64] Long branch thunks.
ClosedPublic

Authored by sfertile on Oct 18 2018, 12:27 PM.

Details

Summary

On PowerPC64, when a function call offset is too large to encode in a call instruction the address is stored in a table in the data segment. A thunk is used to load the branch target address from the table relative to the TOC-pointer and indirectly branch to the callee. When linking position-dependent code the addresses are stored directly in the table, for position-independent code the table is allocated and filled in at load time by the dynamic linker.

For position-independent code the branch targets could have also gone in either the .got.plt or .igot.plt, but since the handling of the .got.plt/.igot.plt is already somewhat complicated and the .branch_lt section is needed for the position-dependent case anyway, I thought it was clearer to use the new section in both cases.

Diff Detail

Repository
rL LLVM

Event Timeline

sfertile created this revision.Oct 18 2018, 12:27 PM
ruiu added a comment.Oct 19 2018, 1:50 PM

First round of review.

ELF/Arch/PPC64.cpp
735–736 ↗(On Diff #170106)

assert(Type == R_PPC64_REL24 && "Unexpected relocation type used in branch") is more idiomatic in LLVM and lld.

739 ↗(On Diff #170106)

Omit llvm::.

ELF/Symbols.h
81 ↗(On Diff #170106)

Can you insert blank lines between these lines so that it is clear that this comment applies only to LtIndex?

164 ↗(On Diff #170106)

We usually do not define trivial accessors but instead make member variables public.

ELF/SyntheticSections.cpp
3072 ↗(On Diff #170106)

Flip the condition to return early.

ELF/SyntheticSections.h
967 ↗(On Diff #170106)

This class needs a class comment.

967 ↗(On Diff #170106)

Is this a PPC64-only thing? If so, the name should include PPC64.

974 ↗(On Diff #170106)

(void) is C-ish. You don't need it in C++.

975 ↗(On Diff #170106)

nit: add a blank line before a label.

ELF/Thunks.cpp
246–248 ↗(On Diff #170106)

Protected members should be written after public members.

MaskRay added inline comments.Oct 22 2018, 4:40 PM
ELF/Arch/PPC64.cpp
724 ↗(On Diff #170106)

executable -> position-dependent executable?

Config->Pic is true when linking .so or PIE executable.

ELF/SyntheticSections.cpp
3060 ↗(On Diff #170106)

LtIndex is uint32_t but -1U is undefined. Though they are usually the same type, UINT32_C(-1) or (uint32_t)-1 may be better

ELF/SyntheticSections.h
980 ↗(On Diff #170106)

InputSection *createInterpSection();

ELF/Thunks.cpp
618 ↗(On Diff #170106)

With -DLLVM_ENABLE_WARNINGS=on & MSVC, /W4 is turned on which warn
uint16_t OffLo = Offset;

warning C4244: 'initializing': conversion from 'int64_t' to 'uint16_t', possible loss of data

Append & 0xffff to suppress it.

sfertile updated this revision to Diff 170727.Oct 23 2018, 12:43 PM

Addressed initial review comments.

sfertile marked 11 inline comments as done.Oct 23 2018, 12:58 PM
sfertile added inline comments.
ELF/SyntheticSections.cpp
3060 ↗(On Diff #170106)

I initially changed this, but looking at it again I think -its interpreted as -(1U) which I believe is well defined. I'll see if I can verify that.

ELF/Thunks.cpp
618 ↗(On Diff #170106)

Thanks, I don't ever compile with MSVC so I didn't realize it would warn on this. I believe I've added similar code in previous patches, I'll find them and clean those up in a followup NFC patch.

ruiu added inline comments.Oct 23 2018, 1:34 PM
ELF/Symbols.h
214–216 ↗(On Diff #170727)

nit: I'd add this before IsInIplt as it seems a more natural place to add this bit. (New code shouldn't look new but should be written as if it were there from the beginning.)

ELF/Thunks.cpp
732–733 ↗(On Diff #170727)

Isn't this an assert? If this line is executed only when there is a bug in the code, this should be an assert.

618 ↗(On Diff #170106)

Hmm, but that narrowing conversion is obvious and we do that everywhere (in particular from int to char because RHS is usually promoted to int due to the usual integer promotion). If MSVC warns on it, we need this, but I don't like that warning in the first place...

MaskRay added inline comments.Oct 23 2018, 1:36 PM
ELF/SyntheticSections.cpp
3060 ↗(On Diff #170106)

Yes, it is interpreted as -(1U) as there is no negative integer literal. It applies unary minus operator to 1U.

(uint32_t)-1 LG.

MaskRay added inline comments.Oct 23 2018, 1:50 PM
ELF/SyntheticSections.cpp
3086 ↗(On Diff #170727)

Entries.size() == 0 -> Entries.empty()

test/ELF/ppc64-long-branch.s
5 ↗(On Diff #170727)

Name shared object *.so

66 ↗(On Diff #170727)

The indentation (this section and the instructions below .localentry) does not look good in Phabricator. Is it intended?

smeenai added inline comments.
test/ELF/ppc64-long-branch.s
66 ↗(On Diff #170727)

Phabricator always displays tabs as two spaces, so there might be some weird mixing of tabs and spaces going on.

MaskRay added inline comments.Oct 23 2018, 3:52 PM
test/ELF/ppc64-long-branch.s
8 ↗(On Diff #170727)

This is a warning ld.lld: warning: cannot find entry symbol _start; defaulting to 0x10010000

If it is obvious that _start serves as a caller, you may rename caller to _start, or use lld -e caller to silent the warning.

12 ↗(On Diff #170727)

These big-endian RUN lines should use RUN:. RUN will not run any tests :)

MaskRay added inline comments.Oct 23 2018, 4:05 PM
ELF/SyntheticSections.cpp
3086 ↗(On Diff #170727)

A synthetic section's empty() function is called twice:

  • In removeUnusedSyntheticSections() It should return false so that an empty .branch_lt will not be removed. I find that empty .branch_lt is kept in both ld.bfd and gold, so the behavior is consistent with them. But I think it deserves a comment.
  • In applySynthetic (called by finalizeSections()) This is to finalize a section which will assign true to Finalized.

In both cases, the section has not been finalized and Finalized is false, thus the function will return false in both cases.

MaskRay added inline comments.Oct 23 2018, 6:00 PM
ELF/Thunks.cpp
618 ↗(On Diff #170106)

I pointed out this because I saw some & 0xffff used otherwhere... and not sure if warnings would make some MSVC build bots unhappy..

/W3 does not warn implicit int -> char but /W4 does. I think it may be acceptable for a warning which is only enabled on /W4... Need some Windows expert to confirm this.

long long -> unsigned unsigned long long -> unsigned is warned in /W3.
http://www.brianlheim.com/2018/04/09/cmake-cheat-sheet.html says /W3 is the default

sfertile updated this revision to Diff 170951.Oct 24 2018, 12:14 PM

Addressed further review comments and update the formatting in the added tests.

sfertile marked 8 inline comments as done.Oct 24 2018, 12:22 PM
sfertile added inline comments.
ELF/Arch/PPC64.cpp
724 ↗(On Diff #170106)

Good catch. I intended to only exclude shared objects here.

ELF/Symbols.h
214–216 ↗(On Diff #170727)

"New code shouldn't look new but should be written as if it were there from the beginning" <-- I like that, I'll keep it in mind from now on :)

test/ELF/ppc64-long-branch.s
66 ↗(On Diff #170727)

Wasn't intended. There was a mix of tabs and spaces in the parts of the code that was generated from C, as well as I simply miss-formatted some of the parts I wrote. Fixed up now.

sfertile marked 2 inline comments as done.Oct 24 2018, 12:42 PM
sfertile added inline comments.
ELF/SyntheticSections.cpp
3060 ↗(On Diff #170106)

Ok, in my understanding the comparison to -1U has well defined behavior then. If thats the case I should stick with that for consistency (we do the same check in a number of other places as well). If it is indeed undefined or implementation defined I can update all the uses in this patch and follow up with an NFC patch to convert the other comparisons to what ever we settle on.

ELF/Thunks.cpp
618 ↗(On Diff #170106)

So if we enable warnings with -DLLVM_ENABLE_WARNINGS=on by default that is going to be /W3? If that's the case I'll leave &0xffff off unless the windows bot complains. (Sorry I would test this out myself but I don't have a windows machine to check it on).

sfertile added inline comments.Oct 24 2018, 1:19 PM
ELF/SyntheticSections.cpp
3086 ↗(On Diff #170727)

I originally just had empty() always return false but thought there may be code in the future that comes after thunk allocation that wants to skip any remaining empty sections. I also considered removing the section after thunk allocation if it was still empty, but decided that the added complexity wasn't worth it.

ruiu added inline comments.Oct 25 2018, 1:48 PM
ELF/Symbols.h
85 ↗(On Diff #170951)

Not sure if this renaming is good. Most people don't know and honestly don't care too much about PPC64 ABI, and PLT is a known terminology for them but LT is perhaps too unfamiliar.

Can you simply add a new member for PowerPC64 Linkage Table index? Does it need a full 32-bit or can it fit in 16 bit?

sfertile updated this revision to Diff 173174.Nov 8 2018, 9:12 AM

Added separate index for use in the branch_lt section and added comment on how we will end up with an empty branch_lt section due removing empty synthetic sections before thunk allocation.

ruiu accepted this revision.Nov 11 2018, 9:39 PM

LGTM

ELF/Symbols.cpp
141 ↗(On Diff #173174)

getPPC64LongBranchOffset

157 ↗(On Diff #173174)

getPPC64LongBranchTableVA

ELF/Symbols.h
92 ↗(On Diff #173174)

I'd name this PPC64BranchltIndex to make it clear that no one except PPC64 uses this member.

ELF/SyntheticSections.h
1012 ↗(On Diff #173174)

PPC64LongBranchTarget.

This revision is now accepted and ready to land.Nov 11 2018, 9:39 PM
This revision was automatically updated to reflect the committed changes.