summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/SyntheticSections.cpp8
-rw-r--r--lld/test/ELF/Inputs/mips-64-got-load.s8
-rw-r--r--lld/test/ELF/mips-64-got-overflow.s80
3 files changed, 95 insertions, 1 deletions
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index cbcf6bf39a1..38859e1650b 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -872,7 +872,13 @@ template <class ELFT> void MipsGotSection::build() {
if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
File->MipsGotIndex = 0;
} else {
- if (!tryMergeGots(MergedGots.back(), SrcGot, false)) {
+ // If this is the first time we failed to merge with the primary GOT,
+ // MergedGots.back() will also be the primary GOT. We must make sure not
+ // to try to merge again with IsPrimary=false, as otherwise, if the
+ // inputs are just right, we could allow the primary GOT to become 1 or 2
+ // words too big due to ignoring the header size.
+ if (MergedGots.size() == 1 ||
+ !tryMergeGots(MergedGots.back(), SrcGot, false)) {
MergedGots.emplace_back();
std::swap(MergedGots.back(), SrcGot);
}
diff --git a/lld/test/ELF/Inputs/mips-64-got-load.s b/lld/test/ELF/Inputs/mips-64-got-load.s
new file mode 100644
index 00000000000..dffc6fb335c
--- /dev/null
+++ b/lld/test/ELF/Inputs/mips-64-got-load.s
@@ -0,0 +1,8 @@
+ .text
+ .global foo1
+foo1:
+ ld $2, %got_disp(local1)($gp)
+
+ .bss
+local1:
+ .word 0
diff --git a/lld/test/ELF/mips-64-got-overflow.s b/lld/test/ELF/mips-64-got-overflow.s
new file mode 100644
index 00000000000..5de71b1b366
--- /dev/null
+++ b/lld/test/ELF/mips-64-got-overflow.s
@@ -0,0 +1,80 @@
+# REQUIRES: mips
+# Check the primary GOT cannot be made to overflow
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: %p/Inputs/mips-64-got-load.s -o %t1.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t2.so.o
+# RUN: ld.lld -shared -mips-got-size 32 %t1.so.o %t2.so.o -o %t-sgot.so
+# RUN: ld.lld -shared -mips-got-size 24 %t1.so.o %t2.so.o -o %t-mgot.so
+# RUN: llvm-readobj -r -dt -mips-plt-got %t-sgot.so | FileCheck -check-prefix=SGOT %s
+# RUN: llvm-readobj -r -dt -mips-plt-got %t-mgot.so | FileCheck -check-prefix=MGOT %s
+
+# SGOT: Primary GOT {
+# SGOT-NEXT: Canonical gp value: 0x27FF0
+# SGOT-NEXT: Reserved entries [
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32752
+# SGOT-NEXT: Initial: 0x0
+# SGOT-NEXT: Purpose: Lazy resolver
+# SGOT-NEXT: }
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32744
+# SGOT-NEXT: Initial: 0x80000000
+# SGOT-NEXT: Purpose: Module pointer (GNU extension)
+# SGOT-NEXT: }
+# SGOT-NEXT: ]
+# SGOT-NEXT: Local entries [
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32736
+# SGOT-NEXT: Initial: 0x20020
+# SGOT-NEXT: }
+# SGOT-NEXT: Entry {
+# SGOT-NEXT: Address:
+# SGOT-NEXT: Access: -32728
+# SGOT-NEXT: Initial: 0x20030
+# SGOT-NEXT: }
+# SGOT-NEXT: ]
+# SGOT-NEXT: Global entries [
+# SGOT-NEXT: ]
+# SGOT-NEXT: Number of TLS and multi-GOT entries: 0
+# SGOT-NEXT: }
+
+# MGOT: Primary GOT {
+# MGOT-NEXT: Canonical gp value: 0x27FF0
+# MGOT-NEXT: Reserved entries [
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32752
+# MGOT-NEXT: Initial: 0x0
+# MGOT-NEXT: Purpose: Lazy resolver
+# MGOT-NEXT: }
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32744
+# MGOT-NEXT: Initial: 0x80000000
+# MGOT-NEXT: Purpose: Module pointer (GNU extension)
+# MGOT-NEXT: }
+# MGOT-NEXT: ]
+# MGOT-NEXT: Local entries [
+# MGOT-NEXT: Entry {
+# MGOT-NEXT: Address:
+# MGOT-NEXT: Access: -32736
+# MGOT-NEXT: Initial: 0x20020
+# MGOT-NEXT: }
+# MGOT-NEXT: ]
+# MGOT-NEXT: Global entries [
+# MGOT-NEXT: ]
+# MGOT-NEXT: Number of TLS and multi-GOT entries: 1
+# MGOT-NEXT: }
+
+ .text
+ .global foo2
+foo2:
+ ld $2, %got_disp(local2)($gp)
+
+ .bss
+local2:
+ .word 0