[cfe-dev] [llvm-dev] RFC: A new ABI for virtual calls, and a change to the virtual call representation in the IR

Peter Collingbourne via cfe-dev cfe-dev at lists.llvm.org
Fri Mar 4 14:48:28 PST 2016

On Mon, Feb 29, 2016 at 1:53 PM, <> wrote:
> @A_vtable = {i8*, i8*, i32, i32} {0, @A::rtti, @A::f - (@A_vtable + 16),
> @A::g - (@A_vtable + 16)}

There's a subtlety about this aspect of the ABI that I should call
attention to. The virtual function references can only be resolved directly
by the static linker if they are defined in the same executable/DSO as the
virtual table. I expect this to be the overwhelmingly common case, as
classes are normally wholly defined within a single executable or DSO, so
our implementation should be optimized around that case.

If we expected cross-DSO references to be relatively common, we could make
vtable entries be relative to GOT entries, but that would introduce an
additional level of indirection and additional relocations, probably
costing us more in binary size and memory bandwidth than the current ABI.

However, it is technically possible to split the implementation of a
class's virtual functions between DSOs, and there are more practical cases
where we might expect to see cross-DSO references:

- one DSO could derive from a class defined in another DSO, and only
override some of its virtual functions
- the vtable could contain a reference to __cxa_pure_virtual which would be
defined by the standard library

We can handle these cases by having the vtable refer to a PLT entry for
each function that is not defined within the module. This can be done by
using a specific type of relative relocation that refers directly to the
symbol if defined within the current module, or to a PLT entry if not. This
is the same type of relocation that is needed to implement relative
branches on x86, so I'd expect it to be generally available on that
architecture (ELF has R_{386,X86_64}_PLT32, Mach-O has X86_64_RELOC_BRANCH,
COFF has IMAGE_REL_{AMD64,I386}_REL32, which may resolve to a thunk [1],
which is essentially the same thing as a PLT entry). It is also present on
ARM (R_ARM_PREL31, which was apparently added to support unwind tables).

We still need some way to create PLT relocations in the vtable's
initializer without breaking the semantics of a load from the vtable.
Rafael and I discussed this and we believe that if the target function is
unnamed_addr, this indicates that the function's address isn't observable
(this is true for virtual functions, as it isn't possible to take their
address), and so it could be substituted with the address of a PLT entry.

One complication is that on ELF the linker will still create a PLT entry if
the symbol has default visibility, in order to support symbol
interposition. We can mitigate against that by using protected visibility
for virtual functions if they would otherwise receive default visibility.


[1] http://llvm.org/klaus/lld/blob/master/COFF/InputFiles.cpp#L-305
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20160304/924f2f63/attachment.html>

More information about the cfe-dev mailing list