Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -14,9 +14,12 @@ #include "OutputSections.h" #include "Target.h" +#include "llvm/Support/Endian.h" + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support::endian; using namespace lld; using namespace lld::elf2; @@ -141,6 +144,21 @@ } } +static uint32_t getMipsPairedRelocType(uint32_t Type) { + if (Config->EMachine != EM_MIPS) + return R_MIPS_NONE; + switch (Type) { + case R_MIPS_HI16: + return R_MIPS_LO16; + case R_MIPS_PCHI16: + return R_MIPS_PCLO16; + case R_MICROMIPS_HI16: + return R_MICROMIPS_LO16; + default: + return R_MIPS_NONE; + } +} + template template uint8_t * @@ -151,15 +169,7 @@ // itself and addend of paired relocation. ABI requires to compute such // combined addend in case of REL relocation record format only. // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (isRela || Config->EMachine != EM_MIPS) - return nullptr; - if (Type == R_MIPS_HI16) - Type = R_MIPS_LO16; - else if (Type == R_MIPS_PCHI16) - Type = R_MIPS_PCLO16; - else if (Type == R_MICROMIPS_HI16) - Type = R_MICROMIPS_LO16; - else + if (isRela || Type == R_MIPS_NONE) return nullptr; for (const auto &RI : Rels) { if (RI.getType(Config->Mips64EL) != Type) @@ -225,20 +235,31 @@ uintX_t A = getAddend(RI); if (!Body) { uintX_t SymVA = getLocalRelTarget(*File, RI, A); + uint8_t *PairedLoc = nullptr; if (Config->EMachine == EM_MIPS) { if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32) // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 // relocations because they use the following expression to calculate // the relocation's result for local symbol: S + A + GP0 - G. SymVA += File->getMipsGp0(); - else if (Type == R_MIPS_GOT16) + else if (Type == R_MIPS_GOT16) { // R_MIPS_GOT16 relocation against local symbol requires index of // a local GOT entry which contains page address corresponds - // to the symbol address. - SymVA = Out::Got->getMipsLocalPageAddr(SymVA); + // to sum of the symbol address and addend. The addend in that case + // is calculated using addends from R_MIPS_GOT16 and paired + // R_MIPS_LO16 relocations. + const endianness E = ELFT::TargetEndianness; + uint8_t *LowLoc = + findMipsPairedReloc(Buf, SymIndex, R_MIPS_LO16, NextRelocs); + uint64_t AHL = read32(BufLoc) << 16; + if (LowLoc) + AHL += SignExtend64<16>(read32(LowLoc)); + SymVA = Out::Got->getMipsLocalPageAddr(SymVA + AHL); + } else + PairedLoc = findMipsPairedReloc( + Buf, SymIndex, getMipsPairedRelocType(Type), NextRelocs); } - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, - findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, PairedLoc); continue; } @@ -284,7 +305,9 @@ } uintX_t Size = Body->getSize(); Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, - findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); + findMipsPairedReloc(Buf, SymIndex, + getMipsPairedRelocType(Type), + NextRelocs)); } } Index: lld/trunk/test/ELF/mips-got16.s =================================================================== --- lld/trunk/test/ELF/mips-got16.s +++ lld/trunk/test/ELF/mips-got16.s @@ -10,17 +10,21 @@ # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 10000: 8f 88 80 18 lw $8, -32744($gp) -# CHECK-NEXT: 10004: 21 08 00 1c addi $8, $8, 28 +# CHECK-NEXT: 10004: 21 08 00 2c addi $8, $8, 44 # CHECK-NEXT: 10008: 8f 88 80 1c lw $8, -32740($gp) -# CHECK-NEXT: 1000c: 21 08 00 00 addi $8, $8, 0 +# CHECK-NEXT: 1000c: 21 08 90 00 addi $8, $8, -28672 # CHECK-NEXT: 10010: 8f 88 80 20 lw $8, -32736($gp) -# CHECK-NEXT: 10014: 21 08 00 04 addi $8, $8, 4 -# CHECK-NEXT: 10018: 8f 88 80 24 lw $8, -32732($gp) +# CHECK-NEXT: 10014: 21 08 90 04 addi $8, $8, -28668 +# CHECK-NEXT: 10018: 8f 88 80 20 lw $8, -32736($gp) +# CHECK-NEXT: 1001c: 21 08 10 04 addi $8, $8, 4100 +# CHECK-NEXT: 10020: 8f 88 80 24 lw $8, -32732($gp) +# CHECK-NEXT: 10024: 21 08 10 08 addi $8, $8, 4104 +# CHECK-NEXT: 10028: 8f 88 80 2c lw $8, -32724($gp) # # CHECK: SYMBOL TABLE: -# CHECK: 0001001c .text 00000000 $LC0 -# CHECK: 00030000 .data 00000000 $LC1 -# CHECK: 00030004 .data 00000000 .hidden bar +# CHECK: 0001002c .text 00000000 $LC0 +# CHECK: 00039000 .data 00000000 $LC1 +# CHECK: 00051008 .data 00000000 .hidden bar # CHECK: 00000000 *UND* 00000000 foo # GOT: Relocations [ @@ -47,22 +51,38 @@ # GOT-NEXT: Address: 0x20008 # GOT-NEXT: Access: -32744 # GOT-NEXT: Initial: 0x10000 +# ^-- (0x1002c + 0x8000) & ~0xffff # GOT-NEXT: } # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x2000C # GOT-NEXT: Access: -32740 -# GOT-NEXT: Initial: 0x30000 +# GOT-NEXT: Initial: 0x40000 +# ^-- (0x39000 + 0x8000) & ~0xffff # GOT-NEXT: } # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20010 # GOT-NEXT: Access: -32736 -# GOT-NEXT: Initial: 0x30004 +# GOT-NEXT: Initial: 0x50000 +# ^-- (0x39000 + 0x10004 + 0x8000) & ~0xffff +# ^-- (0x39000 + 0x18004 + 0x8000) & ~0xffff # GOT-NEXT: } -# GOT-NEXT: ] -# GOT-NEXT: Global entries [ # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20014 # GOT-NEXT: Access: -32732 +# GOT-NEXT: Initial: 0x51008 +# ^-- 'bar' address +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x20018 +# GOT-NEXT: Access: -32728 +# GOT-NEXT: Initial: 0x0 +# ^-- redundant unused entry +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x2001C +# GOT-NEXT: Access: -32724 # GOT-NEXT: Initial: 0x0 # GOT-NEXT: Value: 0x0 # GOT-NEXT: Type: None @@ -80,6 +100,10 @@ addi $t0,$t0,%lo($LC0) lw $t0,%got($LC1)($gp) addi $t0,$t0,%lo($LC1) + lw $t0,%got($LC1+0x10004)($gp) + addi $t0,$t0,%lo($LC1+0x10004) + lw $t0,%got($LC1+0x18004)($gp) + addi $t0,$t0,%lo($LC1+0x18004) lw $t0,%got(bar)($gp) addi $t0,$t0,%lo(bar) lw $t0,%got(foo)($gp) @@ -87,8 +111,11 @@ nop .data + .space 0x9000 $LC1: .word 0 + .space 0x18000 + .word 0 .global bar .hidden bar bar: