Page MenuHomePhabricator

Relative VTables ABI on Fuchsia
Needs ReviewPublic

Authored by leonardchan on Jan 17 2020, 2:15 PM.

Details

Summary

This contains the updated patch for enabling Peter Collingbourne's relative vtable ABI (described in https://bugs.llvm.org/show_bug.cgi?id=26723) on Fuchsia. The goal is to reduce memory usage by making vtables readonly.

Key differences:

  • LTO is not required
  • No white listing of classes. Fuchsia does not guarantee C++ ABI stability, so anything running on Fuchsia should either by compiled with this ABI or not depend on the C++ ABI at all.
  • Instead of taking the offset between the vtable and virtual function directly, we emit a DSO-local stub that just contains a tail call to the original virtual function, and take the offset between that and the vtable. We do this because there are some cases where the original function that would've been inserted into the vtable is not local or hidden and may require some kind of dynamic relocation which prevents the vtable from being readonly. On x86_64, taking the offset between the function and the vtable gets lowered to the offset between the PLT entry for the function and the vtable which gives us a PLT32 reloc. On Aarch64, right now only CALL26 and JUMP26 instructions generate PLT relocations, so we manifest them with stubs that are just jumps to the original function.
  • Although this ABI does not yet work with RTTI, we apply the same technique with the RTTI component in the vtable and emit a proxy that results in a GOTPCREL reloc.

This is only the first patch which lays down the groundwork for the Fuchsia ABI. We would like to commit this, but will keep it disabled for now (hidden behind the flag) until we get RTTI fully working.

Diff Detail

Event Timeline

leonardchan created this revision.Jan 17 2020, 2:15 PM

On Aarch64, right now only CALL26 and JUMP26 instructions generate PLT relocations, so we manifest them with stubs that are just jumps to the original function.

I think it would be worth considering defining a new relocation type for this. I think we should make the new reloc type represent the relative address shifted right by 2, which would allow it to be used freely in the aarch64 small code model (which permits programs up to 4GB), but would require the target to be 4-byte aligned, which seems like a reasonable restriction. On aarch64, decoding this would not require any additional instructions either (we can fold the lsl into the add). We could use the same technique for a new GOTPCREL relocation to be used for the RTTI component. @peter.smith what do you think?

In D72959#1832011, @pcc wrote:

On Aarch64, right now only CALL26 and JUMP26 instructions generate PLT relocations, so we manifest them with stubs that are just jumps to the original function.

I think it would be worth considering defining a new relocation type for this. I think we should make the new reloc type represent the relative address shifted right by 2, which would allow it to be used freely in the aarch64 small code model (which permits programs up to 4GB), but would require the target to be 4-byte aligned, which seems like a reasonable restriction. On aarch64, decoding this would not require any additional instructions either (we can fold the lsl into the add). We could use the same technique for a new GOTPCREL relocation to be used for the RTTI component. @peter.smith what do you think?

The idea of a new relocation type has come up before, as I recall it was something like the equivalent of R_X86_PLT32

| R_X86_64_PLT32 | 4 | word32 | L + A - P |
Where L is defined as: L Represents the place (section offset or address) of the Procedure Linkage Table entry for a symbol.

For Fuchsia there are two options:
1.) Ask for an ABI relocation type to be defined. I've raised an ABI issue with Arm, for it to progress I think it needs a "yes we really would like one, here is the definition we want to use, this is the use case and it could be used outside of Fuchsia at some point." For example I can see position independent C++ being useful in bare-metal embedded C++. The external facing email for feedback on the abi is arm.eabi@arm.com (address is on the first page of the doc below)
2.) There are two ranges of relocation types reserved for private and platform relocations: https://developer.arm.com/docs/ihi0056/f/elf-for-the-arm-64-bit-architecture-aarch64-abi-2019q2-documentation

Private and platform-specific relocations
Private relocations for vendor experiments:

0xE000 to 0xEFFF for ELF64
0xE0 to 0xEF for ELF32
Platform ABI defined relocations:

0xF000 to 0xFFFF for ELF64
0xF0 to 0xFF for ELF32
Platform ABI relocations can only be interpreted when the EI_OSABI field is set to indicate the Platform ABI governing the definition.

All of the above codes will not be assigned by any future version of this standard.

If this could be generally useful outside of Fuchsia, then an official relocation would be preferable.

jdoerfert resigned from this revision.Jan 22 2020, 8:25 AM

There's two independently-useful things here for the relocation, right? First, it's useful to be able to express a relocation to a symbol that has the semantics of a particular function but doesn't necessarily have its address, and that concept could be used across many "physical" relocations; and second, it's potentially useful to have a shifted-by-two relative address relocation, at least on AArch64 where instructions (and v-table entries under this ABI) are always four-byte-aligned anyway. Is it possible to separate these concerns in ELF, e.g. by having a "symbol" that can be the target of any other relocation but which actually represents a function of unspecified address with the semantics of another function?

There's two independently-useful things here for the relocation, right? First, it's useful to be able to express a relocation to a symbol that has the semantics of a particular function but doesn't necessarily have its address, and that concept could be used across many "physical" relocations; and second, it's potentially useful to have a shifted-by-two relative address relocation, at least on AArch64 where instructions (and v-table entries under this ABI) are always four-byte-aligned anyway. Is it possible to separate these concerns in ELF, e.g. by having a "symbol" that can be the target of any other relocation but which actually represents a function of unspecified address with the semantics of another function?

It would be possible to design relocations like that, but I think it would be difficult to fit into existing multi-target designs, which assume that the relocation code alone encodes all the actions a linker needs to take (smart-format, dumb-linker). My understanding of the reasons behind this are:

  • The linker can have millions of relocations to resolve and having all the actions explicit in the code simplifies its job.
  • There is a large space of available relocation codes, partitioned per target, but a much more limited availability of target specific symbol types and flags.
  • The concerns can be separated at implementation time, for example the symbol lookup, encoding and calculation stages are independent and shared between the codes.

It is possible that there is a better trade-off in complexity, but anything radically different might need quite a bit of work to fit into an existing linker. Hope I've understood you correctly and apologies if the above isn't relevant.

Okay. In that case, I would ask that if you're considering going through the work of adding relocations, please consider adding both scaled and unscaled relative-offset-to-equivalent-symbol.