Implementing a special case of cross-module sibling calls in assembly on 64-bit PowerPC

Zack Weinberg
Wed Mar 21 14:21:00 GMT 2018

GNU libc would like to remove a bunch of redundant functions from its
libpthread; for reasons too tedious to get into here, we must preserve
the symbols as stubs forwarding to the real function in
Because one of the affected symbols is vfork, these stubs must not
touch the stack (or anyway that particular one mustn't, and once we've
done the engineering to make that possible, we may as well reuse it
for all of them for efficiency).  On many architectures, this is as
simple as having an .S file full of

    .globl symbol
        jmp __libc_symbol@PLT

where 'jmp' is however you spell an unconditional branch on that
architecture.  (There's additional symbol versioning goo that does not
concern us here.)

On PowerPC-64 (both big- and little-endian), however, that construct
throws an error at link time:

nptl/libpthread_pic.a(pt-compat-stubs.os): In function `__pstub_vfork':
.../pt-compat-stubs.S:56:(.text+0x0): call to `__libc_vfork@@GLIBC_PRIVATE'
  lacks nop, can't restore toc; recompile with -fPIC

This is not actually complaining about a missing nop after the
instruction. elf64-ppc.c uses this error message for several different
conditions, one of which is when a plain branch (not a
branch-and-link) targets a symbol outside the current module.

Having read the ABI spec, I understand that in the general case this
is unsafe, because it could lead to the branch-ee returning to a
function that wasn't prepared to restore its own TOC pointer.
However, in this specific case, we know by construction that it _is_
safe, because these stub symbols are never called from within
libpthread, so whoever did call the version of 'vfork' (or whatever)
defined in libpthread must have done so with a proper cross-module
call sequence itself, and will restore its TOC when ultimately
returned to.

Is there any way to bypass this diagnostic in the current linker?
Failing that, could we add one?  For concreteness, the machine code I
want to emit on PPC64 is

0000000000000000 <.__pstub_vfork>:
   0:   48 00 00 00     b       0 <.__pstub_vfork>
                        0: R_PPC64_REL24        __libc_vfork

with or without 60 00 00 00 nop afterward, don't care (as it won't
actually be executed).


More information about the Binutils mailing list