Bug 24683 - RISC-V call and callplt reloc handling
Summary: RISC-V call and callplt reloc handling
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-06-14 20:23 UTC by Jim Wilson
Modified: 2022-09-06 08:57 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jim Wilson 2019-06-14 20:23:13 UTC
Another one from the lld folks.

Given
.global test, foo, bar, baz
test:
    call foo
    call bar
    call bar@plt
    call baz@plt
and compiling it with
    gcc -o call-plt-pic.so -shared -fPIC call-plt.s -nostdlib
objdump shows the result is
00000000000002c0 <test>:
 2c0:	00000097          	auipc	ra,0x0
 2c4:	d40080e7          	jalr	-704(ra) # 0 <_PROCEDURE_LINKAGE_TABLE_-0x280>
 2c8:	fe9ff0ef          	jal	ra,2b0 <bar@plt>
 2cc:	fe5ff0ef          	jal	ra,2b0 <bar@plt>
 2d0:	fd1ff0ef          	jal	ra,2a0 <baz@plt>

Two things to notice here.  The direct call to the undefined foo is branching to nowhere.  That should probably be a linker error.  And both the direct and plt calls to bar are going through the plt which looks odd and may be a bug.  This probably depends on what the psABI says.

If I clean up the testcase a little to make more sense, and define the functions that should be defined to get the right result
.global test, foo, bar, baz
foo:
	ret
bar:
	ret
baz:
	ret
test:
    call foo
    call bar
    call bar@plt
    call baz@plt
then I get
00000000000002d6 <test>:
 2d6:	ffbff0ef          	jal	ra,2d0 <foo>
 2da:	fe7ff0ef          	jal	ra,2c0 <bar@plt>
 2de:	fe3ff0ef          	jal	ra,2c0 <bar@plt>
 2e2:	fcfff0ef          	jal	ra,2b0 <baz@plt>

The call to foo is correct now, but the direct call to bar is still going through the plt.

Experimenting on x86, I can't get a direct call unless I mark the function protected visibility.  And if I do that, then both the direct call and plt call become direct calls in the output, which makes sense for a protected visibility function.  Which means I apparently can't have both direct and plt calls for the same symbol (at least not without using an alias).  Unless maybe I missed an x86 syntax for this, I haven't spent much time looking at this yet, just recording info for later.
Comment 1 Fangrui Song 2019-06-17 05:21:29 UTC
See https://sourceware.org/bugzilla/show_bug.cgi?id=24685 for a related issue.

For call foo, two relocation types may be used. The semantics in lld are:

* R_X86_64_PLT32: optimized to R_X86_64_PC32 (direct call) if the target symbol is non-preemptable (local/hidden/protected/defined in exe/-Bsymbolic/etc)
* R_X86_64_PC32 (I think this is not emitted by binutils>=2.31):
  if -no-pie or if the target symbol is non-preemptable, direct call
  otherwise, a canonical PLT is created

I think ld.bfd x86-64 behaves in a similar way.
Comment 2 Nelson Chu 2022-09-06 08:57:09 UTC
Anyway, we should have the same behavior of CALL and CALL_PLT both in GNU and LLVM, so marked this as RESOLVED and FIXED.

Btw, Psabi now suggest to use CALL_PLT, and deprecate CALL,
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/a0dced85018d7a0ec17023c9389cbd70b1dbc1b0

commit 3b1450b38c644f99aa2e211747b428b9f8d15cca
Refs: gdb-9-branchpoint-3394-g3b1450b38c6
Author:     Nelson Chu <nelson.chu@sifive.com>
AuthorDate: Wed Aug 26 01:19:13 2020 -0700
Commit:     Nelson Chu <nelson.chu@sifive.com>
CommitDate: Fri Aug 28 09:37:35 2020 +0800

    RISC-V: Treat R_RISCV_CALL and R_RISCV_CALL_PLT as the same in check_relocs.

    In fact, we can treate these two relocation as the same one in the
    riscv_elf_check_relocs.  I have heard that RISC-V lld had made this
    improvement, and so had GNU AARCH64, they only need R_AARCH64_CALL26
    for calls rather than two seperate relocations.

    Beside, the following PLT issue for RISC-V 32-bit glibc seems to be
    fixed by applying at least this patch.

    <https://sourceware.org/pipermail/libc-alpha/2020-August/117214.html>

    I have ran the toolchain regression, and everything seems fine for now.

            bfd/
            * elfnn-riscv.c (riscv_elf_check_relocs): Treat R_RISCV_CALL
            and R_RISCV_CALL_PLT as the same in the riscv_elf_check_relocs.
            (riscv_elf_relocate_section): Remove the R_RISCV_CALL for the
            unresolved reloc checks.

            ld/
            testsuite/ld-riscv-elf/lib-nopic-01a.s: Use R_RISCV_JAL rather
            than R_RISCV_CALL.
            testsuite/ld-riscv-elf/lib-nopic-01b.d: Likewise.
            testsuite/ld-riscv-elf/lib-nopic-01b.s: Likewise.