mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-06 12:09:26 +08:00
abd20cb637
I get the feedback recently that enable linker relaxations may fail to build some program. Consider the following case, .text foo: addi a0, a0, %pcrel_lo(.L2) call foo .L1: auipc a1, %pcrel_hi(data_g) addi a1, a1, %pcrel_lo(.L1) lui a2, %hi(data_g) addi a2, a2, %lo(data_g) lui a3, %tprel_hi(data_t) add a3, a3, tp, %tprel_add(data_t) addi a3, a3, %tprel_lo(data_t) .L2: auipc a0, %pcrel_hi(data_g) .data .word 0x0 .global data_g data_g: .word 0x1 .section .tbss data_t: .word 0x0 The current ld reports `dangerous relocation error` when doing the pcgp relaxation, test.o: in function `foo': (.text+0x0): dangerous relocation: %pcrel_lo missing matching %pcrel_hi The .L2 auipc should not be removed since it is behind the corresponding addi, so we record the information in the pcgp_relocs table to avoid removing the auipc later. But current ld still remove it since we do not update the pcgp_relocs table while doing other relaxations. I have two solutions to fix the problem, 1. Update the pcgp_relocs table once we actually delete the code. 2. Add new relax pass to do the pcgp relaxations At first I tried to do the first solution, and we need to update at least three information - hi_sec_off of riscv_pcgp_lo_reloc, hi_sec_off and hi_addr (symbol value) of riscv_pcgp_hi_reloc. Update the hi_sec_off is simple, but it is more complicate to update the symbol value, since we almost have to do parts the same works of _bfd_riscv_relax_call again in the riscv_relax_delete_bytes to get the correct symbol value. Compared with the first solution, the second one is more intuitive and simple. We add a new relax pass to do the pcgp relaxations later, so we will get all the information correctly in the _bfd_riscv_relax_call, including the symbol value, without changing so much code. I do not see any penalty by adding a new relax pass for now, so it should be fine to delay the pcgp relaxations. Besides, I have pass all riscv-gnu-toolchain regressions for this patch. bfd/ * elfnn-riscv.c (_bfd_riscv_relax_section): Add a new relax pass to do the pcgp relaxation later, after the lui and call relaxations, but before the delete and alignment relaxations. ld/ * emultempl/riscvelf.em (riscv_elf_before_allocation): Change link_info.relax_pass from 3 to 4. * testsuite/ld-riscv-elf/pcgp-relax.d: New testcase. * testsuite/ld-riscv-elf/pcgp-relax.s: Likewise. * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
211 lines
7.8 KiB
Plaintext
211 lines
7.8 KiB
Plaintext
# Expect script for RISC-V ELF linker tests
|
|
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
|
#
|
|
# This file is part of the GNU Binutils.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
# MA 02110-1301, USA.
|
|
#
|
|
|
|
# target: rv32 or rv64.
|
|
# output: Which output you want? (exe, pie, .so)
|
|
proc run_dump_test_ifunc { name target output} {
|
|
set asflags ""
|
|
set ldflags "-z nocombreloc"
|
|
|
|
switch -- $output {
|
|
exe {
|
|
set ext "exe"
|
|
}
|
|
pie {
|
|
set ext "pie"
|
|
set ldflags "$ldflags -pie"
|
|
}
|
|
pic {
|
|
set ext "so"
|
|
set ldflags "$ldflags -shared"
|
|
}
|
|
}
|
|
|
|
switch -- $target {
|
|
rv32 {
|
|
set asflags "$asflags -march=rv32i -mabi=ilp32"
|
|
set ldflags "$ldflags -melf32lriscv"
|
|
}
|
|
rv64 {
|
|
set asflags "$asflags -march=rv64i -mabi=lp64 -defsym __64_bit__=1"
|
|
set ldflags "$ldflags -melf64lriscv"
|
|
}
|
|
}
|
|
|
|
run_ld_link_tests [list \
|
|
[list "$name ($target-$output)" \
|
|
"$ldflags" "" \
|
|
"$asflags" \
|
|
[list "$name.s"] \
|
|
[concat [list "readelf -rW $name-$output.rd"] \
|
|
[list "objdump -dw $name.d"]] \
|
|
"$name-$target.$ext"]]
|
|
}
|
|
|
|
if [istarget "riscv*-*-*"] {
|
|
run_dump_test "call-relax"
|
|
run_dump_test "pcgp-relax"
|
|
run_dump_test "c-lui"
|
|
run_dump_test "c-lui-2"
|
|
run_dump_test "disas-jalr"
|
|
run_dump_test "pcrel-lo-addend"
|
|
run_dump_test "pcrel-lo-addend-2"
|
|
run_dump_test "attr-merge-arch-01"
|
|
run_dump_test "attr-merge-arch-02"
|
|
run_dump_test "attr-merge-arch-03"
|
|
run_dump_test "attr-merge-strict-align-01"
|
|
run_dump_test "attr-merge-strict-align-02"
|
|
run_dump_test "attr-merge-strict-align-03"
|
|
run_dump_test "attr-merge-strict-align-04"
|
|
run_dump_test "attr-merge-strict-align-05"
|
|
run_dump_test "attr-merge-stack-align"
|
|
run_dump_test "attr-merge-priv-spec-01"
|
|
run_dump_test "attr-merge-priv-spec-02"
|
|
run_dump_test "attr-merge-priv-spec-03"
|
|
run_dump_test "attr-merge-arch-failed-01"
|
|
run_dump_test "attr-merge-arch-failed-02"
|
|
run_dump_test "attr-merge-stack-align-failed"
|
|
run_dump_test "attr-merge-priv-spec-failed-01"
|
|
run_dump_test "attr-merge-priv-spec-failed-02"
|
|
run_dump_test "attr-merge-priv-spec-failed-03"
|
|
run_dump_test "attr-merge-priv-spec-failed-04"
|
|
run_dump_test "attr-merge-priv-spec-failed-05"
|
|
run_dump_test "attr-merge-priv-spec-failed-06"
|
|
run_ld_link_tests {
|
|
{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
|
|
"-march=rv32i -mabi=ilp32" {weakref32.s}
|
|
{{objdump -d weakref32.d}} "weakref32"}
|
|
{ "Weak reference 64" "-T weakref.ld -melf64lriscv" ""
|
|
"-march=rv64i -mabi=lp64" {weakref64.s}
|
|
{{objdump -d weakref64.d}} "weakref64"}
|
|
}
|
|
|
|
# The following tests require shared library support.
|
|
if ![check_shared_lib_support] {
|
|
return
|
|
}
|
|
|
|
set abis { rv32gc ilp32 elf32lriscv rv64gc lp64 elf64lriscv }
|
|
foreach { arch abi emul } $abis {
|
|
# This checks whether our linker scripts handle __global_pointer$
|
|
# correctly. It should be defined in executables and PIE, but not
|
|
# in shared libraries.
|
|
set suff64 [string map {ilp32 "" lp64 -64} $abi]
|
|
run_ld_link_tests [list \
|
|
[list "gp test ($abi shared library)" \
|
|
"-m$emul -shared" "" \
|
|
"-march=$arch -mabi=$abi -fpic" \
|
|
{ gp-test.s } \
|
|
[list "readelf --syms gp-test-lib.sd"] \
|
|
"gp-test-lib-${abi}.so"] \
|
|
[list "gp test ($abi executable)" \
|
|
"-m$emul" "" \
|
|
"-march=$arch -mabi=$abi" \
|
|
{ gp-test.s } \
|
|
[list "readelf --syms gp-test.sd"] \
|
|
"gp-test-${abi}"]]
|
|
}
|
|
|
|
run_ld_link_tests {
|
|
{ "Link non-pic code into a shared library (setup)"
|
|
"-shared" "" "" {lib-nopic-01a.s}
|
|
{} "lib-nopic-01a.so" }
|
|
}
|
|
run_dump_test "lib-nopic-01b"
|
|
|
|
# IFUNC testcases.
|
|
# Check IFUNC by single type relocs.
|
|
run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
|
|
run_dump_test_ifunc "ifunc-reloc-call-01" rv32 pie
|
|
run_dump_test_ifunc "ifunc-reloc-call-01" rv32 pic
|
|
run_dump_test_ifunc "ifunc-reloc-call-02" rv32 exe
|
|
run_dump_test_ifunc "ifunc-reloc-call-02" rv32 pie
|
|
run_dump_test_ifunc "ifunc-reloc-call-02" rv32 pic
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 exe
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 pie
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 pic
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv32 exe
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv32 pie
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv32 pic
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv32 exe
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv32 pie
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv32 pic
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 exe
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 pie
|
|
run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 pic
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv64 exe
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv64 pie
|
|
run_dump_test_ifunc "ifunc-reloc-data" rv64 pic
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv64 exe
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv64 pie
|
|
run_dump_test_ifunc "ifunc-reloc-got" rv64 pic
|
|
# Check the IFUNC PLT and non-PLT relocs.
|
|
run_dump_test_ifunc "ifunc-nonplt" rv32 exe
|
|
run_dump_test_ifunc "ifunc-nonplt" rv32 pie
|
|
run_dump_test_ifunc "ifunc-nonplt" rv32 pic
|
|
run_dump_test_ifunc "ifunc-plt-01" rv32 exe
|
|
run_dump_test_ifunc "ifunc-plt-01" rv32 pie
|
|
run_dump_test_ifunc "ifunc-plt-01" rv32 pic
|
|
run_dump_test_ifunc "ifunc-plt-02" rv32 exe
|
|
run_dump_test_ifunc "ifunc-plt-02" rv32 pie
|
|
run_dump_test_ifunc "ifunc-plt-02" rv32 pic
|
|
run_dump_test_ifunc "ifunc-nonplt" rv64 exe
|
|
run_dump_test_ifunc "ifunc-nonplt" rv64 pie
|
|
run_dump_test_ifunc "ifunc-nonplt" rv64 pic
|
|
run_dump_test_ifunc "ifunc-plt-01" rv64 exe
|
|
run_dump_test_ifunc "ifunc-plt-01" rv64 pie
|
|
run_dump_test_ifunc "ifunc-plt-01" rv64 pic
|
|
run_dump_test_ifunc "ifunc-plt-02" rv64 exe
|
|
run_dump_test_ifunc "ifunc-plt-02" rv64 pie
|
|
run_dump_test_ifunc "ifunc-plt-02" rv64 pic
|
|
# Check the .rela.iplt overwrite issue.
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 exe
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 pie
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 pic
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 exe
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pie
|
|
run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pic
|
|
|
|
# Setup shared libraries.
|
|
run_ld_link_tests {
|
|
{ "Build shared library for IFUNC non-PLT caller"
|
|
"-shared" "" "" {ifunc-seperate-caller-nonplt.s}
|
|
{} "ifunc-seperate-caller.so" }
|
|
{ "Build shared library for IFUNC PLT caller"
|
|
"-shared" "" "" {ifunc-seperate-caller-plt.s}
|
|
{} "ifunc-seperate-caller.so" }
|
|
{ "Build shared library for IFUNC resolver"
|
|
"-shared" "" "" {ifunc-seperate-resolver.s}
|
|
{} "ifunc-seperate-resolver.so" }
|
|
}
|
|
# The IFUNC resolver and caller are in the seperate modules.
|
|
# If IFUNC resolver and caller are linked to the same module,
|
|
# then the result are the same as the run_dump_test_ifunc.
|
|
run_dump_test "ifunc-seperate-nonplt-exe"
|
|
run_dump_test "ifunc-seperate-nonplt-pie"
|
|
run_dump_test "ifunc-seperate-nonplt-pic"
|
|
run_dump_test "ifunc-seperate-plt-exe"
|
|
run_dump_test "ifunc-seperate-plt-pie"
|
|
run_dump_test "ifunc-seperate-plt-pic"
|
|
run_dump_test "ifunc-seperate-pcrel-pie"
|
|
run_dump_test "ifunc-seperate-pcrel-pic"
|
|
}
|