Align = std::max<uintX_t>(Header->sh_addralign, 1);
}
+template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
+ if (auto *D = dyn_cast<InputSection<ELFT>>(this))
+ if (D->getThunksSize() > 0)
+ return D->getThunkOff() + D->getThunksSize();
+ return Header->sh_size;
+}
+
template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
return check(File->getObj().getSectionName(this->Header));
}
return Sections[this->Header->sh_info];
}
+template <class ELFT> void InputSection<ELFT>::addThunk(SymbolBody &Body) {
+ Body.ThunkIndex = Thunks.size();
+ Thunks.push_back(&Body);
+}
+
+template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
+ return this->Header->sh_size;
+}
+
+template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
+ return Thunks.size() * Target->ThunkSize;
+}
+
// This is used for -r. We can't use memcpy to copy relocations because we need
// to update symbol table offset and section index for each relocation. So we
// copy relocations one by one.
// If that's the case, we leave the field alone rather than filling it
// with a possibly incorrect value.
continue;
+ } else if (Target->needsThunk(Type, *this->getFile(), Body)) {
+ // Get address of a thunk code related to the symbol.
+ SymVA = Body.getThunkVA<ELFT>();
} else if (Config->EMachine == EM_MIPS) {
SymVA = adjustMipsSymVA<ELFT>(Type, *File, Body, AddrLoc, SymVA);
} else if (!Target->needsCopyRel<ELFT>(Type, Body) &&
else
this->relocate(Buf, BufEnd, EObj.rels(RelSec));
}
+
+ // The section might have a data/code generated by the linker and need
+ // to be written after the section. Usually these are thunks - small piece
+ // of code used to jump between "incompatible" functions like PIC and non-PIC
+ // or if the jump target too far and its address does not fit to the short
+ // jump istruction.
+ if (!Thunks.empty()) {
+ Buf += OutSecOff + getThunkOff();
+ for (const SymbolBody *S : Thunks) {
+ Target->writeThunk(Buf, S->getVA<ELFT>());
+ Buf += Target->ThunkSize;
+ }
+ }
}
template <class ELFT>
InputSectionBase<ELFT> *Repl;
// Returns the size of this section (even if this is a common or BSS.)
- size_t getSize() const { return Header->sh_size; }
+ size_t getSize() const;
static InputSectionBase<ELFT> *Discarded;
InputSectionBase<ELFT> *getRelocatedSection();
+ // Register thunk related to the symbol. When the section is written
+ // to a mmap'ed file, target is requested to write an actual thunk code.
+ // Now thunks is supported for MIPS target only.
+ void addThunk(SymbolBody &Body);
+
+ // The offset of synthetic thunk code from beginning of this section.
+ uint64_t getThunkOff() const;
+
+ // Size of chunk with thunks code.
+ uint64_t getThunksSize() const;
+
private:
template <class RelTy>
void copyRelocations(uint8_t *Buf, llvm::iterator_range<const RelTy *> Rels);
// Used by ICF.
uint64_t GroupId = 0;
+
+ llvm::TinyPtrVector<const SymbolBody *> Thunks;
};
// MIPS .reginfo section provides information on the registers used by the code
Sections.push_back(S);
S->OutSec = this;
this->updateAlign(S->Align);
-
- uintX_t Off = this->Header.sh_size;
- Off = alignTo(Off, S->Align);
- S->OutSecOff = Off;
- Off += S->getSize();
- this->Header.sh_size = Off;
}
// If an input string is in the form of "foo.N" where N is a number,
}
// This function is called after we sort input sections
-// to update their offsets.
-template <class ELFT> void OutputSection<ELFT>::reassignOffsets() {
+// and scan relocations to setup sections' offsets.
+template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
uintX_t Off = 0;
for (InputSection<ELFT> *S : Sections) {
Off = alignTo(Off, S->Align);
Sections.clear();
for (Pair &P : V)
Sections.push_back(P.second);
- reassignOffsets();
}
// Returns true if S matches /Filename.?\.o$/.
// Read the comment above.
template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
- reassignOffsets();
}
static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
// Typically the first section of each PT_LOAD segment has this flag.
bool PageAlign = false;
+ virtual void assignOffsets() {}
virtual void finalize() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
void sortInitFini();
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
+ void assignOffsets() override;
void finalize() override;
private:
- void reassignOffsets();
std::vector<InputSection<ELFT> *> Sections;
};
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
auto &D = cast<DefinedSynthetic<ELFT>>(Body);
+ if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
+ return D.Section.getVA() + D.Section.getSize();
return D.Section.getVA() + D.Value;
}
case SymbolBody::DefinedRegularKind: {
PltIndex * Target->PltEntrySize;
}
+template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
+ auto *D = cast<DefinedRegular<ELFT>>(this);
+ auto *S = cast<InputSection<ELFT>>(D->Section);
+ return S->OutSec->getVA() + S->OutSecOff + S->getThunkOff() +
+ ThunkIndex * Target->ThunkSize;
+}
+
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
if (auto *B = dyn_cast<DefinedElf<ELFT>>(this))
return B->Sym.st_size;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
+template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
+template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
+template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
+template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
+
template int SymbolBody::compare<ELF32LE>(SymbolBody *Other);
template int SymbolBody::compare<ELF32BE>(SymbolBody *Other);
template int SymbolBody::compare<ELF64LE>(SymbolBody *Other);
uint32_t GotIndex = -1;
uint32_t GotPltIndex = -1;
uint32_t PltIndex = -1;
+ uint32_t ThunkIndex = -1;
bool hasGlobalDynIndex() { return GlobalDynIndex != uint32_t(-1); }
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
+ bool hasThunk() const { return ThunkIndex != -1U; }
void setUsedInRegularObj() { IsUsedInRegularObj = true; }
template <class ELFT> typename ELFT::uint getGotVA() const;
template <class ELFT> typename ELFT::uint getGotPltVA() const;
template <class ELFT> typename ELFT::uint getPltVA() const;
+ template <class ELFT> typename ELFT::uint getThunkVA() const;
template <class ELFT> typename ELFT::uint getSize() const;
// A SymbolBody has a backreference to a Symbol. Originally they are
return S->kind() == SymbolBody::DefinedSyntheticKind;
}
+ // Special value designates that the symbol 'points'
+ // to the end of the section.
+ static const uintX_t SectionEnd = uintX_t(-1);
+
uintX_t Value;
const OutputSectionBase<ELFT> &Section;
};
#include "Target.h"
#include "Error.h"
+#include "InputFiles.h"
#include "OutputSections.h"
#include "Symbols.h"
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void writeGotHeader(uint8_t *Buf) const override;
+ void writeThunk(uint8_t *Buf, uint64_t S) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, const SymbolBody &S) const override;
bool needsPltImpl(uint32_t Type) const override;
+ bool needsThunk(uint32_t Type, const InputFile &File,
+ const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t SA) const override;
bool isHintRel(uint32_t Type) const override;
return Plt_No;
}
+bool TargetInfo::needsThunk(uint32_t Type, const InputFile &File,
+ const SymbolBody &S) const {
+ return false;
+}
+
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
bool TargetInfo::pointsToLocalDynamicGotEntry(uint32_t Type) const {
PageSize = 65536;
PltEntrySize = 16;
PltZeroSize = 32;
+ ThunkSize = 16;
UseLazyBinding = true;
CopyRel = R_MIPS_COPY;
PltRel = R_MIPS_JUMP_SLOT;
}
template <class ELFT>
+void MipsTargetInfo<ELFT>::writeThunk(uint8_t *Buf, uint64_t S) const {
+ // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
+ // See MipsTargetInfo::writeThunk for details.
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 0x3c190000); // lui $25, %hi(func)
+ write32<E>(Buf + 4, 0x08000000); // j func
+ write32<E>(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
+ write32<E>(Buf + 12, 0x00000000); // nop
+ writeMipsHi16<E>(Buf, S);
+ write32<E>(Buf + 4, 0x08000000 | (S >> 2));
+ writeMipsLo16<E>(Buf + 8, S);
+}
+
+template <class ELFT>
bool MipsTargetInfo<ELFT>::needsCopyRelImpl(uint32_t Type) const {
return !isRelRelative(Type);
}
}
template <class ELFT>
+bool MipsTargetInfo<ELFT>::needsThunk(uint32_t Type, const InputFile &File,
+ const SymbolBody &S) const {
+ // Any MIPS PIC code function is invoked with its address in register $t9.
+ // So if we have a branch instruction from non-PIC code to the PIC one
+ // we cannot make the jump directly and need to create a small stubs
+ // to save the target function address.
+ // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (Type != R_MIPS_26)
+ return false;
+ auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
+ if (!F)
+ return false;
+ // If current file has PIC code, LA25 stub is not required.
+ if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
+ return false;
+ auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
+ if (!D || !D->Section)
+ return false;
+ // LA25 is required if target file has PIC code
+ // or target symbol is a PIC symbol.
+ return (D->Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC) ||
+ (D->Sym.st_other & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+}
+
+template <class ELFT>
uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(uint8_t *Buf,
uint32_t Type) const {
const endianness E = ELFT::TargetEndianness;
namespace lld {
namespace elf {
+class InputFile;
class SymbolBody;
class TargetInfo {
enum PltNeed { Plt_No, Plt_Explicit, Plt_Implicit };
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const;
+ virtual bool needsThunk(uint32_t Type, const InputFile &File,
+ const SymbolBody &S) const;
+
+ virtual void writeThunk(uint8_t *Buf, uint64_t S) const {}
+
virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
uint64_t P, uint64_t SA) const = 0;
virtual bool isGotRelative(uint32_t Type) const;
unsigned PltZeroSize = 0;
unsigned GotHeaderEntriesNum = 0;
unsigned GotPltHeaderEntriesNum = 3;
+ uint32_t ThunkSize = 0;
bool UseLazyBinding = false;
private:
bool isOutputDynamic() const {
return !Symtab.getSharedFiles().empty() || Config->Pic;
}
+ template <class RelTy>
+ void scanRelocsForThunks(const elf::ObjectFile<ELFT> &File,
+ iterator_range<const RelTy *> Rels);
void ensureBss();
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
return 0;
}
+// Some targets might require creation of thunks for relocations. Now we
+// support only MIPS which requires LA25 thunk to call PIC code from non-PIC
+// one. Scan relocations to find each one requires thunk.
+template <class ELFT>
+template <class RelTy>
+void Writer<ELFT>::scanRelocsForThunks(const elf::ObjectFile<ELFT> &File,
+ iterator_range<const RelTy *> Rels) {
+ for (const RelTy &RI : Rels) {
+ uint32_t Type = RI.getType(Config->Mips64EL);
+ uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
+ SymbolBody &Body = File.getSymbolBody(SymIndex).repl();
+ if (Body.hasThunk() || !Target->needsThunk(Type, File, Body))
+ continue;
+ auto *D = cast<DefinedRegular<ELFT>>(&Body);
+ auto *S = cast<InputSection<ELFT>>(D->Section);
+ S->addThunk(Body);
+ }
+}
+
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
Out<ELFT>::RelaDyn->addReloc(
{Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend});
}
+
+ // Scan relocations for necessary thunks.
+ if (Config->EMachine == EM_MIPS)
+ scanRelocsForThunks(File, Rels);
}
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
}
}
+ for (OutputSectionBase<ELFT> *Sec : getSections())
+ Sec->assignOffsets();
+
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
std::vector<DefinedCommon *> CommonSymbols;
OutputSectionBase<ELFT> *OS) {
if (OS) {
Symtab.addSynthetic(Start, *OS, 0, STV_DEFAULT);
- Symtab.addSynthetic(End, *OS, OS->getSize(), STV_DEFAULT);
+ Symtab.addSynthetic(End, *OS, DefinedSynthetic<ELFT>::SectionEnd,
+ STV_DEFAULT);
} else {
Symtab.addIgnored(Start);
Symtab.addIgnored(End);
Symtab.addSynthetic(Start, *Sec, 0, STV_DEFAULT);
if (SymbolBody *B = Symtab.find(Stop))
if (B->isUndefined())
- Symtab.addSynthetic(Stop, *Sec, Sec->getSize(), STV_DEFAULT);
+ Symtab.addSynthetic(Stop, *Sec, DefinedSynthetic<ELFT>::SectionEnd,
+ STV_DEFAULT);
}
template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
--- /dev/null
+ .option pic2
+
+ .section .text.1,"ax",@progbits
+ .align 4
+ .globl foo1a
+ .type foo1a, @function
+foo1a:
+ nop
+ .globl foo1b
+ .type foo1b, @function
+foo1b:
+ nop
+
+ .section .text.2,"ax",@progbits
+ .align 4
+ .globl foo2
+ .type foo2, @function
+foo2:
+ nop
--- /dev/null
+# Check LA25 stubs creation. This stub code is necessary when
+# non-PIC code calls PIC function.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: ld.lld %t-npic.o %t-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT: 20000: 0c 00 80 0a jal 131112
+# ^-- 0x20030 .pic.foo1a
+# CHECK-NEXT: 20004: 00 00 00 00 nop
+# CHECK-NEXT: 20008: 0c 00 80 15 jal 131156
+# ^-- 0x20060 .pic.foo2
+# CHECK-NEXT: 2000c: 00 00 00 00 nop
+# CHECK-NEXT: 20010: 0c 00 80 0e jal 131128
+# ^-- 0x20040 .pic.foo1b
+# CHECK-NEXT: 20014: 00 00 00 00 nop
+# CHECK-NEXT: 20018: 0c 00 80 15 jal 131156
+# ^-- 0x20060 .pic.foo2
+# CHECK-NEXT: 2001c: 00 00 00 00 nop
+#
+# CHECK: foo1a:
+# CHECK-NEXT: 20020: 00 00 00 00 nop
+#
+# CHECK: foo1b:
+# CHECK-NEXT: 20024: 00 00 00 00 nop
+#
+# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2
+# CHECK-NEXT: 2002c: 08 00 80 08 j 131104 <foo1a>
+# CHECK-NEXT: 20030: 27 39 00 20 addiu $25, $25, 32
+# CHECK-NEXT: 20034: 00 00 00 00 nop
+# CHECK-NEXT: 20038: 3c 19 00 02 lui $25, 2
+# CHECK-NEXT: 2003c: 08 00 80 09 j 131108 <foo1b>
+# CHECK-NEXT: 20040: 27 39 00 24 addiu $25, $25, 36
+# CHECK-NEXT: 20044: 00 00 00 00 nop
+# CHECK-NEXT: 20048: 00 00 00 00 nop
+# CHECK-NEXT: 2004c: 00 00 00 00 nop
+#
+# CHECK: foo2:
+# CHECK-NEXT: 20050: 00 00 00 00 nop
+#
+# CHECK-NEXT: 20054: 3c 19 00 02 lui $25, 2
+# CHECK-NEXT: 20058: 08 00 80 14 j 131152 <foo2>
+# CHECK-NEXT: 2005c: 27 39 00 50 addiu $25, $25, 80
+# CHECK-NEXT: 20060: 00 00 00 00 nop
+
+ .text
+ .globl __start
+__start:
+ jal foo1a
+ jal foo2
+ jal foo1b
+ jal foo2