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.
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.
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.