summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2018-02-16 01:10:51 +0000
committerRui Ueyama <ruiu@google.com>2018-02-16 01:10:51 +0000
commit65b620be8a63c8dee5225562a43c6dfc827394a7 (patch)
tree94a131817f542bc3ec34f96ad6d452daf92046e7
parentda9c122203ee41d66979e906cea81c9ddbd1cfdc (diff)
downloadbcm5719-llvm-65b620be8a63c8dee5225562a43c6dfc827394a7.tar.gz
bcm5719-llvm-65b620be8a63c8dee5225562a43c6dfc827394a7.zip
Relax relocation type checking in a non-ALLOC section.
Even though it doesn't make sense, there seems to be multiple programs in the wild that create PC-relative relocations in non-ALLOC sections. I believe this is caused by the negligence of GNU linkers to not report any errors for such relocations. Currently, lld emits warnings against such relocations and exits. So, you cannot link any program that contains wrong relocations until you fix an issue in a program that generates wrong ELF files. It's often impractical to fix a program because it's not always easy. This patch relaxes the error checking and emit a warning instead. Differential Revision: https://reviews.llvm.org/D43351 llvm-svn: 325307
-rw-r--r--lld/ELF/InputSection.cpp36
-rw-r--r--lld/test/ELF/i386-debug-noabs.test2
-rw-r--r--lld/test/ELF/non-abs-reloc.s16
3 files changed, 40 insertions, 14 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 6766c00915d..c59b03ba239 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -641,6 +641,14 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
for (const RelTy &Rel : Rels) {
RelType Type = Rel.getType(Config->IsMips64EL);
+
+ // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
+ // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
+ // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
+ // need to keep this bug-compatible code for a while.
+ if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
+ continue;
+
uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
int64_t Addend = getAddend<ELFT>(Rel);
@@ -651,17 +659,27 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
if (Expr == R_NONE)
continue;
+
if (Expr != R_ABS) {
- // GCC 8.0 or earlier have a bug that it emits R_386_GOTPC relocations
- // against _GLOBAL_OFFSET_TABLE for .debug_info. The bug seems to have
- // been fixed in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630,
- // but we need to keep this bug-compatible code for a while.
- if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
- continue;
+ std::string Msg = getLocation<ELFT>(Offset) +
+ ": has non-ABS relocation " + toString(Type) +
+ " against symbol '" + toString(Sym) + "'";
+ if (Expr != R_PC) {
+ error(Msg);
+ return;
+ }
- error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " +
- toString(Type) + " against symbol '" + toString(Sym) + "'");
- return;
+ // If the control reaches here, we found a PC-relative relocation in a
+ // non-ALLOC section. Since non-ALLOC section is not loaded into memory
+ // at runtime, the notion of PC-relative doesn't make sense here. So,
+ // this is a usage error. However, GNU linkers historically accept such
+ // relocations without any errors and relocate them as if they were at
+ // address 0. For bug-compatibilty, we accept them with warnings. We
+ // know Steel Bank Common Lisp as of 2018 have this bug.
+ warn(Msg);
+ Target->relocateOne(BufLoc, Type,
+ SignExtend64<Bits>(Sym.getVA(Addend - Offset)));
+ continue;
}
if (Sym.isTls() && !Out::TlsPhdr)
diff --git a/lld/test/ELF/i386-debug-noabs.test b/lld/test/ELF/i386-debug-noabs.test
index 712d0a59cec..c0eb4d9562d 100644
--- a/lld/test/ELF/i386-debug-noabs.test
+++ b/lld/test/ELF/i386-debug-noabs.test
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: yaml2obj %s -o %t.o
-# RUN: ld.lld %t.o -o %t.exe
+# RUN: ld.lld %t.o -o %t.exe --entry 0 --fatal-warnings
## This is for https://bugs.llvm.org//show_bug.cgi?id=34852. GCC 8.0 or
## earlier have a bug which creates non-absolute R_386_GOTPC relocations
diff --git a/lld/test/ELF/non-abs-reloc.s b/lld/test/ELF/non-abs-reloc.s
index 454104cca07..875af47fe15 100644
--- a/lld/test/ELF/non-abs-reloc.s
+++ b/lld/test/ELF/non-abs-reloc.s
@@ -1,11 +1,19 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
-// CHECK: {{.*}}:(.dummy+0x0): has non-ABS relocation R_X86_64_GOTPCREL against symbol 'foo'
+// RUN: ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: (.nonalloc+0x1): has non-ABS relocation R_X86_64_PC32 against symbol '_start'
+// CHECK: (.nonalloc+0x6): has non-ABS relocation R_X86_64_PC32 against symbol '_start'
+
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DISASM %s
+// DISASM: Disassembly of section .nonalloc:
+// DISASM-NEXT: .nonalloc:
+// DISASM-NEXT: 0: {{.*}} callq {{.*}} <_start>
+// DISASM-NEXT: 5: {{.*}} callq {{.*}} <_start>
.globl _start
_start:
nop
-.section .dummy
- .long foo@gotpcrel
+.section .nonalloc
+ call _start
+ call _start
OpenPOWER on IntegriCloud