From 6a4eb75c46dc11578c4dd47db82c7a69a8f65839 Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Thu, 8 Dec 2016 06:19:47 +0000 Subject: [PATCH] [ELF][MIPS] Make _gp, _gp_disp, __gnu_local_gp global symbols These MIPS specific symbols should be global because in general they can have an arbitrary value. By default this value is a fixed offset from .got section. This patch adds more checks to the mips-gp-local.s test case but marks it as XFAIL because LLD does not allow redefinition of absolute symbols value by a linker script. This should be fixed by D27276. Differential revision: https://reviews.llvm.org/D27524 llvm-svn: 289025 --- lld/ELF/Relocations.cpp | 5 +++ lld/ELF/SymbolTable.cpp | 7 ++-- lld/ELF/SymbolTable.h | 3 +- lld/ELF/Symbols.h | 4 +- lld/ELF/Target.cpp | 8 ++-- lld/ELF/Writer.cpp | 28 ++++++++----- lld/test/ELF/basic-mips.s | 2 +- lld/test/ELF/mips-64-disp.s | 2 +- lld/test/ELF/mips-64-got.s | 2 +- lld/test/ELF/mips-64-gprel-so.s | 2 +- lld/test/ELF/mips-64-rels.s | 2 +- lld/test/ELF/mips-got-relocs.s | 4 +- lld/test/ELF/mips-gp-disp.s | 2 +- lld/test/ELF/mips-gp-ext.s | 76 ++++++++++++++++++++++++---------- lld/test/ELF/mips-gp-local.s | 2 +- lld/test/ELF/mips-gprel32-relocs-gp0.s | 2 +- lld/test/ELF/mips-gprel32-relocs.s | 2 +- lld/test/ELF/mips-hilo-gp-disp.s | 4 +- lld/test/ELF/mips-n32-rels.s | 2 +- 19 files changed, 102 insertions(+), 57 deletions(-) diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 4f39f3c..a394569 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -348,9 +348,14 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, // resolve to the image base. This is a little strange, but it allows us to // link function calls to such symbols. Normally such a call will be guarded // with a comparison, which will load a zero from the GOT. + // Another special case is MIPS _gp_disp symbol which represents offset + // between start of a function and '_gp' value and defined as absolute just + // to simplify the code. if (AbsVal && RelE) { if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return true; + if (&Body == ElfSym::MipsGpDisp) + return true; error(S.getLocation(RelOff) + ": relocation " + toString(Type) + " cannot refer to absolute symbol '" + toString(Body) + "' defined in " + toString(Body.File)); diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 2b0bf42..0f79d34 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -127,9 +127,10 @@ template void SymbolTable::addCombinedLTOObject() { template DefinedRegular *SymbolTable::addAbsolute(StringRef Name, - uint8_t Visibility) { - Symbol *Sym = addRegular(Name, Visibility, STT_NOTYPE, 0, 0, STB_GLOBAL, - nullptr, nullptr); + uint8_t Visibility, + uint8_t Type) { + Symbol *Sym = + addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Type, nullptr, nullptr); return cast>(Sym->body()); } diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 7ffab38..35b602e 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -50,7 +50,8 @@ public: ArrayRef *> getSharedFiles() const { return SharedFiles; } DefinedRegular *addAbsolute(StringRef Name, - uint8_t Visibility = llvm::ELF::STV_HIDDEN); + uint8_t Visibility = llvm::ELF::STV_HIDDEN, + uint8_t Type = llvm::ELF::STB_GLOBAL); DefinedRegular *addIgnored(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 3f4b682..42194eb 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -351,7 +351,7 @@ template struct ElfSym { // The content for _gp_disp/__gnu_local_gp symbols for MIPS target. static DefinedRegular *MipsGpDisp; static DefinedRegular *MipsLocalGp; - static SymbolBody *MipsGp; + static DefinedRegular *MipsGp; }; template DefinedRegular *ElfSym::EhdrStart; @@ -363,7 +363,7 @@ template DefinedRegular *ElfSym::End; template DefinedRegular *ElfSym::End2; template DefinedRegular *ElfSym::MipsGpDisp; template DefinedRegular *ElfSym::MipsLocalGp; -template SymbolBody *ElfSym::MipsGp; +template DefinedRegular *ElfSym::MipsGp; // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 4c12d78..9f743d4 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -1972,10 +1972,10 @@ RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, case R_MIPS_HI16: case R_MIPS_LO16: case R_MIPS_GOT_OFST: - // MIPS _gp_disp designates offset between start of function and 'gp' - // pointer into GOT. __gnu_local_gp is equal to the current value of - // the 'gp'. Therefore any relocations against them do not require - // dynamic relocation. + // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate + // offset between start of function and 'gp' value which by default + // equal to the start of .got section. In that case we consider these + // relocations as relative. if (&S == ElfSym::MipsGpDisp) return R_PC; return R_ABS; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index ce1e533..dbaa593 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -662,23 +662,28 @@ template void Writer::addRelIpltSymbols() { template void Writer::addReservedSymbols() { if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer - // so that it points to an absolute address which is relative to GOT. - // Default offset is 0x7ff0. + // so that it points to an absolute address which by default is relative + // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - ElfSym::MipsGp = addRegular("_gp", In::MipsGot, 0x7ff0)->body(); + ElfSym::MipsGp = + Symtab::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and 'gp' pointer into GOT. - if (Symbol *S = addOptionalRegular("_gp_disp", In::MipsGot, 0)) - ElfSym::MipsGpDisp = cast>(S->body()); + // start of function and 'gp' pointer into GOT. To simplify relocation + // calculation we assign _gp value to it and calculate corresponding + // relocations as relative to this value. + if (Symtab::X->find("_gp_disp")) + ElfSym::MipsGpDisp = + Symtab::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html - if (Symbol *S = addOptionalRegular("__gnu_local_gp", In::MipsGot, 0)) - ElfSym::MipsLocalGp = cast>(S->body()); + if (Symtab::X->find("__gnu_local_gp")) + ElfSym::MipsLocalGp = + Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol @@ -1473,11 +1478,12 @@ template void Writer::fixAbsoluteSymbols() { // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS) { - uintX_t GpDisp = In::MipsGot->getGp() - In::MipsGot->getVA(); + if (!ElfSym::MipsGp->Value) + ElfSym::MipsGp->Value = In::MipsGot->getVA() + 0x7ff0; if (ElfSym::MipsGpDisp) - ElfSym::MipsGpDisp->Value = GpDisp; + ElfSym::MipsGpDisp->Value = ElfSym::MipsGp->Value; if (ElfSym::MipsLocalGp) - ElfSym::MipsLocalGp->Value = GpDisp; + ElfSym::MipsLocalGp->Value = ElfSym::MipsGp->Value; } } diff --git a/lld/test/ELF/basic-mips.s b/lld/test/ELF/basic-mips.s index 2cc86c1..dc640ed 100644 --- a/lld/test/ELF/basic-mips.s +++ b/lld/test/ELF/basic-mips.s @@ -228,7 +228,7 @@ __start: # CHECK-NEXT: Other [ (0x2) # CHECK-NEXT: STV_HIDDEN (0x2) # CHECK-NEXT: ] -# CHECK-NEXT: Section: .got +# CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: __start diff --git a/lld/test/ELF/mips-64-disp.s b/lld/test/ELF/mips-64-disp.s index 1c66ba4..9556807 100644 --- a/lld/test/ELF/mips-64-disp.s +++ b/lld/test/ELF/mips-64-disp.s @@ -18,7 +18,7 @@ # CHECK-NEXT: 20010: 24 42 80 38 addiu $2, $2, -32712 # CHECK: 0000000000020014 .text 00000000 foo -# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp +# CHECK: 0000000000037ff0 *ABS* 00000000 .hidden _gp # CHECK: 0000000000020000 .text 00000000 __start # CHECK: 0000000000000000 g F *UND* 00000000 foo1a diff --git a/lld/test/ELF/mips-64-got.s b/lld/test/ELF/mips-64-got.s index b120abb..f489b44 100644 --- a/lld/test/ELF/mips-64-got.s +++ b/lld/test/ELF/mips-64-got.s @@ -19,7 +19,7 @@ # CHECK-NEXT: 20010: 24 42 80 38 addiu $2, $2, -32712 # CHECK: 0000000000020018 .text 00000000 foo -# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp +# CHECK: 0000000000037ff0 *ABS* 00000000 .hidden _gp # CHECK: 0000000000020000 .text 00000000 __start # CHECK: 0000000000020014 .text 00000000 bar diff --git a/lld/test/ELF/mips-64-gprel-so.s b/lld/test/ELF/mips-64-gprel-so.s index 437238e..a390ec0 100644 --- a/lld/test/ELF/mips-64-gprel-so.s +++ b/lld/test/ELF/mips-64-gprel-so.s @@ -12,7 +12,7 @@ # CHECK-NEXT: 10004: 03 99 e0 2d daddu $gp, $gp, $25 # CHECK-NEXT: 10008: 67 9c 7f f0 daddiu $gp, $gp, 32752 -# CHECK: 0000000000027ff0 .got 00000000 .hidden _gp +# CHECK: 0000000000027ff0 *ABS* 00000000 .hidden _gp # CHECK: 0000000000010000 .text 00000000 foo .text diff --git a/lld/test/ELF/mips-64-rels.s b/lld/test/ELF/mips-64-rels.s index 7126afc..b9a3ee7 100644 --- a/lld/test/ELF/mips-64-rels.s +++ b/lld/test/ELF/mips-64-rels.s @@ -24,7 +24,7 @@ # ^-- 0x20004 - 0x37ff0 = 0xfffffffffffe8014 # CHECK: 0000000000020004 .text 00000000 loc -# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp +# CHECK: 0000000000037ff0 *ABS* 00000000 .hidden _gp # CHECK: 0000000000020000 .text 00000000 __start # REL: Relocations [ diff --git a/lld/test/ELF/mips-got-relocs.s b/lld/test/ELF/mips-got-relocs.s index c44cf90..19c0db4 100644 --- a/lld/test/ELF/mips-got-relocs.s +++ b/lld/test/ELF/mips-got-relocs.s @@ -47,7 +47,7 @@ v1: # EXE_SYM: Sections: # EXE_SYM: .got 0000000c 0000000000030000 DATA # EXE_SYM: SYMBOL TABLE: -# EXE_SYM: 00037ff0 .got 00000000 .hidden _gp +# EXE_SYM: 00037ff0 *ABS* 00000000 .hidden _gp # ^-- .got + GP offset (0x7ff0) # EXE_SYM: 00040000 g .data 00000004 v1 @@ -71,7 +71,7 @@ v1: # DSO_SYM: Sections: # DSO_SYM: .got 0000000c 0000000000020000 DATA # DSO_SYM: SYMBOL TABLE: -# DSO_SYM: 00027ff0 .got 00000000 .hidden _gp +# DSO_SYM: 00027ff0 *ABS* 00000000 .hidden _gp # ^-- .got + GP offset (0x7ff0) # DSO_SYM: 00030000 g .data 00000004 v1 diff --git a/lld/test/ELF/mips-gp-disp.s b/lld/test/ELF/mips-gp-disp.s index 7a0fd64..62a2b10 100644 --- a/lld/test/ELF/mips-gp-disp.s +++ b/lld/test/ELF/mips-gp-disp.s @@ -24,7 +24,7 @@ # DIS-NEXT: 10000: 3c 08 00 01 lui $8, 1 # DIS-NEXT: 10004: 21 08 7f f0 addi $8, $8, 32752 # ^-- 0x37ff0 & 0xffff -# DIS: 00027ff0 .got 00000000 .hidden _gp +# DIS: 00027ff0 *ABS* 00000000 .hidden _gp # REL: Relocations [ # REL-NEXT: ] diff --git a/lld/test/ELF/mips-gp-ext.s b/lld/test/ELF/mips-gp-ext.s index 780489a1..b6c49e0 100644 --- a/lld/test/ELF/mips-gp-ext.s +++ b/lld/test/ELF/mips-gp-ext.s @@ -1,35 +1,67 @@ # Check that the linker use a value of _gp symbol defined # in a linker script to calculate GOT relocations. +# FIXME: This test is xfailed because it depends on D27276 patch +# that enables absolute symbols redefinition by a linker's script. +# XFAIL: * + # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o + # RUN: echo "SECTIONS { \ # RUN: .text : { *(.text) } \ # RUN: _gp = . + 0x100; \ -# RUN: .got : { *(.got) } }" > %t.script -# RUN: ld.lld -shared -o %t.so --script %t.script %t.o -# RUN: llvm-objdump -s -t %t.so | FileCheck %s +# RUN: .got : { *(.got) } }" > %t.rel.script +# RUN: ld.lld -shared -o %t.rel.so --script %t.rel.script %t.o +# RUN: llvm-objdump -s -t %t.rel.so | FileCheck --check-prefix=REL %s + +# RUN: echo "SECTIONS { \ +# RUN: .text : { *(.text) } \ +# RUN: _gp = 0x200; \ +# RUN: .got : { *(.got) } }" > %t.abs.script +# RUN: ld.lld -shared -o %t.abs.so --script %t.abs.script %t.o +# RUN: llvm-objdump -s -t %t.abs.so | FileCheck --check-prefix=ABS %s # REQUIRES: mips -# CHECK: Contents of section .text: -# CHECK-NEXT: 0000 3c080000 2108010c 8f82ffe4 -# ^-- %hi(_gp_disp) -# ^-- %lo(_gp_disp) -# ^-- 8 - (0x10c - 0xe8) -# G - (GP - .got) - -# CHECK: Contents of section .reginfo: -# CHECK-NEXT: 0028 10000104 00000000 00000000 00000000 -# CHECK-NEXT: 0038 00000000 0000010c -# ^-- _gp - -# CHECK: Contents of section .data: -# CHECK-NEXT: 0100 fffffef4 -# ^-- 0-0x10c - -# CHECK: 00000000 .text 00000000 foo -# CHECK: 0000010c .got 00000000 .hidden _gp_disp -# CHECK: 0000010c .text 00000000 .hidden _gp +# REL: Contents of section .text: +# REL-NEXT: 0000 3c080000 2108010c 8f82ffe4 +# ^-- %hi(_gp_disp) +# ^-- %lo(_gp_disp) +# ^-- 8 - (0x10c - 0xe8) +# G - (GP - .got) + +# REL: Contents of section .reginfo: +# REL-NEXT: 0028 10000104 00000000 00000000 00000000 +# REL-NEXT: 0038 00000000 0000010c +# ^-- _gp + +# REL: Contents of section .data: +# REL-NEXT: 0100 fffffef4 +# ^-- 0-0x10c + +# REL: 00000000 .text 00000000 foo +# REL: 0000010c *ABS* 00000000 .hidden _gp_disp +# REL: 0000010c *ABS* 00000000 .hidden _gp + +# ABS: Contents of section .text: +# ABS-NEXT: 0000 3c080000 21080200 8f82fef0 +# ^-- %hi(_gp_disp) +# ^-- %lo(_gp_disp) +# ^-- 8 - (0x200 - 0xe8) +# G - (GP - .got) + +# ABS: Contents of section .reginfo: +# ABS-NEXT: 0028 10000104 00000000 00000000 00000000 +# ABS-NEXT: 0038 00000000 00000200 +# ^-- _gp + +# ABS: Contents of section .data: +# ABS-NEXT: 0100 fffffe00 +# ^-- 0-0x200 + +# ABS: 00000000 .text 00000000 foo +# ABS: 00000200 *ABS* 00000000 .hidden _gp_disp +# ABS: 00000200 *ABS* 00000000 .hidden _gp .text foo: diff --git a/lld/test/ELF/mips-gp-local.s b/lld/test/ELF/mips-gp-local.s index 8bb3c23..b77dbb8 100644 --- a/lld/test/ELF/mips-gp-local.s +++ b/lld/test/ELF/mips-gp-local.s @@ -11,7 +11,7 @@ # CHECK-NEXT: 20000: 3c 08 00 03 lui $8, 3 # CHECK-NEXT: 20004: 21 08 7f f0 addi $8, $8, 32752 -# CHECK: 00037ff0 .got 00000000 .hidden _gp +# CHECK: 00037ff0 *ABS* 00000000 .hidden _gp .text .globl __start diff --git a/lld/test/ELF/mips-gprel32-relocs-gp0.s b/lld/test/ELF/mips-gprel32-relocs-gp0.s index 05ca336..e71f885 100644 --- a/lld/test/ELF/mips-gprel32-relocs-gp0.s +++ b/lld/test/ELF/mips-gprel32-relocs-gp0.s @@ -29,7 +29,7 @@ # DUMP: SYMBOL TABLE: # DUMP: 00010008 .text 00000000 bar # DUMP: 00010004 .text 00000000 foo -# DUMP: 00027ff0 .got 00000000 .hidden _gp +# DUMP: 00027ff0 *ABS* 00000000 .hidden _gp # ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value diff --git a/lld/test/ELF/mips-gprel32-relocs.s b/lld/test/ELF/mips-gprel32-relocs.s index fa1c5cf..993596d 100644 --- a/lld/test/ELF/mips-gprel32-relocs.s +++ b/lld/test/ELF/mips-gprel32-relocs.s @@ -28,4 +28,4 @@ v1: # CHECK: SYMBOL TABLE: # CHECK: 00010008 .text 00000000 bar # CHECK: 00010004 .text 00000000 foo -# CHECK: 00027ff0 .got 00000000 .hidden _gp +# CHECK: 00027ff0 *ABS* 00000000 .hidden _gp diff --git a/lld/test/ELF/mips-hilo-gp-disp.s b/lld/test/ELF/mips-hilo-gp-disp.s index 37cf90d..16eab06 100644 --- a/lld/test/ELF/mips-hilo-gp-disp.s +++ b/lld/test/ELF/mips-hilo-gp-disp.s @@ -34,7 +34,7 @@ bar: # EXE: SYMBOL TABLE: # EXE: 0002000c .text 00000000 bar -# EXE: 00037ff0 .got 00000000 .hidden _gp +# EXE: 00037ff0 *ABS* 00000000 .hidden _gp # EXE: 00020000 .text 00000000 __start # SO: Disassembly of section .text: @@ -51,5 +51,5 @@ bar: # SO: SYMBOL TABLE: # SO: 0001000c .text 00000000 bar -# SO: 00027ff0 .got 00000000 .hidden _gp +# SO: 00027ff0 *ABS* 00000000 .hidden _gp # SO: 00010000 .text 00000000 __start diff --git a/lld/test/ELF/mips-n32-rels.s b/lld/test/ELF/mips-n32-rels.s index 633995b..4cf7288 100644 --- a/lld/test/ELF/mips-n32-rels.s +++ b/lld/test/ELF/mips-n32-rels.s @@ -42,7 +42,7 @@ # ^-- loc # CHECK: 00020004 .text 00000000 loc -# CHECK: 00037ff0 .got 00000000 .hidden _gp +# CHECK: 00037ff0 *ABS* 00000000 .hidden _gp # CHECK: 00020000 g F .text 00000000 __start # ELF: Format: ELF32-mips -- 2.7.4