diff options
Diffstat (limited to 'lld')
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 8 | ||||
-rw-r--r-- | lld/test/ELF/Inputs/mips-64-got-load.s | 8 | ||||
-rw-r--r-- | lld/test/ELF/mips-64-got-overflow.s | 80 |
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 |