[PATCH] RISC-V: Support GNU indirect functions.

Nelson Chu nelson.chu@sifive.com
Tue Jul 21 07:15:07 GMT 2020


Hi MaskRay,

On Wed, Jul 15, 2020 at 12:44 PM Fangrui Song <i@maskray.me> wrote:
> .text
> .globl func
> .type func, @gnu_indirect_function
> func:
>    ret
>
> .globl _start
> _start:
> .L:
>    auipc a0, %pcrel_hi(func)
>    addi a0, a0, %pcrel_lo(.L)
>
> % ld.lld -pie a.64.o -o a.64  # silent
> % ld-new -pie a.64.o -o a.64
> ....: warning: GNU indirect functions with DT_TEXTREL may result in a segfault at runtime; recompile with -fPIE

The warning and redundant R_RISCV_NOP can be fixed by the following
change, but haven't run all tests.

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index ca0dd11..73f44d8 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -808,9 +808,10 @@ riscv_elf_check_relocs (bfd *abfd, struct
bfd_link_info *info,

          if ((bfd_link_pic (info)
               && (sec->flags & SEC_ALLOC) != 0
               && ((r != NULL && ! r->pc_relative)
                   || (h != NULL
-                      && (! info->symbolic
+                      && (! (bfd_link_pie (info)
+                             || info->symbolic)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (!bfd_link_pic (info)


> This test checks a non-GOT-non-PLT relocation to a STT_GNU_IFUNC.
> Such relocations can be used to take the address of the indirect function.
> To make sure pointer equality holds (i.e. taking the address from another module will get the same address),
> LLD will create a PLT (called "canonical PLT" among a few linker people),
> change func's type to STT_FUNC, and redirect all references to the PLT.
>
>       4: 0000000000001270     0 FUNC    GLOBAL DEFAULT    7 func
>
> This patch does not change func's type. If you link with ld-new -E -pie a.64.o -o a.64,
> func will be exported. Taking the address of func from another module will break pointer equality.
>
>      20: 00000000000003f0     0 IFUNC   GLOBAL DEFAULT    9 func

Consider Vincent Chen's ifunc support in GLIBC,
https://sourceware.org/pipermail/libc-alpha/2020-July/116059.html

I'm not sure why we need to change the symbol type from STT_IFUNC to
STT_FUNC, and then update the symbol value to the corresponding plt
entry.  If other modules want to call `func`, it will use
R_RISCV_JUMP_SLOT with the undef STT_FUNC `func`.  Glibc will know the
`func` is actually an STT_IFUNC according to the executable (probably
need --export-dynamic) or shared library which defines it, and then
handle the case just like what R_RISCV_IRELATIVE does.  If we want to
call the `ifunc`, and the `ifunc` is defined in the same
executable/shared library, then linker will generate the
R_RISCV_IRELATIVE for the call, it should be worked with or without
changing the STT_IFUNC to STT_FUNC.  So are there any cases that would
fail since we don't change the STT_IFUNC to STT_FUNC, and redirect it
to the plt entry?

I would be happy to do the changes, even if the GNU toolchain (gcc +
binutils + glibc) seems OK for now.  But this wouldn't be the first
time I was wrong, so please feel free to correct me.


> Regarding tests, it'd be nice to check whether this example works
> https://reviews.llvm.org/rG45acc35ac21323bafaf5d4367df10ebc4eed35f4
>
>    // gcc -fno-pie -no-pie a.c
>    // gcc -fPIE -pie a.c
>    #include <stdio.h>
>    static void impl(void) { puts("meow"); }
>    void thefunc(void) __attribute__((ifunc("resolver")));
>    void *resolver(void) { return &impl; }
>    int main(void) {
>      thefunc();
>      void (*theptr)(void) = &thefunc;
>      theptr();
>    }

I assume both `thefunc` and `theptr` should print "meow".  If the
result is expected, then our patches (Vincent Chen's glibc patch and
my binutils patch) should work.


Thanks
Nelson


More information about the Binutils mailing list