diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -422,11 +422,11 @@ 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 @@ 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 @@ // ELF defines two different 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 - // different 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 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -720,6 +720,12 @@ .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 --- /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@PLT + movl func@GOT(%eax), %eax + +.section .text1,"awx" + movl %gs:tls@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 --- /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@PLT + movq func@GOTPCREL(%rip), %rax + +.data + .quad .data + .quad _start+42