mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-24 12:35:55 +08:00
ebdcad3fdd
According to the commit abd20cb637
, an
intersting thing is that - the more relax passes, the more chances of
relaxations are reduced [1]. Originally, we set the boolean `again`
to TRUE once the code is actually deleted, and then we run the relaxations
repeatedly if `again` is still TRUE. But `again` only works for the
relax pass itself, and won't affect others. That is - we can not use
`again` to re-run the relax pass when we already enter into the following
passes (can not run the relax passes backwards). Besides, we must seperate
the PCREL relaxations into two relax passes for some reasons [2], it make
us lose some relax opportunities.
This patch try to fix the problem, and the basic idea was come from Jim
Wilson - we use a new boolean, restart_relax, to determine if we need to
run the whole relax passes again from 0 to 2. Once we have deleted the
code between relax pass 0 to 2, the restart_relax will be set to TRUE,
we should run the whole relaxations again to give them more chances to
shorten the code. We will only enter into the relax pass 3 when the
restart_relax is FALSE, since we can't relax anything else once we start
to handle the alignments.
I have passed the gcc/binutils regressions by riscv-gnu-toolchain, and
looks fine for now.
[1] https://sourceware.org/pipermail/binutils/2020-November/114223.html
[2] https://sourceware.org/pipermail/binutils/2020-November/114235.html
bfd/
* elfnn-riscv.c (riscv_elf_link_hash_table): New boolean restart_relax,
used to check if we need to run the whole relaxations from relax pass 0
to 2 again.
(riscv_elf_link_hash_table_create): Init restart_relax to FALSE.
(_bfd_riscv_relax_align): Remove obsolete sec_flg0 set.
(_bfd_riscv_relax_delete): Set again to TRUE if we do delete the code.
(bfd_elfNN_riscv_restart_relax_sections): New function. Called by
after_allocation to check if we need to run the whole relaxations again.
(_bfd_riscv_relax_section): We will only enter into the relax pass 3 when
the restart_relax is FALSE; At last set restart_relax to TRUE if again is
TRUE, too.
* elfxx-riscv.h (bfd_elf32_riscv_restart_relax_sections): Declaration.
(bfd_elf64_riscv_restart_relax_sections): Likewise.
ld/
* emultempl/riscvelf.em (after_allocation): Run ldelf_map_segments many
times if riscv_restart_relax_sections returns TRUE.
* testsuite/ld-riscv-elf/restart-relax.d: New testcase. Before applying
this patch, the call won't be relaxed to jal; But now we have more chances
to do relaxations.
* testsuite/ld-riscv-elf/restart-relax.s: Likewise.
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
229 lines
8.4 KiB
Plaintext
229 lines
8.4 KiB
Plaintext
# Expect script for RISC-V ELF linker tests
|
|
# Copyright (C) 2017-2021 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.
|
|
#
|
|
|
|
proc riscv_choose_ilp32_emul {} {
|
|
if { [istarget "riscvbe-*"] \
|
|
|| [istarget "riscv32be-*"] \
|
|
|| [istarget "riscv64be-*"] } {
|
|
return "elf32briscv"
|
|
}
|
|
return "elf32lriscv"
|
|
}
|
|
|
|
proc riscv_choose_lp64_emul {} {
|
|
if { [istarget "riscvbe-*"] \
|
|
|| [istarget "riscv32be-*"] \
|
|
|| [istarget "riscv64be-*"] } {
|
|
return "elf64briscv"
|
|
}
|
|
return "elf64lriscv"
|
|
}
|
|
|
|
# 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 -m[riscv_choose_ilp32_emul]"
|
|
}
|
|
rv64 {
|
|
set asflags "$asflags -march=rv64i -mabi=lp64 -defsym __64_bit__=1"
|
|
set ldflags "$ldflags -m[riscv_choose_lp64_emul]"
|
|
}
|
|
}
|
|
|
|
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 "restart-relax"
|
|
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 [list \
|
|
[list "Weak reference 32" "-T weakref.ld -m[riscv_choose_ilp32_emul]" "" \
|
|
"-march=rv32i -mabi=ilp32" {weakref32.s} \
|
|
{{objdump -d weakref32.d}} "weakref32"] \
|
|
[list "Weak reference 64" "-T weakref.ld -m[riscv_choose_lp64_emul]" "" \
|
|
"-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 [list rv32gc ilp32 [riscv_choose_ilp32_emul] rv64gc lp64 [riscv_choose_lp64_emul]]
|
|
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"
|
|
}
|