[PATCH] RISC-V: Support GNU indirect functions.
Fangrui Song
i@maskray.me
Wed Jul 22 06:27:18 GMT 2020
On 2020-07-21, Nelson Chu wrote:
>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?
STT_FUNC is required for references within the module. If an ifunc is
referended by a local PC-relative relocation, the intention may be to
take the address. The address should be equal to other potentially
address taking relocation types. I don't think there is a way keeping
STT_IFUNC if no dynamic relocation is desired.
Compilers can produce a PC-relative relocation if it does not know the
target function is an ifunc (marked via inline asm, instead of
__attribute__((ifunc(...)))).
>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.
Great!
More information about the Binutils
mailing list