From the PowerPC ELFv2 ABI section 4.2.3. Global Offset Table.
```
The GOT consists of an 8-byte header that contains the TOC base (the first TOC
base when multiple TOCs are present), followed by an array of 8-byte addresses.
```
Due to the introduction of PC Relative code it is now possible to require a GOT
without having a .TOC. symbol in the object that is being linked. Since LLD uses
the .TOC. symbol to determine whether or not a GOT is required the GOT header is
not setup correctly and the 8-byte header is missing.
This patch allows the Power PC GOT setup to happen when an element is added to
the GOT instead of at the very begining. When this header is added a .TOC.
symbol is also added.
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D91426
// If ElfSym::globalOffsetTable is relative to .got and is referenced,
// increase numEntries by the number of entries used to emit
// ElfSym::globalOffsetTable.
- if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt)
+ // On PP64 we always add the header at the start.
+ if ((ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt) ||
+ config->emachine == EM_PPC64)
numEntries += target->gotHeaderEntriesNum;
}
}
void GotSection::finalizeContents() {
- size = numEntries * config->wordsize;
+ if (config->emachine == EM_PPC64 &&
+ numEntries <= target->gotHeaderEntriesNum && !ElfSym::globalOffsetTable)
+ size = 0;
+ else
+ size = numEntries * config->wordsize;
}
bool GotSection::isNeeded() const {
// We need to emit a GOT even if it's empty if there's a relocation that is
// relative to GOT(such as GOTOFFREL).
+
+ // On PPC64 we need to check that the number of entires is more than just the
+ // size of the header since the header is always added. A GOT with just the
+ // header may not actually be needed.
+ if (config->emachine == EM_PPC64)
+ return numEntries > target->gotHeaderEntriesNum || hasGotOffRel;
+
return numEntries || hasGotOffRel;
}
--- /dev/null
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=INPUT-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t.o | FileCheck --check-prefix=INPUT-ASM %s
+
+# RUN: ld.lld --shared %t.o --soname=t.so -o %t.so
+# RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=SO-REL %s
+# RUN: llvm-readelf -x .got %t.so | FileCheck --check-prefix=SO-GOT %s
+# RUN: llvm-readelf -s %t.so | FileCheck --check-prefix=SO-SYM %s
+
+## Test to make sure that the first element of a GOT section is the tocbase .TOC.
+
+# INPUT-REL: Section (3) .rela.text {
+# INPUT-REL-NEXT: 0x0 R_PPC64_GOT_PCREL34 glob_int 0x0
+# INPUT-REL-NEXT: 0x0 R_PPC64_PCREL_OPT - 0x8
+# INPUT-REL-NEXT: }
+
+# INPUT-ASM-LABEL: <test>:
+# INPUT-ASM: pld 3, 0(0), 1
+# INPUT-ASM-NEXT: lwa 3, 0(3)
+# INPUT-ASM-NEXT: blr
+
+# SO-REL: Relocation section '.rela.dyn'
+# SO-REL: 0000000000020390 0000000100000014 R_PPC64_GLOB_DAT 00000000000102d0 glob_int + 0
+
+# SO-GOT: Hex dump of section '.got':
+# SO-GOT: 0x00020388 88830200 00000000 00000000 00000000
+
+# SO-SYM: Symbol table '.symtab' contains 4 entries:
+# SO-SYM: 3: 00000000000102d0 4 NOTYPE GLOBAL DEFAULT 6 glob_int
+
+test:
+ pld 3, glob_int@got@pcrel(0), 1
+.Lpcrel0:
+ .reloc .Lpcrel0-8,R_PPC64_PCREL_OPT,.-(.Lpcrel0-8)
+ lwa 3, 0(3)
+ blr
+
+ .globl glob_int
+ .p2align 2
+glob_int:
+ .long 0
+ .size glob_int, 4
# RELOCS-NEXT: R_PPC64_GOT_DTPREL16_DS j 0x0
# RELOCS-NEXT: }
-## ha(i@got@dtprel) = (&.got[0] - (.got+0x8000) + 0x8000 >> 16) & 0xffff = 0
-## lo(i@got@dtprel) = &.got[0] - (.got+0x8000) & 0xffff = -32768
-## hi(j@got@dtprel) = (&.got[1] - (.got+0x8000) >> 16) & 0xffff = -1
-## j@got@dtprel = &.got[1] - (.got+0x8000) = -32760
+## Start with .got[1] as .got[0] is .TOC.
+## ha(i@got@dtprel) = (&.got[1] - (.got+0x8000) >> 16) & 0xffff = 0
+## lo(i@got@dtprel) = &.got[1] - (.got+0x8000) & 0xffff = -32760
+## hi(j@got@dtprel) = (&.got[2] - .got >> 16) & 0xffff = -1
+## j@got@dtprel = &.got[2] - (.got+0x8000) = -32752
# CHECK: addis 3, 2, 0
-# CHECK-NEXT: ld 3, -32768(3)
+# CHECK-NEXT: ld 3, -32760(3)
# CHECK-NEXT: addis 3, 2, -1
-# CHECK-NEXT: addi 3, 2, -32760
+# CHECK-NEXT: addi 3, 2, -32752
addis 3, 2, i@got@dtprel@ha
ld 3, i@got@dtprel@l(3)
.text
.section .text_low, "ax", %progbits
# CHECK-LABEL: <GlobIntPCRel>:
-# CHECK-NEXT: pld 3, 458928(0), 1
+# CHECK-NEXT: pld 3, 458936(0), 1
# CHECK-NEXT: lwa 3, 0(3)
+
# SYMBOL: Symbol table '.dynsym' contains 4 entries:
# SYMBOL: 00000000 0 NOTYPE GLOBAL DEFAULT UND glob_int
-# RELA: 100800b0 0000000100000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int + 0
+# RELA: 100800b8 0000000100000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int + 0
GlobIntPCRel:
pld 3, glob_int@got@PCREL(0), 1
lwa 3, 0(3)
blr
# CHECK-LABEL: <GlobIntPCRelOffset>:
-# CHECK-NEXT: pld 3, 458920(0), 1
+# CHECK-NEXT: pld 3, 458928(0), 1
# CHECK-NEXT: lwa 3, 8(3)
# SYMBOL: 00000000 0 NOTYPE GLOBAL DEFAULT UND glob_int8
-# RELA: 100800b8 0000000200000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int8 + 0
+# RELA: 100800c0 0000000200000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int8 + 0
GlobIntPCRelOffset:
pld 3, glob_int8@got@PCREL(0), 1
lwa 3, 8(3)
blr
# CHECK-LABEL: <GlobIntPCRelBigOffset>:
-# CHECK-NEXT: pld 3, 192(0), 1
+# CHECK-NEXT: pld 3, 200(0), 1
# CHECK-NEXT: lwa 3, 64(3)
# SYMBOL: 00000000 0 NOTYPE GLOBAL DEFAULT UND glob_int8_big
-# RELA: 100800c0 0000000300000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int8_big + 0
+# RELA: 100800c8 0000000300000014 R_PPC64_GLOB_DAT 0000000000000000 glob_int8_big + 0
+
+## Note that the first entry of the .got[0] should always be .TOC.
+# SYMBOL: Symbol table '.symtab' contains 8 entries:
+# SYMBOL: 1: 0000000010010000 0 NOTYPE LOCAL DEFAULT 6 GlobIntPCRel
+# SYMBOL: 2: 0000000010010010 0 NOTYPE LOCAL DEFAULT 6 GlobIntPCRelOffset
+# SYMBOL: 3: 0000000010080000 0 NOTYPE LOCAL DEFAULT 7 GlobIntPCRelBigOffset
.section .text_high, "ax", %progbits
GlobIntPCRelBigOffset:
pld 3, glob_int8_big@got@PCREL(0), 1
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
# GD-REL: .rela.dyn {
-# GD-REL-NEXT: 0x20548 R_PPC64_DTPMOD64 a 0x0
-# GD-REL-NEXT: 0x20550 R_PPC64_DTPREL64 a 0x0
-# GD-REL-NEXT: 0x20558 R_PPC64_DTPMOD64 b 0x0
-# GD-REL-NEXT: 0x20560 R_PPC64_DTPREL64 b 0x0
-# GD-REL-NEXT: 0x20568 R_PPC64_DTPMOD64 c 0x0
-# GD-REL-NEXT: 0x20570 R_PPC64_DTPREL64 c 0x0
+# GD-REL-NEXT: 0x20550 R_PPC64_DTPMOD64 a 0x0
+# GD-REL-NEXT: 0x20558 R_PPC64_DTPREL64 a 0x0
+# GD-REL-NEXT: 0x20560 R_PPC64_DTPMOD64 b 0x0
+# GD-REL-NEXT: 0x20568 R_PPC64_DTPREL64 b 0x0
+# GD-REL-NEXT: 0x20570 R_PPC64_DTPMOD64 c 0x0
+# GD-REL-NEXT: 0x20578 R_PPC64_DTPREL64 c 0x0
# GD-REL-NEXT: }
-## &DTPMOD(a) - .TOC. = &.got[0] - (.got+0x8000) = -32768
+## Start with .got[1] as .got[0] is the .TOC.
+## &DTPMOD(a) - .TOC. = &.got[1] - (.got+0x8000) = -32760
# GD: addis 3, 2, 0
-# GD-NEXT: addi 3, 3, -32768
+# GD-NEXT: addi 3, 3, -32760
# GD-NEXT: bl 0x10400
# GD-NEXT: ld 2, 24(1)
-## &DTPMOD(b) - .TOC. = &.got[2] - (.got+0x8000) = -32752
+## &DTPMOD(b) - .TOC. = &.got[3] - (.got+0x8000) = -32744
# GD-NEXT: addis 3, 2, 0
-# GD-NEXT: addi 3, 3, -32752
+# GD-NEXT: addi 3, 3, -32744
# GD-NEXT: bl 0x10400
# GD-NEXT: ld 2, 24(1)
-## &DTPMOD(b) - .TOC. = &.got[4] - (.got+0x8000) = -32736
-# GD-NEXT: li 3, -32736
+## &DTPMOD(b) - .TOC. = &.got[5] - (.got+0x8000) = -32728
+# GD-NEXT: li 3, -32728
# GD-NEXT: bl 0x10400
# GD-NEXT: ld 2, 24(1)
# LE-NEXT: addi 3, 3, -28656
# IE-REL: .rela.dyn {
-# IE-REL-NEXT: 0x10020418 R_PPC64_TPREL64 b 0x0
-# IE-REL-NEXT: 0x10020420 R_PPC64_TPREL64 c 0x0
+# IE-REL-NEXT: 0x10020420 R_PPC64_TPREL64 b 0x0
+# IE-REL-NEXT: 0x10020428 R_PPC64_TPREL64 c 0x0
# IE-REL-NEXT: }
## a is relaxed to use LE.
# IE-NEXT: addis 3, 13, 0
# IE-NEXT: nop
# IE-NEXT: addi 3, 3, -28664
-## &DTPMOD(b) - .TOC. = &.got[0] - (.got+0x8000) = -32768
+## &DTPMOD(b) - .TOC. = &.got[1] - (.got+0x8000) = -32760
# IE-NEXT: addis 3, 2, 0
-# IE-NEXT: ld 3, -32768(3)
+# IE-NEXT: ld 3, -32760(3)
# IE-NEXT: nop
# IE-NEXT: add 3, 3, 13
-## &DTPMOD(c) - .TOC. = &.got[1] - (.got+0x8000) = -32760
+## &DTPMOD(c) - .TOC. = &.got[2] - (.got+0x8000) = -32752
## r0 is wrong. R_PPC64_GOT_TLS16 cannot be relaxed to IE but the behavior is
## consistent with ld.bfd
-# IE-NEXT: ld 3, -32760(0)
+# IE-NEXT: ld 3, -32752(0)
# IE-NEXT: nop
# IE-NEXT: add 3, 3, 13
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
# IE-REL: .rela.dyn {
-# IE-REL-NEXT: 0x204A0 R_PPC64_TPREL64 c 0x0
-# IE-REL-NEXT: 0x204A8 R_PPC64_TPREL64 s 0x0
-# IE-REL-NEXT: 0x204B0 R_PPC64_TPREL64 i 0x0
-# IE-REL-NEXT: 0x204B8 R_PPC64_TPREL64 l 0x0
+# IE-REL-NEXT: 0x204A8 R_PPC64_TPREL64 c 0x0
+# IE-REL-NEXT: 0x204B0 R_PPC64_TPREL64 s 0x0
+# IE-REL-NEXT: 0x204B8 R_PPC64_TPREL64 i 0x0
+# IE-REL-NEXT: 0x204C0 R_PPC64_TPREL64 l 0x0
# IE-REL-NEXT: }
# INPUT-REL: R_PPC64_GOT_TPREL16_HA c 0x0
# INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS c 0x0
# INPUT-REL: R_PPC64_TLS c 0x0
-## &.got[0] - .TOC. = -32768
+## &.got[1] - .TOC. = -32760
# IE-LABEL: <test1>:
# IE-NEXT: addis 3, 2, 0
-# IE-NEXT: ld 3, -32768(3)
+# IE-NEXT: ld 3, -32760(3)
# IE-NEXT: lbzx 3, 3, 13
# LE-LABEL: <test1>:
# LE-NEXT: nop
# INPUT-REL: R_PPC64_GOT_TPREL16_HA s 0x0
# INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS s 0x0
# INPUT-REL: R_PPC64_TLS s 0x0
-## &.got[1] - .TOC. = -32760
+## &.got[2] - .TOC. = -32752
# IE-LABEL: <test2>:
# IE-NEXT: addis 3, 2, 0
-# IE-NEXT: ld 3, -32760(3)
+# IE-NEXT: ld 3, -32752(3)
# IE-NEXT: lhzx 3, 3, 13
# LE-LABEL: <test2>:
# LE-NEXT: nop
# INPUT-REL: R_PPC64_GOT_TPREL16_HA i 0x0
# INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS i 0x0
# INPUT-REL: R_PPC64_TLS i 0x0
-## &.got[2] - .TOC. = -32752
+## &.got[3] - .TOC. = -32744
# IE-LABEL: <test3>:
# IE-NEXT: addis 3, 2, 0
-# IE-NEXT: ld 3, -32752(3)
+# IE-NEXT: ld 3, -32744(3)
# IE-NEXT: lwzx 3, 3, 13
# LE-LABEL: <test3>:
# LE-NEXT: nop
# INPUT-REL: R_PPC64_GOT_TPREL16_HA l 0x0
# INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS l 0x0
# INPUT-REL: R_PPC64_TLS l 0x0
-## &.got[3] - .TOC. = -32744
+## &.got[4] - .TOC. = -32736
# IE-LABEL: <test4>:
# IE-NEXT: addis 3, 2, 0
-# IE-NEXT: ld 3, -32744(3)
+# IE-NEXT: ld 3, -32736(3)
# IE-NEXT: ldx 3, 3, 13
# LE-LABEL: <test4>:
# LE-NEXT: nop
## .got+16: DTPMOD/DTPREL for _TLS_MODULE_BASE_ is 1 and 0, respectively.
## .got+32: TPOFFSET for x = st_value-0x7000
# HEX: section '.got':
-# HEX-NEXT: [[#%x,IGNORE:]] 01000000 00000000 0080ffff ffffffff
-# HEX-NEXT: [[#%x,IGNORE:]] 01000000 00000000 00000000 00000000
-# HEX-NEXT: [[#%x,IGNORE:]] 0090ffff ffffffff
+# HEX-NEXT: [[#%x,IGNORE:]] 50820210 00000000 01000000 00000000
+# HEX-NEXT: [[#%x,IGNORE:]] 0080ffff ffffffff 01000000 00000000
+# HEX-NEXT: [[#%x,IGNORE:]] 00000000 00000000 0090ffff ffffffff
## .TOC.-32768 = (.got+0x8000)-32768 = .got
# DIS-LABEL: <GeneralDynamic>:
# DIS-NEXT: addis 3, 2, 0
-# DIS-NEXT: addi 3, 3, -32768
+# DIS-NEXT: addi 3, 3, -32760
# DIS-NEXT: bl [[#%x,TGA:]]
# DIS-LABEL: <GeneralDynamic_NOTOC>:
# DIS-NEXT: addis 3, 2, 0
-# DIS-NEXT: addi 3, 3, -32768
+# DIS-NEXT: addi 3, 3, -32760
# DIS-NEXT: bl [[#TGA]]
## LocalDynamic references _TLS_MODULE_BASE_.
## .TOC.-32752 = (.got+0x8000)-32752 = .got+16
# DIS-LABEL: <LocalDynamic>:
# DIS-NEXT: addis 3, 2, 0
-# DIS-NEXT: addi 3, 3, -32752
+# DIS-NEXT: addi 3, 3, -32744
# DIS-NEXT: bl [[#TGA]]
# DIS-LABEL: <LocalDynamic_NOTOC>:
# DIS-NEXT: addis 3, 2, 0
-# DIS-NEXT: addi 3, 3, -32752
+# DIS-NEXT: addi 3, 3, -32744
# DIS-NEXT: bl [[#TGA]]
## Technically we don't have to disable IE to LE relaxation,
## but disabling it for implementation simplicity does not hurt.
# DIS-LABEL: <InitialExec>:
# DIS-NEXT: addis 3, 2, 0
-# DIS-NEXT: ld 3, -32736(3)
+# DIS-NEXT: ld 3, -32728(3)
# DIS-NEXT: add 3, 3, 13
#--- a.s
#--- asm
# GD-RELOC: Relocation section '.rela.dyn' at offset 0x100b8 contains 4 entries:
-# GD-RELOC: 0000000001001170 0000000100000044 R_PPC64_DTPMOD64 0000000000000000 x + 0
-# GD-RELOC: 0000000001001178 000000010000004e R_PPC64_DTPREL64 0000000000000000 x + 0
-# GD-RELOC: 0000000001001180 0000000300000044 R_PPC64_DTPMOD64 0000000000000000 y + 0
-# GD-RELOC: 0000000001001188 000000030000004e R_PPC64_DTPREL64 0000000000000000 y + 0
+# GD-RELOC: 0000000001001178 0000000100000044 R_PPC64_DTPMOD64 0000000000000000 x + 0
+# GD-RELOC: 0000000001001180 000000010000004e R_PPC64_DTPREL64 0000000000000000 x + 0
+# GD-RELOC: 0000000001001188 0000000300000044 R_PPC64_DTPMOD64 0000000000000000 y + 0
+# GD-RELOC: 0000000001001190 000000030000004e R_PPC64_DTPREL64 0000000000000000 y + 0
# GD-SYM: Symbol table '.dynsym' contains 4 entries:
# GD-SYM: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
# GDTOIE-RELOC: Relocation section '.rela.dyn' at offset 0x{{.*}} contains 2 entries:
-# GDTOIE-RELOC: 00000000010010e0 0000000100000049 R_PPC64_TPREL64 0000000000000000 x + 0
-# GDTOIE-RELOC: 00000000010010e8 0000000300000049 R_PPC64_TPREL64 0000000000000000 y + 0
+# GDTOIE-RELOC: 00000000010010e8 0000000100000049 R_PPC64_TPREL64 0000000000000000 x + 0
+# GDTOIE-RELOC: 00000000010010f0 0000000300000049 R_PPC64_TPREL64 0000000000000000 y + 0
# GDTOIE-SYM: Symbol table '.dynsym' contains 4 entries:
# GDTOIE-SYM: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
# GDTOLE-SYM: 0000000000000004 0 TLS GLOBAL DEFAULT 3 y
# GD-LABEL: <GDTwoVal>:
-# GD-NEXT: paddi 3, 0, 368, 1
+# GD-NEXT: paddi 3, 0, 376, 1
# GD-NEXT: bl
-# GD-NEXT: paddi 3, 0, 372, 1
+# GD-NEXT: paddi 3, 0, 380, 1
# GD-NEXT: bl
# GD-NEXT: blr
# GDTOIE-LABEL: <GDTwoVal>:
-# GDTOIE-NEXT: pld 3, 224(0), 1
+# GDTOIE-NEXT: pld 3, 232(0), 1
# GDTOIE-NEXT: add 3, 3, 13
-# GDTOIE-NEXT: pld 3, 220(0), 1
+# GDTOIE-NEXT: pld 3, 228(0), 1
# GDTOIE-NEXT: add 3, 3, 13
# GDTOIE-NEXT: blr
# GDTOLE-LABEL: <GDTwoVal>:
#--- asm
# IE-RELOC: Relocation section '.rela.dyn' at offset 0x10090 contains 2 entries:
-# IE-RELOC: 00000000010040d8 0000000100000049 R_PPC64_TPREL64 0000000000000000 x + 0
-# IE-RELOC: 00000000010040e0 0000000200000049 R_PPC64_TPREL64 0000000000000000 y + 0
+# IE-RELOC: 00000000010040e0 0000000100000049 R_PPC64_TPREL64 0000000000000000 x + 0
+# IE-RELOC: 00000000010040e8 0000000200000049 R_PPC64_TPREL64 0000000000000000 y + 0
# IE-SYM: Symbol table '.dynsym' contains 3 entries:
# IE-SYM: 1: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
# LE-GOT: could not find section '.got'
# IE-LABEL: <IEAddr>:
-# IE-NEXT: pld 3, 12504(0), 1
+# IE-NEXT: pld 3, 12512(0), 1
# IE-NEXT: add 3, 3, 13
# IE-NEXT: blr
# LE-LABEL: <IEAddr>:
blr
# IE-LABEL: <IEAddrCopy>:
-# IE-NEXT: pld 3, 12488(0), 1
+# IE-NEXT: pld 3, 12496(0), 1
# IE-NEXT: add 4, 3, 13
# IE-NEXT: blr
# LE-LABEL: <IEAddrCopy>:
blr
# IE-LABEL: <IEVal>:
-# IE-NEXT: pld 3, 8408(0), 1
+# IE-NEXT: pld 3, 8416(0), 1
# IE-NEXT: lwzx 3, 3, 13
# IE-NEXT: blr
# LE-LABEL: <IEVal>:
blr
# IE-LABEL: <IETwoVal>:
-# IE-NEXT: pld 3, 4312(0), 1
-# IE-NEXT: pld 4, 4312(0), 1
+# IE-NEXT: pld 3, 4320(0), 1
+# IE-NEXT: pld 4, 4320(0), 1
# IE-NEXT: lwzx 3, 3, 13
# IE-NEXT: lwzx 4, 4, 13
# IE-NEXT: blr
blr
# IE-LABEL: <IEIncrementVal>:
-# IE-NEXT: pld 4, 224(0), 1
+# IE-NEXT: pld 4, 232(0), 1
# IE-NEXT: lwzx 3, 4, 13
# IE-NEXT: stwx 3, 4, 13
# IE-NEXT: blr