[lld] 881c5ee - [ELF] Add -z rel and -z rela

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri May 29 14:23:52 PDT 2020


Author: Fangrui Song
Date: 2020-05-29T14:22:03-07:00
New Revision: 881c5eef98a6c3fa59907ba2eefa6e8d086394a6

URL: https://github.com/llvm/llvm-project/commit/881c5eef98a6c3fa59907ba2eefa6e8d086394a6
DIFF: https://github.com/llvm/llvm-project/commit/881c5eef98a6c3fa59907ba2eefa6e8d086394a6.diff

LOG: [ELF] Add -z rel and -z rela

LLD supports both REL and RELA for static relocations, but emits either
of REL and RELA for dynamic relocations. The relocation entry format is
specified by each psABI.

musl ld.so supports both REL and RELA. For such ld.so implementations,
REL (.rel.dyn .rel.plt) has size benefits even if the psABI chooses RELA:
sizeof(Elf64_Rel)=16 < sizeof(Elf64_Rela)=24.

* COPY, GLOB_DAT and J[U]MP_SLOT always have 0 addend. A ld.so
  implementation does not need to read the implicit addend.
  REL is strictly better.
* A RELATIVE has a non-zero addend. Such relocations can be packed
  compactly with the RELR relocation entry format, which is out of scope
  of this patch.
* For other dynamic relocation types (e.g. symbolic relocation R_X86_64_64),
  a ld.so implementation needs to read the implicit addend. REL may have
  minor performance impact, because reading implicit addends forces
  random access reads instead of being able to blast out a bunch of
  writes while chasing the relocation array.

This patch adds -z rel and -z rela to change the relocation entry format
for dynamic relocations. I have tested that a -z rel produced x86-64
executable works with musl ld.so

-z rela may be useful for debugging purposes on processors whose psABIs
specify REL as the canonical format: addends can be easily read by a tool.

Reviewed By: grimar, mcgrathr

Differential Revision: https://reviews.llvm.org/D80496

Added: 
    lld/test/ELF/i386-zrel-zrela.s
    lld/test/ELF/x86-64-zrel-zrela.s

Modified: 
    lld/ELF/Driver.cpp
    lld/docs/ld.lld.1

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index a38d6542f988..0019bb8cfdb9 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -422,11 +422,11 @@ static bool isKnownZFlag(StringRef s) {
          s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
          s == "nognustack" || s == "nokeep-text-section-prefix" ||
          s == "norelro" || s == "noseparate-code" || s == "notext" ||
-         s == "now" || s == "origin" || s == "pac-plt" || s == "relro" ||
-         s == "retpolineplt" || s == "rodynamic" || s == "shstk" ||
-         s == "text" || s == "undefs" || s == "wxneeded" ||
-         s.startswith("common-page-size=") || s.startswith("max-page-size=") ||
-         s.startswith("stack-size=");
+         s == "now" || s == "origin" || s == "pac-plt" || s == "rel" ||
+         s == "rela" || s == "relro" || s == "retpolineplt" ||
+         s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" ||
+         s == "wxneeded" || s.startswith("common-page-size=") ||
+         s.startswith("max-page-size=") || s.startswith("stack-size=");
 }
 
 // Report an error for an unknown -z option.
@@ -842,6 +842,22 @@ static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef mb) {
   return names.takeVector();
 }
 
