[PATCH v2 0/8] RISC-V: Support GNU indirect functions

Nelson Chu nelson.chu@sifive.com
Mon Aug 10 07:35:33 GMT 2020


Hi binutils,

On Fri, Aug 7, 2020 at 4:23 PM Nelson Chu <nelson.chu@sifive.com> wrote:
> $ cat ifunc-plt-02.s
> .text
>         .type   foo_resolver, @function
> foo_resolver:
>         ret
>         .size   foo_resolver, .-foo_resolver
>
>         .globl  foo
>         .type   foo, %gnu_indirect_function
>         .set    foo, foo_resolver
>
>         .globl  bar
>         .type   bar, @function
> bar:
> # ifunc-reloc-got
> .L1:
>         auipc   x1, %got_pcrel_hi (foo)
>         ld      x1, %pcrel_lo (.L1) (x1)
> # ifunc-reloc-data
> .L2:
>         auipc   x2, %pcrel_hi (foo_addr)
>         ld      x2, %pcrel_lo (.L2) (x2)
> # ifunc-reloc-pcrel
> .L3:
>         auipc   x3, %pcrel_hi (foo)
>         addi    x3, x3, %pcrel_lo (.L3)
> # ifunc-reloc-call
> call    foo
>         call    foo@plt
>         ret
>         .size   bar, .-bar
>
>         .data
> foo_addr:
>         .quad   foo
>
> $ riscv64-unknown-linux-gnu-as ifunc-plt-02.s -o ifunc-plt-02.o
> $ ld.lld -pie ifunc-plt-02.o -o lld.pie
> $ riscv64-unknown-linux-gnu-readelf -Ws lld.pie
> Symbol table '.symtab' contains 9 entries:
> ...
> 1: 0000000000001278     4 FUNC    LOCAL  DEFAULT    6 foo_resolver
> ...
> 7: 00000000000012b0     0 FUNC    GLOBAL DEFAULT  UND foo
> ...
>
> $ riscv64-unknown-linux-gnu-readelf -Wr lld.pie
> Relocation section '.rela.dyn' at offset 0x248 contains 2 entries:
>     Offset             Info             Type               Symbol's
> Value  Symbol's Name + Addend
> 00000000000023d0  0000000000000003 R_RISCV_RELATIVE
>       12b0
> 00000000000033e0  000000000000003a R_RISCV_IRELATIVE
>       1278
>
> $ riscv64-unknown-linux-gnu-objdump -D lld.pie | less
> Disassembly of section .text:
>
> 0000000000001278 <foo_resolver>:
>     1278:       00008067                ret
>
> 000000000000127c <bar>:
>     127c:       00001097                auipc   ra,0x1
>     1280:       1540a083                lw      ra,340(ra) # 23d0
> <_DYNAMIC+0x110>
>
> 0000000000001284 <.L2>:
>     1284:       00002117                auipc   sp,0x2
>     1288:       15412103                lw      sp,340(sp) # 33d8 <foo_addr>
>
> 000000000000128c <.L3>:
>     128c:       00000197                auipc   gp,0x0
>     1290:       02418193                addi    gp,gp,36 # 12b0 <.L3+0x24>
>     1294:       00000097                auipc   ra,0x0
>     1298:       01c080e7                jalr    28(ra) # 12b0 <.L3+0x24>
>     129c:       00000097                auipc   ra,0x0
>     12a0:       014080e7                jalr    20(ra) # 12b0 <.L3+0x24>
>     12a4:       00008067                ret
>
> Disassembly of section .iplt:
>
> 00000000000012b0 <.iplt>:
>     12b0:       00002e17                auipc   t3,0x2
>     12b4:       130e3e03                ld      t3,304(t3) # 33e0 <foo_addr+0x8>
>     12b8:       000e0367                jalr    t1,t3
>     12bc:       00000013                nop
> ...
> Disassembly of section .data:
>
> 00000000000033d8 <foo_addr>:
>     33d8:       12b0                    addi    a2,sp,360
> ...
>
> 0x23d0 is GOT entry, 0x33d8 is data section, and 0x33e0 is .got.plt enrty.
> My understanding is that the GOT refers to `foo` and will get the
> address of .plt
> entry after ld.so resolved the R_RISCV_RELATIVE reloc.  Also, lld stroe the
> .plt entry address into the data section `foo_addr`.  Therefore, the function
> pointer equality looks good since we should always get the .plt entry as the
> function address.  As for the .got.plt, we should get the resolved IFUNC
> address after ld.so resolved the R_RISCV_IRELATIVE reloc.

Sorry, correct the lld readelf results, they are a little bit different,

$ riscv64-unknown-linux-gnu-readelf -Ws lld.pie
Symbol table '.symtab' contains 9 entries:
1: 0000000000001290     4 FUNC    LOCAL  DEFAULT    6 foo_resolver
7: 00000000000012c0     0 FUNC    GLOBAL DEFAULT    7 foo

$ riscv64-unknown-linux-gnu-readelf -Wr lld.pie
Relocation section '.rela.dyn' at offset 0x248 contains 3 entries:
    Offset             Info             Type               Symbol's
Value  Symbol's Name + Addend
00000000000023e0  0000000000000003 R_RISCV_RELATIVE
      12c0
00000000000033e8  0000000000000003 R_RISCV_RELATIVE
      12c0
00000000000033f0  000000000000003a R_RISCV_IRELATIVE
      1290

0x23e0 is GOT entry, 0x33e8 is the data address `foo_addr`, 0x12c0 is
.plt entry, and 0x33f0 is .got.plt entry.  0x1290 is the address of
`foo_resolver`.  Otherwise, the results are the same as the previous
mails.

I got the undef FUNC `foo` and missing R_RISCV_RELATIVE for 0x23e0
(data section) before, these unexpected behavior might caused since I
forgot to give  "-defsym __64_bit__=1" to assembler when assembling
ifunc-plt-02.s...  Sorry about these...

* Conclusion

1. For LLD
- PCREL relocation should be resolved locally, so it doesn’t allowed
to build shared library (different modules).
- Once the non-GOT and non-PLT reloc is used, lld will redirect them
to the corresponding .plt entry, and change the STT_IFUNC to STT_FUNC
to make sure the pointer equality.

2. For LD
- I treat PCREL and CALL as the same - through PLT, and allowed to
build shared library.
- GNU ld don't change the STT_IFUNC to STT_FUNC, we add more IRELATIVE
relocs to make sure the pointer equality.
- GNU ld will redirect the GOT and DATA relocs to the .plt entry only
when generating PDE (position dependent executable), and then fill the
.plt address into GOT and data region directly without dynamic relocs.

Thanks
Nelson


More information about the Binutils mailing list