forked from OSchip/llvm-project
[ELF][MIPS] Implement R_MIPS_GPREL16/R_MIPS_GPREL32 relocations
The R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations use the following expressions for calculations: ``` local symbol: S + A + GP0 - GP global symbol: S + A - GP GP - Represents the final gp value, i.e. _gp symbol GP0 - Represents the gp value used to create the relocatable object ``` The GP0 value is taken from the .reginfo data section defined by an object file. To implement that I keep a reference to `MipsReginfoInputSection` in the `ObjectFile` class. This reference is used by the `ObjectFile::getMipsGp0` method to return the GP0 value. Differential Revision: http://reviews.llvm.org/D15760 llvm-svn: 256416
This commit is contained in:
parent
a7afacae70
commit
57830b60dc
|
@ -93,6 +93,10 @@ typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
|
|||
return this->getSymbolsHelper(true);
|
||||
}
|
||||
|
||||
template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const {
|
||||
return MipsReginfo ? MipsReginfo->getGp0() : 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const typename ObjectFile<ELFT>::Elf_Sym *
|
||||
ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
|
||||
|
@ -245,8 +249,10 @@ elf2::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
|||
|
||||
// A MIPS object file has a special section that contains register
|
||||
// usage info, which needs to be handled by the linker specially.
|
||||
if (Config->EMachine == EM_MIPS && Name == ".reginfo")
|
||||
return new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
|
||||
if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
|
||||
MipsReginfo = new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
|
||||
return MipsReginfo;
|
||||
}
|
||||
|
||||
if (Name == ".eh_frame")
|
||||
return new (this->EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
|
||||
|
|
|
@ -121,6 +121,11 @@ public:
|
|||
|
||||
const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
|
||||
|
||||
// Get MIPS GP0 value defined by this file. This value represents the gp value
|
||||
// used to create the relocatable object and required to support
|
||||
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
||||
uint32_t getMipsGp0() const;
|
||||
|
||||
private:
|
||||
void initializeSections(llvm::DenseSet<StringRef> &Comdats);
|
||||
void initializeSymbols();
|
||||
|
@ -134,6 +139,9 @@ private:
|
|||
// List of all symbols referenced or defined by this file.
|
||||
std::vector<SymbolBody *> SymbolBodies;
|
||||
|
||||
// MIPS .reginfo section defined by this file.
|
||||
MipsReginfoInputSection<ELFT> *MipsReginfo = nullptr;
|
||||
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
|
||||
llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
|
||||
|
|
|
@ -187,6 +187,12 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
|
|||
uintX_t A = getAddend<ELFT>(RI);
|
||||
if (!Body) {
|
||||
uintX_t SymVA = getLocalRelTarget(*File, RI, A);
|
||||
// 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.
|
||||
if (Config->EMachine == EM_MIPS &&
|
||||
(Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
|
||||
SymVA += File->getMipsGp0();
|
||||
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
|
||||
findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
|
||||
continue;
|
||||
|
@ -351,6 +357,13 @@ uint32_t MipsReginfoInputSection<ELFT>::getGeneralMask() const {
|
|||
return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gprmask;
|
||||
}
|
||||
|
||||
template <class ELFT> uint32_t MipsReginfoInputSection<ELFT>::getGp0() const {
|
||||
ArrayRef<uint8_t> D = this->getSectionData();
|
||||
if (D.size() != sizeof(Elf_Mips_RegInfo))
|
||||
error("Invalid size of .reginfo section");
|
||||
return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gp_value;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
|
||||
return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
|
||||
|
|
|
@ -176,6 +176,7 @@ public:
|
|||
MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
|
||||
|
||||
uint32_t getGeneralMask() const;
|
||||
uint32_t getGp0() const;
|
||||
|
||||
static bool classof(const InputSectionBase<ELFT> *S);
|
||||
};
|
||||
|
|
|
@ -1382,6 +1382,16 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
|
|||
write32<E>(Loc, (read32<E>(Loc) & 0xffff0000) | (V & 0xffff));
|
||||
break;
|
||||
}
|
||||
case R_MIPS_GPREL16: {
|
||||
uint32_t Instr = read32<E>(Loc);
|
||||
int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr<ELFT>();
|
||||
checkInt<16>(V, Type);
|
||||
write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
|
||||
break;
|
||||
}
|
||||
case R_MIPS_GPREL32:
|
||||
write32<E>(Loc, SA + int32_t(read32<E>(Loc)) - getMipsGpAddr<ELFT>());
|
||||
break;
|
||||
case R_MIPS_HI16: {
|
||||
uint32_t Instr = read32<E>(Loc);
|
||||
if (PairedLoc) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Check R_MIPS_GPREL32 relocation calculation.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld -shared -o %t.so %t.o
|
||||
# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
.text
|
||||
.globl __start
|
||||
__start:
|
||||
lw $t0,%call16(__start)($gp)
|
||||
foo:
|
||||
nop
|
||||
bar:
|
||||
nop
|
||||
|
||||
.section .rodata, "a"
|
||||
v1:
|
||||
.gpword foo
|
||||
.gpword bar
|
||||
|
||||
# CHECK: Contents of section .rodata:
|
||||
# CHECK: 0114 fffe8014 fffe8018
|
||||
# ^ 0x10004 - 0x27ff0
|
||||
# ^ 0x10008 - 0x27ff0
|
||||
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK: 00010008 .text 00000000 bar
|
||||
# CHECK: 00010004 .text 00000000 foo
|
||||
# CHECK: 00027ff0 *ABS* 00000000 _gp
|
Loading…
Reference in New Issue