+static bool getIsRela(opt::InputArgList &args) {
+  // If -z rel or -z rela is specified, use the last option.
+  for (auto *arg : args.filtered_reverse(OPT_z)) {
+    StringRef s(arg->getValue());
+    if (s == "rel")
+      return false;
+    if (s == "rela")
+      return true;
+  }
+
+  // Otherwise use the psABI defined relocation entry format.
+  uint16_t m = config->emachine;
+  return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC ||
+         m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64;
+}
+
 static void parseClangOption(StringRef opt, const Twine &msg) {
   std::string err;
   raw_string_ostream os(err);
@@ -1204,20 +1220,19 @@ static void setConfigs(opt::InputArgList &args) {
 
   // ELF defines two 
diff erent ways to store relocation addends as shown below:
   //
-  //  Rel:  Addends are stored to the location where relocations are applied.
+  //  Rel: Addends are stored to the location where relocations are applied. It
+  //  cannot pack the full range of addend values for all relocation types, but
+  //  this only affects relocation types that we don't support emitting as
+  //  dynamic relocations (see getDynRel).
   //  Rela: Addends are stored as part of relocation entry.
   //
   // In other words, Rela makes it easy to read addends at the price of extra
-  // 4 or 8 byte for each relocation entry. We don't know why ELF defined two
-  // 
diff erent mechanisms in the first place, but this is how the spec is
-  // defined.
+  // 4 or 8 byte for each relocation entry.
   //
-  // You cannot choose which one, Rel or Rela, you want to use. Instead each
-  // ABI defines which one you need to use. The following expression expresses
-  // that.
-  config->isRela = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON ||
-                   m == EM_PPC || m == EM_PPC64 || m == EM_RISCV ||
-                   m == EM_X86_64;
+  // We pick the format for dynamic relocations according to the psABI for each
+  // processor, but a contrary choice can be made if the dynamic loader
+  // supports.
+  config->isRela = getIsRela(args);
 
   // If the output uses REL relocations we must store the dynamic relocation
   // addends to the output sections. We also store addends for RELA relocations

diff  --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 298da173d58e..781bff1e970c 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -720,6 +720,12 @@ processing.
 .It Cm pac-plt
 AArch64 only, use pointer authentication in PLT.
 .Pp
+.It Cm rel
+Use REL format for dynamic relocations.
+.Pp
+.It Cm rela
+Use RELA format for dynamic relocations.
+.Pp
 .It Cm retpolineplt
 Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
 .Pp

diff  --git a/lld/test/ELF/i386-zrel-zrela.s b/lld/test/ELF/i386-zrel-zrela.s
new file mode 100644
index 000000000000..61b9e4122f0f
--- /dev/null
+++ b/lld/test/ELF/i386-zrel-zrela.s
@@ -0,0 +1,63 @@
+# REQUIRES: x86
+## The i386 psABI uses Elf64_Rela relocation entries. We produce
+## Elf32_Rel dynamic relocations by default, but can use Elf32_Rela with -z rela.
+
+# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -d -r -x .data %t.so | FileCheck --check-prefix=REL %s
+# RUN: ld.lld -shared -z rel %t.o -o %t1.so
+# RUN: llvm-readobj -d -r -x .data %t1.so | FileCheck --check-prefix=REL %s
+
+# REL:      REL      {{.*}}
+# REL-NEXT: RELSZ    32 (bytes)
+# REL-NEXT: RELENT   8 (bytes)
+# REL-NEXT: RELCOUNT 1
+# REL-NEXT: JMPREL   {{.*}}
+# REL-NEXT: PLTRELSZ 8 (bytes)
+# REL-NEXT: PLTGOT   {{.*}}
+# REL-NEXT: PLTREL   REL{{$}}
+# REL:      .rel.dyn {
+# REL-NEXT:   R_386_RELATIVE - 0x0
+# REL-NEXT:   R_386_GLOB_DAT func 0x0
+# REL-NEXT:   R_386_TLS_TPOFF tls 0x0
+# REL-NEXT:   R_386_32 _start 0x0
+# REL-NEXT: }
+# REL-NEXT: .rel.plt {
+# REL-NEXT:   R_386_JUMP_SLOT func 0x0
+# REL-NEXT: }
+
+# REL:      Hex dump of section '.data':
+# REL-NEXT: 0x000042cc cc420000 2a000000
+
+# RUN: ld.lld -shared -z rel -z rela %t.o -o %t2.so
+# RUN: llvm-readobj -d -r %t2.so | FileCheck --check-prefix=RELA %s
+
+# RELA:      RELA      {{.*}}
+# RELA-NEXT: RELASZ    48 (bytes)
+# RELA-NEXT: RELAENT   12 (bytes)
+# RELA-NEXT: RELACOUNT 1
+# RELA-NEXT: JMPREL    {{.*}}
+# RELA-NEXT: PLTRELSZ  12 (bytes)
+# RELA-NEXT: PLTGOT    {{.*}}
+# RELA-NEXT: PLTREL    RELA
+# RELA:      .rela.dyn {
+# RELA-NEXT:   R_386_RELATIVE - 0x42EC
+# RELA-NEXT:   R_386_GLOB_DAT func 0x0
+# RELA-NEXT:   R_386_TLS_TPOFF tls 0x2A
+# RELA-NEXT:   R_386_32 _start 0x2A
+# RELA-NEXT: }
+# RELA-NEXT: .rela.plt {
+# RELA-NEXT:   R_386_JUMP_SLOT func 0x0
+# RELA-NEXT: }
+
+.globl _start
+_start:
+  call func at PLT
+  movl func at GOT(%eax), %eax
+
+.section .text1,"awx"
+  movl %gs:tls at NTPOFF+42, %eax
+
+.data
+  .long .data
+  .long _start+42

diff  --git a/lld/test/ELF/x86-64-zrel-zrela.s b/lld/test/ELF/x86-64-zrel-zrela.s
new file mode 100644
index 000000000000..62b154fe7e98
--- /dev/null
+++ b/lld/test/ELF/x86-64-zrel-zrela.s
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+## The x86-64 psABI uses Elf64_Rela relocation entries. We produce
+## Elf64_Rel dynamic relocations by default, but can use Elf64_Rel with -z rel.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -d -r %t.so | FileCheck --check-prefix=RELA %s
+# RUN: ld.lld -shared -z rela %t.o -o %t1.so
+# RUN: llvm-readobj -d -r %t1.so | FileCheck --check-prefix=RELA %s
+
+# RELA:      RELA      {{.*}}
+# RELA-NEXT: RELASZ    72 (bytes)
+# RELA-NEXT: RELAENT   24 (bytes)
+# RELA-NEXT: RELACOUNT 1
+# RELA-NEXT: JMPREL    {{.*}}
+# RELA-NEXT: PLTRELSZ  24 (bytes)
+# RELA-NEXT: PLTGOT    {{.*}}
+# RELA-NEXT: PLTREL    RELA
+# RELA:      .rela.dyn {
+# RELA-NEXT:   R_X86_64_RELATIVE - 0x3428
+# RELA-NEXT:   R_X86_64_GLOB_DAT func 0x0
+# RELA-NEXT:   R_X86_64_64 _start 0x2A
+# RELA-NEXT: }
+# RELA-NEXT: .rela.plt {
+# RELA-NEXT:   R_X86_64_JUMP_SLOT func 0x0
+# RELA-NEXT: }
+
+# RUN: ld.lld -shared -z rela -z rel %t.o -o %t2.so
+# RUN: llvm-readobj -d -r -x .data %t2.so | FileCheck --check-prefix=REL %s
+
+# REL:      REL      {{.*}}
+# REL-NEXT: RELSZ    48 (bytes)
+# REL-NEXT: RELENT   16 (bytes)
+# REL-NEXT: RELCOUNT 1
+# REL-NEXT: JMPREL   {{.*}}
+# REL-NEXT: PLTRELSZ 16 (bytes)
+# REL-NEXT: PLTGOT   {{.*}}
+# REL-NEXT: PLTREL   REL{{$}}
+# REL:      .rel.dyn {
+# REL-NEXT:   R_X86_64_RELATIVE - 0x0
+# REL-NEXT:   R_X86_64_GLOB_DAT func 0x0
+# REL-NEXT:   R_X86_64_64 _start 0
+# REL-NEXT: }
+# REL-NEXT: .rel.plt {
+# REL-NEXT:   R_X86_64_JUMP_SLOT func 0x0
+# REL-NEXT: }
+
+# REL:      Hex dump of section '.data':
+# REL-NEXT: 0x00003408 08340000 00000000 2a000000 00000000
+
+.globl _start
+_start:
+  call func at PLT
+  movq func at GOTPCREL(%rip), %rax
+
+.data
+  .quad .data
+  .quad _start+42


        


More information about the llvm-commits mailing list