[ELF] Make the rule to create relative relocations in a writable section stricter
The current rule is loose: `!Sym.IsPreemptible || Expr == R_GOT`. When the symbol is non-preemptable, this allows absolute relocation types with smaller numbers of bits, e.g. R_X86_64_{8,16,32}. They are disallowed by ld.bfd and gold, e.g. ld.bfd: a.o: relocation R_X86_64_8 against `.text' can not be used when making a shared object; recompile with -fPIC This patch: a) Add TargetInfo::SymbolicRel to represent relocation types that resolve to a symbol value (e.g. R_AARCH_ABS64, R_386_32, R_X86_64_64). As a side benefit, we currently (ab)use GotRel (R_*_GLOB_DAT) to resolve GOT slots that are link-time constants. Since we now use Target->SymbolRel to do the job, we can remove R_*_GLOB_DAT from relocateOne() for all targets. R_*_GLOB_DAT cannot be used as static relocation types. b) Change the condition to `!Sym.IsPreemptible && Type != Target->SymbolicRel || Expr == R_GOT`. Some tests are caught by the improved error checking (ld.bfd/gold also issue errors on them). Many misuse .long where .quad should be used instead. Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D63121 llvm-svn: 363059
This commit is contained in:
parent
a5240361dd
commit
025a815d75
|
@ -59,6 +59,7 @@ AArch64::AArch64() {
|
|||
GotRel = R_AARCH64_GLOB_DAT;
|
||||
NoneRel = R_AARCH64_NONE;
|
||||
PltRel = R_AARCH64_JUMP_SLOT;
|
||||
SymbolicRel = R_AARCH64_ABS64;
|
||||
TlsDescRel = R_AARCH64_TLSDESC;
|
||||
TlsGotRel = R_AARCH64_TLS_TPREL64;
|
||||
PltEntrySize = 16;
|
||||
|
@ -258,7 +259,6 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
write32le(Loc, Val);
|
||||
break;
|
||||
case R_AARCH64_ABS64:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_PREL64:
|
||||
write64le(Loc, Val);
|
||||
break;
|
||||
|
|
|
@ -35,6 +35,7 @@ AMDGPU::AMDGPU() {
|
|||
RelativeRel = R_AMDGPU_RELATIVE64;
|
||||
GotRel = R_AMDGPU_ABS64;
|
||||
NoneRel = R_AMDGPU_NONE;
|
||||
SymbolicRel = R_AMDGPU_ABS64;
|
||||
}
|
||||
|
||||
static uint32_t getEFlags(InputFile *File) {
|
||||
|
|
|
@ -52,6 +52,7 @@ ARM::ARM() {
|
|||
GotRel = R_ARM_GLOB_DAT;
|
||||
NoneRel = R_ARM_NONE;
|
||||
PltRel = R_ARM_JUMP_SLOT;
|
||||
SymbolicRel = R_ARM_ABS32;
|
||||
TlsGotRel = R_ARM_TLS_TPOFF32;
|
||||
TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
|
||||
TlsOffsetRel = R_ARM_TLS_DTPOFF32;
|
||||
|
@ -377,7 +378,6 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
switch (Type) {
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_BASE_PREL:
|
||||
case R_ARM_GLOB_DAT:
|
||||
case R_ARM_GOTOFF32:
|
||||
case R_ARM_GOT_BREL:
|
||||
case R_ARM_GOT_PREL:
|
||||
|
|
|
@ -40,6 +40,7 @@ Hexagon::Hexagon() {
|
|||
PltRel = R_HEX_JMP_SLOT;
|
||||
RelativeRel = R_HEX_RELATIVE;
|
||||
GotRel = R_HEX_GLOB_DAT;
|
||||
SymbolicRel = R_HEX_32;
|
||||
|
||||
// The zero'th GOT entry is reserved for the address of _DYNAMIC. The
|
||||
// next 3 are reserved for the dynamic loader.
|
||||
|
|
|
@ -59,11 +59,13 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
|
|||
|
||||
if (ELFT::Is64Bits) {
|
||||
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
|
||||
SymbolicRel = R_MIPS_64;
|
||||
TlsGotRel = R_MIPS_TLS_TPREL64;
|
||||
TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
|
||||
TlsOffsetRel = R_MIPS_TLS_DTPREL64;
|
||||
} else {
|
||||
RelativeRel = R_MIPS_REL32;
|
||||
SymbolicRel = R_MIPS_32;
|
||||
TlsGotRel = R_MIPS_TLS_TPREL32;
|
||||
TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
|
||||
TlsOffsetRel = R_MIPS_TLS_DTPREL32;
|
||||
|
|
|
@ -135,6 +135,7 @@ PPC::PPC() {
|
|||
PltRel = R_PPC_JMP_SLOT;
|
||||
RelativeRel = R_PPC_RELATIVE;
|
||||
IRelativeRel = R_PPC_IRELATIVE;
|
||||
SymbolicRel = R_PPC_ADDR32;
|
||||
GotBaseSymInGotPlt = false;
|
||||
GotHeaderEntriesNum = 3;
|
||||
GotPltHeaderEntriesNum = 0;
|
||||
|
@ -288,7 +289,6 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
write16(Loc, Val);
|
||||
break;
|
||||
case R_PPC_ADDR32:
|
||||
case R_PPC_GLOB_DAT:
|
||||
case R_PPC_REL32:
|
||||
write32(Loc, Val);
|
||||
break;
|
||||
|
|
|
@ -288,6 +288,7 @@ PPC64::PPC64() {
|
|||
PltRel = R_PPC64_JMP_SLOT;
|
||||
RelativeRel = R_PPC64_RELATIVE;
|
||||
IRelativeRel = R_PPC64_IRELATIVE;
|
||||
SymbolicRel = R_PPC64_ADDR64;
|
||||
PltEntrySize = 4;
|
||||
GotBaseSymInGotPlt = false;
|
||||
GotHeaderEntriesNum = 1;
|
||||
|
|
|
@ -37,6 +37,7 @@ SPARCV9::SPARCV9() {
|
|||
NoneRel = R_SPARC_NONE;
|
||||
PltRel = R_SPARC_JMP_SLOT;
|
||||
RelativeRel = R_SPARC_RELATIVE;
|
||||
SymbolicRel = R_SPARC_64;
|
||||
PltEntrySize = 32;
|
||||
PltHeaderSize = 4 * PltEntrySize;
|
||||
|
||||
|
@ -114,7 +115,6 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
break;
|
||||
case R_SPARC_64:
|
||||
case R_SPARC_UA64:
|
||||
case R_SPARC_GLOB_DAT:
|
||||
// V-xword64
|
||||
write64be(Loc, Val);
|
||||
break;
|
||||
|
|
|
@ -52,6 +52,7 @@ X86::X86() {
|
|||
PltRel = R_386_JUMP_SLOT;
|
||||
IRelativeRel = R_386_IRELATIVE;
|
||||
RelativeRel = R_386_RELATIVE;
|
||||
SymbolicRel = R_386_32;
|
||||
TlsGotRel = R_386_TLS_TPOFF;
|
||||
TlsModuleIndexRel = R_386_TLS_DTPMOD32;
|
||||
TlsOffsetRel = R_386_TLS_DTPOFF32;
|
||||
|
@ -291,7 +292,6 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
write16le(Loc, Val);
|
||||
break;
|
||||
case R_386_32:
|
||||
case R_386_GLOB_DAT:
|
||||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
case R_386_GOTOFF:
|
||||
|
|
|
@ -55,6 +55,7 @@ X86_64::X86_64() {
|
|||
PltRel = R_X86_64_JUMP_SLOT;
|
||||
RelativeRel = R_X86_64_RELATIVE;
|
||||
IRelativeRel = R_X86_64_IRELATIVE;
|
||||
SymbolicRel = R_X86_64_64;
|
||||
TlsDescRel = R_X86_64_TLSDESC;
|
||||
TlsGotRel = R_X86_64_TPOFF64;
|
||||
TlsModuleIndexRel = R_X86_64_DTPMOD64;
|
||||
|
@ -387,7 +388,6 @@ void X86_64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
break;
|
||||
case R_X86_64_64:
|
||||
case R_X86_64_DTPOFF64:
|
||||
case R_X86_64_GLOB_DAT:
|
||||
case R_X86_64_PC64:
|
||||
case R_X86_64_SIZE64:
|
||||
case R_X86_64_GOT64:
|
||||
|
|
|
@ -861,19 +861,19 @@ static void addGotEntry(Symbol &Sym) {
|
|||
bool IsLinkTimeConstant =
|
||||
!Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
|
||||
if (IsLinkTimeConstant) {
|
||||
In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
|
||||
In.Got->Relocations.push_back({Expr, Target->SymbolicRel, Off, 0, &Sym});
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
|
||||
// the GOT slot will be fixed at load-time.
|
||||
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
|
||||
addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel);
|
||||
addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->SymbolicRel);
|
||||
return;
|
||||
}
|
||||
Main->RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
|
||||
In.Got, Off, &Sym, 0,
|
||||
Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
|
||||
Main->RelaDyn->addReloc(
|
||||
Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got, Off, &Sym, 0,
|
||||
Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->SymbolicRel);
|
||||
}
|
||||
|
||||
// Return true if we can define a symbol in the executable that
|
||||
|
@ -919,10 +919,10 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
|
|||
}
|
||||
bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
|
||||
if (CanWrite) {
|
||||
// R_GOT refers to a position in the got, even if the symbol is preemptible.
|
||||
bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;
|
||||
|
||||
if (!IsPreemptibleValue) {
|
||||
if ((!Sym.IsPreemptible && Type == Target->SymbolicRel) || Expr == R_GOT) {
|
||||
// If this is a symbolic relocation to a non-preemptable symbol, or an
|
||||
// R_GOT, its address is its link-time value plus load address. Represent
|
||||
// it with a relative relocation.
|
||||
addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
|
||||
return;
|
||||
} else if (RelType Rel = Target->getDynRel(Type)) {
|
||||
|
@ -967,10 +967,17 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
|
|||
return;
|
||||
}
|
||||
|
||||
// Copy relocations are only possible if we are creating an executable.
|
||||
if (Config->Shared) {
|
||||
errorOrWarn("relocation " + toString(Type) +
|
||||
" cannot be used against symbol " + toString(Sym) +
|
||||
// Copy relocations (for STT_OBJECT) and canonical PLT (for STT_FUNC) are only
|
||||
// possible in an executable.
|
||||
//
|
||||
// Among R_ABS relocatoin types, SymbolicRel has the same size as the word
|
||||
// size. Others have fewer bits and may cause runtime overflow in -pie/-shared
|
||||
// mode. Disallow them.
|
||||
if (Config->Shared ||
|
||||
(Config->Pie && Expr == R_ABS && Type != Target->SymbolicRel)) {
|
||||
errorOrWarn(
|
||||
"relocation " + toString(Type) + " cannot be used against " +
|
||||
(Sym.getName().empty() ? "local symbol" : "symbol " + toString(Sym)) +
|
||||
"; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
RelType PltRel;
|
||||
RelType RelativeRel;
|
||||
RelType IRelativeRel;
|
||||
RelType SymbolicRel;
|
||||
RelType TlsDescRel;
|
||||
RelType TlsGotRel;
|
||||
RelType TlsModuleIndexRel;
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
|
||||
.data
|
||||
.hidden foo
|
||||
.long foo
|
||||
.quad foo
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
.asciz "abc"
|
||||
|
||||
.data
|
||||
.long .rodata.str1.1 + 4
|
||||
.quad .rodata.str1.1 + 4
|
||||
|
||||
// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): offset is outside the section
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x10004
|
||||
// CHECK-NEXT: Offset: 0x10004
|
||||
// CHECK-NEXT: Size: 12
|
||||
// CHECK-NEXT: Size: 24
|
||||
|
||||
|
||||
.data
|
||||
|
@ -54,9 +54,9 @@
|
|||
|
||||
.section foo,"aw"
|
||||
foof:
|
||||
.long foof
|
||||
.long bar-53
|
||||
.long bar
|
||||
.quad foof
|
||||
.quad bar-53
|
||||
.quad bar
|
||||
|
||||
.section x,"a"
|
||||
.zero 65036
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
// CHECK: relocation-before-merge-start.s.tmp.o:(.foo): offset is outside the section
|
||||
|
||||
.data
|
||||
.long .foo - 1
|
||||
.quad .foo - 1
|
||||
.section .foo,"aM",@progbits,4
|
||||
.quad 0
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): offset is outside the section
|
||||
|
||||
.data
|
||||
.long .foo + 10
|
||||
.quad .foo + 10
|
||||
.section .foo,"aM",@progbits,4
|
||||
.quad 0
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
|
||||
# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s
|
||||
# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
## Check we don't create dynamic relocations in a writable section,
|
||||
## if the number of bits is smaller than the wordsize.
|
||||
|
||||
.globl hidden
|
||||
.hidden hidden
|
||||
local:
|
||||
hidden:
|
||||
|
||||
# CHECK: error: relocation R_X86_64_8 cannot be used against local symbol; recompile with -fPIC
|
||||
# CHECK-NEXT: >>> defined in {{.*}}.o
|
||||
# CHECK-NEXT: >>> referenced by {{.*}}.o:(.data+0x0)
|
||||
# CHECK: error: relocation R_X86_64_16 cannot be used against local symbol; recompile with -fPIC
|
||||
# CHECK: error: relocation R_X86_64_32 cannot be used against local symbol; recompile with -fPIC
|
||||
# CHECK: error: relocation R_X86_64_32 cannot be used against symbol hidden; recompile with -fPIC
|
||||
|
||||
.data
|
||||
.byte local # R_X86_64_8
|
||||
.short local # R_X86_64_16
|
||||
.long local # R_X86_64_32
|
||||
|
||||
.long hidden # R_X86_64_32
|
Loading…
Reference in New Issue