Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -112,7 +112,8 @@ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, Out::Got->getVA() + Out::LocalModuleTlsIndexOffset + - getAddend(RI)); + getAddend(RI), + nullptr); continue; } @@ -121,22 +122,22 @@ const Elf_Shdr *SymTab = File->getSymbolTable(); if (SymIndex < SymTab->sh_info) { uintX_t SymVA = getLocalRelTarget(*File, RI); - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA); + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, nullptr); continue; } SymbolBody &Body = *File->getSymbolBody(SymIndex)->repl(); if (Target->isTlsGlobalDynamicReloc(Type)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out::Got->getEntryAddr(Body) + - getAddend(RI)); + Target->relocateOne( + BufLoc, BufEnd, Type, AddrLoc, + Out::Got->getEntryAddr(Body) + getAddend(RI), &Body); continue; } if (Target->isTlsOptimized(Type, Body)) { - Target->relocateTlsOptimize(BufLoc, BufEnd, AddrLoc, - getSymVA(Body)); + Target->relocateTlsOptimize(BufLoc, BufEnd, AddrLoc, getSymVA(Body), + &Body); continue; } @@ -156,7 +157,7 @@ continue; } Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - SymVA + getAddend(RI)); + SymVA + getAddend(RI), &Body); } } Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -58,10 +58,11 @@ virtual bool relocPointsToGot(uint32_t Type) const; virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const = 0; + uint64_t P, uint64_t SA, + const SymbolBody *S) const = 0; virtual bool isTlsOptimized(unsigned Type, const SymbolBody &S) const; virtual void relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; + uint64_t SA, const SymbolBody *S) const; virtual ~TargetInfo(); protected: Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -55,7 +55,7 @@ bool relocPointsToGot(uint32_t Type) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; }; class X86_64TargetInfo final : public TargetInfo { @@ -72,11 +72,11 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; bool isRelRelative(uint32_t Type) const override; bool isTlsOptimized(unsigned Type, const SymbolBody &S) const override; void relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; }; class PPC64TargetInfo final : public TargetInfo { @@ -90,7 +90,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; bool isRelRelative(uint32_t Type) const override; }; @@ -107,12 +107,13 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; }; template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); + unsigned getGotRefReloc(unsigned Type) const override; void writeGotHeaderEntries(uint8_t *Buf) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, @@ -122,7 +123,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, const SymbolBody *S) const override; }; } // anonymous namespace @@ -170,7 +171,7 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } void TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const {} + uint64_t SA, const SymbolBody *S) const {} void TargetInfo::writeGotHeaderEntries(uint8_t *Buf) const {} @@ -209,7 +210,8 @@ } void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + const SymbolBody *S) const { switch (Type) { case R_386_GOT32: add32le(Loc, SA - Out::Got->getVA()); @@ -369,7 +371,8 @@ // 5.5 x86-x64 linker optimizations" (http://www.akkadia.org/drepper/tls.pdf) // by Ulrich Drepper for details. void X86_64TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + const SymbolBody *S) const { // Ulrich's document section 6.5 says that @gottpoff(%rip) must be // used in MOVQ or ADDQ instructions only. // "MOVQ foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVQ $foo, %REG". @@ -395,11 +398,12 @@ if (*Prefix == 0x4c) *Prefix = (IsMov || RspAdd) ? 0x49 : 0x4d; *RegSlot = (IsMov || RspAdd) ? (0xc0 | Reg) : (0x80 | Reg | (Reg << 3)); - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); + relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA, S); } void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + const SymbolBody *S) const { switch (Type) { case R_X86_64_PC32: case R_X86_64_GOTPCREL: @@ -542,7 +546,8 @@ } void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + const SymbolBody *S) const { uint64_t TB = getPPC64TocBase(); // For a TOC-relative relocation, adjust the addend and proceed in terms of @@ -695,11 +700,11 @@ memcpy(Buf, PltData, sizeof(PltData)); relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr + 4, - GotEntryAddr + 16); + GotEntryAddr + 16, nullptr); relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 8, - GotEntryAddr + 16); + GotEntryAddr + 16, nullptr); relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 12, - GotEntryAddr + 16); + GotEntryAddr + 16, nullptr); } void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, @@ -714,11 +719,11 @@ memcpy(Buf, Inst, sizeof(Inst)); relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr, - GotEntryAddr); + GotEntryAddr, nullptr); relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4, - GotEntryAddr); + GotEntryAddr, nullptr); relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8, - GotEntryAddr); + GotEntryAddr, nullptr); } bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, @@ -760,8 +765,8 @@ } void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { + uint32_t Type, uint64_t P, uint64_t SA, + const SymbolBody *S) const { switch (Type) { case R_AARCH64_ABS16: checkAArch64OutOfRange<16>(SA, Type); @@ -845,6 +850,11 @@ } template +unsigned MipsTargetInfo::getGotRefReloc(unsigned Type) const { + return Type; +} + +template void MipsTargetInfo::writeGotHeaderEntries(uint8_t *Buf) const { typedef typename llvm::object::ELFFile::Elf_Off Elf_Off; auto *P = reinterpret_cast(Buf); @@ -864,7 +874,7 @@ template bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return Type == R_MIPS_GOT16; + return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16; } template @@ -875,13 +885,20 @@ template void MipsTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { + uint32_t Type, uint64_t P, uint64_t SA, + const SymbolBody *S) const { const endianness E = ELFT::TargetEndianness; switch (Type) { case R_MIPS_32: add32(Loc, SA); break; + case R_MIPS_CALL16: { + int64_t V = SA - getMipsGpAddr(); + if (!S) + error("Relocation R_MIPS_CALL16 not against a global symbol"); + write32(Loc, (read32(Loc) & 0xffff0000) | (V & 0xffff)); + break; + } case R_MIPS_GOT16: { int64_t V = SA - getMipsGpAddr(); if (!isInt<16>(V)) Index: test/ELF/mips-call16-local.s =================================================================== --- /dev/null +++ test/ELF/mips-call16-local.s @@ -0,0 +1,18 @@ +# Check that LLD report an error if R_MIPS_CALL16 relocation target +# is a local symbol. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o -shared -o %t.exe 2>&1 | FileCheck %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lw $t0,%call16(l1)($gp) + + .type l1,@function +l1: + nop + +# CHECK: Relocation R_MIPS_CALL16 not against a global symbol Index: test/ELF/mips-call16.s =================================================================== --- /dev/null +++ test/ELF/mips-call16.s @@ -0,0 +1,40 @@ +# Check R_MIPS_CALL16 relocation calculation. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -shared -o %t.exe +# RUN: llvm-objdump -d %t.exe | FileCheck %s +# RUN: llvm-readobj -mips-plt-got -symbols %t.exe \ +# RUN: | FileCheck -check-prefix=GOT %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lw $t0,%call16(g1)($gp) + + .globl g1 + .type g1,@function +g1: + nop + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: __start: +# CHECK-NEXT: 10000: 8f 88 80 18 lw $8, -32744 + +# GOT: Name: g1 +# GOT-NEXT: Value: 0x[[ADDR:[0-9A-F]+]] + +# GOT: Local entries [ +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32744 +# GOT-NEXT: Initial: 0x[[ADDR]] +# GOT-NEXT: Value: 0x[[ADDR]] +# GOT-NEXT: Type: Function +# GOT-NEXT: Section: .text +# GOT-NEXT: Name: g1 +# GOT-NEXT: } +# GOT-NEXT: ]