summaryrefslogtreecommitdiffstats
path: root/lld/ELF/InputSection.cpp
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2016-03-31 21:26:23 +0000
committerSimon Atanasyan <simon@atanasyan.com>2016-03-31 21:26:23 +0000
commit13f6da1d2c20ebb0c4f6600b4ea23d428ef20cc5 (patch)
tree3af0a03790dfff52de58ae9c7cd48bd314bd4832 /lld/ELF/InputSection.cpp
parent098c3fcb03b3b3541de3d99a0fb518474ea4dbd8 (diff)
downloadbcm5719-llvm-13f6da1d2c20ebb0c4f6600b4ea23d428ef20cc5.tar.gz
bcm5719-llvm-13f6da1d2c20ebb0c4f6600b4ea23d428ef20cc5.zip
[ELF] Implement infrastructure for thunk code creation
Some targets might require creation of thunks. For example, MIPS targets require stubs to call PIC code from non-PIC one. The patch implements infrastructure for thunk code creation and provides support for MIPS LA25 stubs. 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 stub to save the target function address. See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - In relocation scanning phase we ask target about thunk creation necessity by calling `TagetInfo::needsThunk` method. The `InputSection` class maintains list of Symbols requires thunk creation. - Reassigning offsets performed for each input sections after relocation scanning complete because position of each section might change due thunk creation. - The patch introduces new dedicated value for DefinedSynthetic symbols DefinedSynthetic::SectionEnd. Synthetic symbol with that value always points to the end of the corresponding output section. That allows to escape updating synthetic symbols if output sections sizes changes after relocation scanning due thunk creation. - In the `InputSection::writeTo` method we write thunks after corresponding input section. Each thunk is written by calling `TargetInfo::writeThunk` method. - The patch supports the only type of thunk code for each target. For now, it is enough. Differential Revision: http://reviews.llvm.org/D17934 llvm-svn: 265059
Diffstat (limited to 'lld/ELF/InputSection.cpp')
-rw-r--r--lld/ELF/InputSection.cpp36
1 files changed, 36 insertions, 0 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index d26c7400563..b5448aca373 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -38,6 +38,13 @@ InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
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));
}
@@ -105,6 +112,19 @@ InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
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.
@@ -293,6 +313,9 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
// 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) &&
@@ -333,6 +356,19 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
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>
OpenPOWER on IntegriCloud