From a05384dc8930cbe967def7c5c4113740838e8fd0 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 12 Nov 2021 09:47:31 -0800 Subject: [PATCH] [ELF] Make --no-relax disable R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX GOT optimization This brings back the original version of D81359. I have found several use cases now. * Unlike GNU ld, LLD's relocation processing is one pass. If we decide to optimize(relax) R_X86_64_{,REX_}GOTPCRELX, we will suppress GOT generation and cannot undo the decision later. Optimizing R_X86_64_REX_GOTPCRELX can usually make it easy to hit `relocation R_X86_64_REX_GOTPCRELX out of range` because the distance to GOT is usually shorter. Without --no-relax, the user has to recompile with `-Wa,-mrelax-relocations=no`. * The option would help during my investigationg of the root cause of https://git.kernel.org/linus/09e43968db40c33a73e9ddbfd937f46d5c334924 * There is need for relaxation for AArch64 & RISC-V. Implementing this for x86-64 improves consistency with little target-specific cost (two-line X86_64.cpp change). Reviewed By: alexander-shaposhnikov Differential Revision: https://reviews.llvm.org/D113615 --- lld/ELF/Arch/X86_64.cpp | 4 ++-- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 1 + lld/ELF/Options.td | 5 ++++- lld/docs/ReleaseNotes.rst | 3 +++ lld/docs/ld.lld.1 | 2 +- lld/test/ELF/x86-64-gotpc-relax.s | 11 +++++++++++ 7 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index 4cb95d4..4043675 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -802,8 +802,8 @@ RelExpr X86_64::adjustGotPcExpr(RelType type, int64_t addend, // with addend != -4. Such an instruction does not load the full GOT entry, so // we cannot relax the relocation. E.g. movl x@GOTPCREL+4(%rip), %rax // (addend=0) loads the high 32 bits of the GOT entry. - if ((type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX) || - addend != -4) + if (!config->relax || addend != -4 || + (type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX)) return R_GOT_PC; const uint8_t op = loc[-2]; const uint8_t modRm = loc[-1]; diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 65101d2..79c4fe0 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -202,6 +202,7 @@ struct Configuration { bool pie; bool printGcSections; bool printIcfSections; + bool relax; bool relocatable; bool relrPackDynRelocs; bool saveTemps; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 14d740d..9fac045 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1115,6 +1115,7 @@ static void readConfigs(opt::InputArgList &args) { config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats); config->printSymbolOrder = args.getLastArgValue(OPT_print_symbol_order); + config->relax = args.hasFlag(OPT_relax, OPT_no_relax, true); config->rpath = getRpath(args); config->relocatable = args.hasArg(OPT_relocatable); config->saveTemps = args.hasArg(OPT_save_temps); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 626b00c..ce82eb8 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -352,6 +352,10 @@ def push_state: F<"push-state">, def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; +defm relax: BB<"relax", + "Enable target-specific relaxations if supported (default)", + "Disable target-specific relaxations">; + defm reproduce: EEq<"reproduce", "Write tar file containing inputs and command to reproduce link">; @@ -695,7 +699,6 @@ def: F<"long-plt">; def: F<"no-copy-dt-needed-entries">; def: F<"no-ctors-in-init-array">; def: F<"no-keep-memory">; -def: F<"no-relax">; def: F<"no-warn-mismatch">; def: Separate<["--", "-"], "rpath-link">; def: J<"rpath-link=">; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index bd89cf0..1d53177 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -36,6 +36,9 @@ Architecture specific changes: * The x86-32 port now supports TLSDESC (``-mtls-dialect=gnu2``). (`D112582 `_) +* For x86-64, ``--no-relax`` now suppresses ``R_X86_64_GOTPCRELX`` and + ``R_X86_64_REX_GOTPCRELX`` GOT optimization + (`D113615 `_) Breaking changes ---------------- diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index dda76c4..843f4a1 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -345,7 +345,7 @@ Page align sections. .It Fl -no-omagic Do not set the text data sections to be writable, page align sections. .It Fl -no-relax -Disable target-specific relaxations. This is currently a no-op. +Disable target-specific relaxations. For x86-64 this disables R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX GOT optimization. .It Fl -no-rosegment Do not put read-only non-executable sections in their own segment. .It Fl -no-undefined-version diff --git a/lld/test/ELF/x86-64-gotpc-relax.s b/lld/test/ELF/x86-64-gotpc-relax.s index bf10838..cfd17fd 100644 --- a/lld/test/ELF/x86-64-gotpc-relax.s +++ b/lld/test/ELF/x86-64-gotpc-relax.s @@ -1,4 +1,6 @@ # REQUIRES: x86 +## Test R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX GOT optimization. + # RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t1 --no-apply-dynamic-relocs # RUN: llvm-readobj -x .got.plt -r %t1 | FileCheck --check-prefixes=RELOC,NO-APPLY-DYNAMIC-RELOCS %s @@ -7,6 +9,10 @@ # RUN: ld.lld %t.o -o %t1 # RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s +## --no-relax disables GOT optimization. +# RUN: ld.lld --no-relax %t.o -o %t2 +# RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=NORELAX %s + ## There is one R_X86_64_IRELATIVE relocations. # RELOC-LABEL: Relocations [ # RELOC-NEXT: Section (1) .rela.dyn { @@ -60,6 +66,11 @@ # DISASM-NEXT: jmpq *4119(%rip) # DISASM-NEXT: jmpq *4113(%rip) +# NORELAX-LABEL: <_start>: +# NORELAX-COUNT-12: movq +# NORELAX-COUNT-6: callq * +# NORELAX-COUNT-6: jmpq * + .text .globl foo .type foo, @function -- 2.7.4