forked from OSchip/llvm-project
[ELF] Define _GLOBAL_OFFSET_TABLE_ symbol relative to .got
On many architectures gcc and clang will recognize _GLOBAL_OFFSET_TABLE_ - . and produce a relocation that can be processed without needing to know the value of _GLOBAL_OFFSET_TABLE_. This is not always the case; for example ARM gcc produces R_ARM_BASE_PREL but clang produces the more general R_ARM_REL32 to _GLOBAL_OFFSET_TABLE_. To evaluate this relocation correctly _GLOBAL_OFFSET_TABLE_ must be defined to be the either the base of the GOT or end of the GOT dependent on architecture.. If/when llvm-mc is changed to recognize _GLOBAL_OFFSET_TABLE_ - . this change will not be necessary for new objects. However there may still be old objects and versions of clang. Differential Revision: https://reviews.llvm.org/D34355 llvm-svn: 306282
This commit is contained in:
parent
1158fe9715
commit
113a59e7db
|
@ -21,7 +21,7 @@ using namespace lld::elf;
|
|||
namespace {
|
||||
class PPC final : public TargetInfo {
|
||||
public:
|
||||
PPC() {}
|
||||
PPC() { GotBaseSymOff = 0x8000; }
|
||||
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
||||
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
|
||||
const uint8_t *Loc) const override;
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
} // namespace
|
||||
|
||||
X86::X86() {
|
||||
GotBaseSymOff = -1;
|
||||
CopyRel = R_386_COPY;
|
||||
GotRel = R_386_GLOB_DAT;
|
||||
PltRel = R_386_JUMP_SLOT;
|
||||
|
|
|
@ -51,6 +51,7 @@ private:
|
|||
} // namespace
|
||||
|
||||
template <class ELFT> X86_64<ELFT>::X86_64() {
|
||||
GotBaseSymOff = -1;
|
||||
CopyRel = R_X86_64_COPY;
|
||||
GotRel = R_X86_64_GLOB_DAT;
|
||||
PltRel = R_X86_64_JUMP_SLOT;
|
||||
|
|
|
@ -361,7 +361,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
|
|||
// These expressions always compute a constant
|
||||
if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
|
||||
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
|
||||
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
|
||||
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
|
||||
R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
|
||||
R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
|
||||
return true;
|
||||
|
|
|
@ -66,6 +66,10 @@ public:
|
|||
// Given that, the smallest value that can be used in here is 0x10000.
|
||||
uint64_t DefaultImageBase = 0x10000;
|
||||
|
||||
// Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
|
||||
// end of .got
|
||||
uint64_t GotBaseSymOff = 0;
|
||||
|
||||
uint32_t CopyRel;
|
||||
uint32_t GotRel;
|
||||
uint32_t PltRel;
|
||||
|
|
|
@ -87,6 +87,8 @@ private:
|
|||
|
||||
uint64_t FileSize;
|
||||
uint64_t SectionHeaderOff;
|
||||
|
||||
bool HasGotBaseSym = false;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -815,19 +817,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
|||
Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
|
||||
}
|
||||
|
||||
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
|
||||
// is magical and is used to produce a R_386_GOTPC relocation.
|
||||
// The R_386_GOTPC relocation value doesn't actually depend on the
|
||||
// symbol value, so it could use an index of STN_UNDEF which, according
|
||||
// to the spec, means the symbol value is 0.
|
||||
// Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
|
||||
// the object file.
|
||||
// The situation is even stranger on x86_64 where the assembly doesn't
|
||||
// need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
|
||||
// an undefined symbol in the .o files.
|
||||
// Given that the symbol is effectively unused, we just create a dummy
|
||||
// hidden one to avoid the undefined symbol error.
|
||||
Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_");
|
||||
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
|
||||
// be at some offset from the base of the .got section, usually 0 or the end
|
||||
// of the .got
|
||||
InputSection *GotSection = (InX::MipsGot) ? cast<InputSection>(InX::MipsGot)
|
||||
: cast<InputSection>(InX::Got);
|
||||
HasGotBaseSym = addOptionalRegular<ELFT>("_GLOBAL_OFFSET_TABLE_", GotSection,
|
||||
Target->GotBaseSymOff) != nullptr;
|
||||
|
||||
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
|
||||
// static linking the linker is required to optimize away any references to
|
||||
|
@ -1136,7 +1132,8 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
|
|||
// to make them visible from linkescript side. But not all sections are always
|
||||
// required to be in output. For example we don't need dynamic section content
|
||||
// sometimes. This function filters out such unused sections from the output.
|
||||
static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
|
||||
static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V,
|
||||
bool HasGotBaseSym) {
|
||||
// All input synthetic sections that can be empty are placed after
|
||||
// all regular ones. We iterate over them all and exit at first
|
||||
// non-synthetic.
|
||||
|
@ -1147,6 +1144,8 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
|
|||
OutputSection *OS = SS->getParent();
|
||||
if (!SS->empty() || !OS)
|
||||
continue;
|
||||
if ((SS == InX::Got || SS == InX::MipsGot) && HasGotBaseSym)
|
||||
continue;
|
||||
OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
|
||||
SS->Live = false;
|
||||
// If there are no other sections in the output section, remove it from the
|
||||
|
@ -1220,7 +1219,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
return;
|
||||
|
||||
addPredefinedSections();
|
||||
removeUnusedSyntheticSections(OutputSections);
|
||||
removeUnusedSyntheticSections(OutputSections, HasGotBaseSym);
|
||||
|
||||
clearOutputSections();
|
||||
sortSections();
|
||||
|
|
|
@ -16,9 +16,9 @@ _start:
|
|||
bx lr
|
||||
.align 2
|
||||
.LGOT:
|
||||
// gas implicitly uses (GOT_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
|
||||
// llvm-mc needs the (GOT_PREL) suffix or it generates R_ARM_REL32
|
||||
.word _GLOBAL_OFFSET_TABLE_(GOT_PREL) - (.LPIC+8)
|
||||
// gas implicitly uses (R_ARM_BASE_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
|
||||
// llvm-mc generates R_ARM_REL32, this will need updating when MC changes
|
||||
.word _GLOBAL_OFFSET_TABLE_ - (.LPIC+8)
|
||||
.word function(GOT)
|
||||
|
||||
.globl function
|
||||
|
@ -28,17 +28,17 @@ function:
|
|||
bx lr
|
||||
|
||||
// CHECK: Dynamic Relocations {
|
||||
// CHECK-NEXT: 0x204C R_ARM_GLOB_DAT function 0x0
|
||||
// CHECK-NEXT: 0x2048 R_ARM_GLOB_DAT function 0x0
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
|
||||
// CHECK-NEXT: Value: 0x0
|
||||
// CHECK-NEXT: Value: 0x2048
|
||||
// CHECK-NEXT: Size:
|
||||
// CHECK-NEXT: Binding: Local
|
||||
// CHECK-NEXT: Type: None
|
||||
// CHECK-NEXT: Other [
|
||||
// CHECK-NEXT: STV_HIDDEN
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: Absolute
|
||||
// CHECK-NEXT: Section: .got
|
||||
|
||||
// CODE: Disassembly of section .text:
|
||||
// CODE-NEXT: _start:
|
||||
|
@ -49,5 +49,5 @@ function:
|
|||
// CODE:$d.1:
|
||||
// (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038
|
||||
// CODE-NEXT: 1010: 38 10 00 00
|
||||
// (Got(function) - GotBase = 0x4
|
||||
// CODE-NEXT: 1014: 04 00 00 00
|
||||
// (Got(function) - GotBase = 0x0
|
||||
// CODE-NEXT: 1014: 00 00 00 00
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
// REQUIRES: aarch64
|
||||
.globl a
|
||||
.type a,@object
|
||||
.comm a,4,4
|
||||
|
||||
.globl f
|
||||
.type f,@function
|
||||
f:
|
||||
adrp x0, :got:a
|
||||
ldr x0, [x0, #:got_lo12:a]
|
||||
|
||||
.global _start
|
||||
.type _start,@function
|
||||
_start:
|
||||
bl f
|
||||
.data
|
||||
.long _GLOBAL_OFFSET_TABLE_ - .
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11)
|
||||
// CHECK-NEXT: Value: 0x30090
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local (0x0)
|
||||
// CHECK-NEXT: Type: None (0x0)
|
||||
// CHECK-NEXT: Other [ (0x2)
|
||||
// CHECK-NEXT: STV_HIDDEN (0x2)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got
|
|
@ -0,0 +1,35 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
// REQUIRES: arm
|
||||
|
||||
// The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
|
||||
.globl a
|
||||
.type a,%object
|
||||
.comm a,4,4
|
||||
|
||||
.globl f
|
||||
.type f,%function
|
||||
f:
|
||||
ldr r2, .L1
|
||||
.L0:
|
||||
add r2, pc
|
||||
.L1:
|
||||
.word _GLOBAL_OFFSET_TABLE_ - (.L0+4)
|
||||
.word a(GOT)
|
||||
|
||||
.global _start
|
||||
.type _start,%function
|
||||
_start:
|
||||
bl f
|
||||
.data
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
|
||||
// CHECK-NEXT: Value: 0x3068
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local
|
||||
// CHECK-NEXT: Type: None
|
||||
// CHECK-NEXT: Other [ (0x2)
|
||||
// CHECK-NEXT: STV_HIDDEN (0x2)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got
|
|
@ -0,0 +1,31 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
// REQUIRES: x86
|
||||
|
||||
// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
|
||||
.globl a
|
||||
.type a,@object
|
||||
.comm a,4,4
|
||||
|
||||
.globl f
|
||||
.type f,@function
|
||||
f:
|
||||
addl $_GLOBAL_OFFSET_TABLE_, %eax
|
||||
movl a@GOT(%eax), %eax
|
||||
|
||||
.global _start
|
||||
.type _start,@function
|
||||
_start:
|
||||
addl $_GLOBAL_OFFSET_TABLE_, %eax
|
||||
calll f@PLT
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1)
|
||||
// CHECK-NEXT: Value: 0x306C
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local (0x0)
|
||||
// CHECK-NEXT: Type: None (0x0)
|
||||
// CHECK-NEXT: Other [ (0x2)
|
||||
// CHECK-NEXT: STV_HIDDEN (0x2)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got (0xA)
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
|
||||
// REQUIRES: mips
|
||||
|
||||
// The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
|
||||
|
||||
.globl a
|
||||
.hidden a
|
||||
.type a,@object
|
||||
.comm a,4,4
|
||||
|
||||
.globl f
|
||||
.type f,@function
|
||||
f:
|
||||
ld $v0,%got_page(a)($gp)
|
||||
daddiu $v0,$v0,%got_ofst(a)
|
||||
|
||||
.global _start
|
||||
.type _start,@function
|
||||
_start:
|
||||
lw $t0,%call16(f)($gp)
|
||||
.word _GLOBAL_OFFSET_TABLE_ - .
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1)
|
||||
// CHECK-NEXT: Value: 0x20000
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local (0x0)
|
||||
// CHECK-NEXT: Type: None (0x0)
|
||||
// CHECK-NEXT: Other [ (0x2)
|
||||
// CHECK-NEXT: STV_HIDDEN (0x2)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got (0x9)
|
|
@ -0,0 +1,31 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
// REQUIRES: x86
|
||||
|
||||
// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
|
||||
.globl a
|
||||
.type a,@object
|
||||
.comm a,4,4
|
||||
|
||||
.globl f
|
||||
.type f,@function
|
||||
f:
|
||||
movq a@GOTPCREL(%rip), %rax
|
||||
|
||||
.global _start
|
||||
.type _start,@function
|
||||
_start:
|
||||
callq f@PLT
|
||||
.data
|
||||
.long _GLOBAL_OFFSET_TABLE_ - .
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
|
||||
// CHECK-NEXT: Value: 0x30D8
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local
|
||||
// CHECK-NEXT: Type: None (0x0)
|
||||
// CHECK-NEXT: Other [
|
||||
// CHECK-NEXT: STV_HIDDEN
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got
|
|
@ -1,9 +1,14 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
|
||||
// RUN: ld.lld -shared %t -o %t2
|
||||
// RUN: llvm-readobj -t %t2 | FileCheck %s
|
||||
.long _GLOBAL_OFFSET_TABLE_
|
||||
.long _GLOBAL_OFFSET_TABLE_ - .
|
||||
|
||||
// CHECK: Name: _GLOBAL_OFFSET_TABLE_
|
||||
// CHECK-NEXT: Value:
|
||||
// CHECK-NEXT: Value: 0x2060
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local
|
||||
// CHECK-NEXT: Type: None
|
||||
// CHECK-NEXT: Other [ (0x2)
|
||||
// CHECK-NEXT: STV_HIDDEN (0x2)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Section: .got
|
||||
|
|
Loading…
Reference in New Issue