diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -802,8 +802,8 @@ // 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 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -202,6 +202,7 @@ 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 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1115,6 +1115,7 @@ 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 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -352,6 +352,10 @@ 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<"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 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -36,6 +36,9 @@ * 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 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -345,7 +345,7 @@ .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 --- 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