mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-02 21:22:44 +00:00
Create thunks before regular relocation scan.
We will need to do something like this to support range extension thunks since that process is iterative. Doing this also has the advantage that when doing the regular relocation scan the offset in the output section is known and we can just store that. This reduces the number of times we have to run getOffset and I think will allow a more specialized .eh_frame representation. By itself this is already a performance win. firefox master 7.295045737 patch 7.209466989 0.98826892235 chromium master 4.531254468 patch 4.509221804 0.995137623774 chromium fast master 1.836928973 patch 1.823805241 0.992855612714 the gold plugin master 0.379768791 patch 0.380043405 1.00072310839 clang master 0.642698284 patch 0.642215663 0.999249070657 llvm-as master 0.036665467 patch 0.036456225 0.994293213284 the gold plugin fsds master 0.40395817 patch 0.404384555 1.0010555177 clang fsds master 0.722045545 patch 0.720946135 0.998477367518 llvm-as fsds master 0.03292646 patch 0.032759965 0.994943428477 scylla master 3.427376378 patch 3.368316181 0.98276810292 llvm-svn: 276146
This commit is contained in:
parent
a12aa1fa9c
commit
0f7cedaa1e
@ -338,7 +338,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
||||
|
||||
const unsigned Bits = sizeof(uintX_t) * 8;
|
||||
for (const Relocation<ELFT> &Rel : Relocations) {
|
||||
uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
|
||||
uintX_t Offset = Rel.Offset;
|
||||
uint8_t *BufLoc = Buf + Offset;
|
||||
uint32_t Type = Rel.Type;
|
||||
uintX_t A = Rel.Addend;
|
||||
|
@ -1278,7 +1278,7 @@ template <class ELFT>
|
||||
typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
|
||||
if (OutputSec)
|
||||
return OutputSec->getVA() + OffsetInSec;
|
||||
return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec);
|
||||
return InputSec->OutSec->getVA() + OffsetInSec;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
|
@ -548,9 +548,19 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
while (PieceI != PieceE &&
|
||||
(PieceI->InputOff + PieceI->size() <= RI.r_offset))
|
||||
++PieceI;
|
||||
if (PieceI != PieceE && PieceI->InputOff <= RI.r_offset &&
|
||||
PieceI->OutputOff == (uintX_t)-1)
|
||||
continue;
|
||||
|
||||
// Compute the offset of this section in the output section. We do it here
|
||||
// to try to compute it only once.
|
||||
uintX_t Offset;
|
||||
if (PieceI != PieceE) {
|
||||
assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece");
|
||||
if (PieceI->OutputOff == (uintX_t)-1)
|
||||
continue;
|
||||
Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff;
|
||||
assert(Offset == C.getOffset(RI.r_offset));
|
||||
} else {
|
||||
Offset = C.getOffset(RI.r_offset);
|
||||
}
|
||||
|
||||
// This relocation does not require got entry, but it is relative to got and
|
||||
// needs it to be created. Here we request for that.
|
||||
@ -559,8 +569,8 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
|
||||
uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
|
||||
|
||||
if (unsigned Processed = handleTlsRelocation<ELFT>(
|
||||
Type, Body, C, RI.r_offset, Addend, Expr)) {
|
||||
if (unsigned Processed =
|
||||
handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
|
||||
I += (Processed - 1);
|
||||
continue;
|
||||
}
|
||||
@ -581,17 +591,17 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
// relocation. We can process some of it and and just ask the dynamic
|
||||
// linker to add the load address.
|
||||
if (!Constant)
|
||||
AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend});
|
||||
AddDyn({Target->RelativeRel, &C, Offset, true, &Body, Addend});
|
||||
|
||||
// If the produced value is a constant, we just remember to write it
|
||||
// when outputting this section. We also have to do it if the format
|
||||
// uses Elf_Rel, since in that case the written value is the addend.
|
||||
if (Constant || !RelTy::IsRela)
|
||||
C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body});
|
||||
C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
|
||||
} else {
|
||||
// We don't know anything about the finaly symbol. Just ask the dynamic
|
||||
// linker to handle the relocation for us.
|
||||
AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend});
|
||||
AddDyn({Target->getDynRel(Type), &C, Offset, false, &Body, Addend});
|
||||
// MIPS ABI turns using of GOT and dynamic relocations inside out.
|
||||
// While regular ABI uses dynamic relocations to fill up GOT entries
|
||||
// MIPS ABI requires dynamic linker to fills up GOT entries using
|
||||
@ -612,14 +622,6 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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, and ARM which requires interworking.
|
||||
if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
|
||||
auto *Sec = cast<InputSection<ELFT>>(&C);
|
||||
addThunk<ELFT>(Type, Body, *Sec);
|
||||
}
|
||||
|
||||
// At this point we are done with the relocated position. Some relocations
|
||||
// also require us to create a got or plt entry.
|
||||
|
||||
@ -676,19 +678,6 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void scanRelocations(InputSection<ELFT> &C) {
|
||||
typedef typename ELFT::Shdr Elf_Shdr;
|
||||
|
||||
// Scan all relocations. Each relocation goes through a series
|
||||
// of tests to determine if it needs special treatment, such as
|
||||
// creating GOT, PLT, copy relocations, etc.
|
||||
// Note that relocations for non-alloc sections are directly
|
||||
// processed by InputSection::relocateNonAlloc.
|
||||
if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
|
||||
for (const Elf_Shdr *RelSec : C.RelocSections)
|
||||
scanRelocations(C, *RelSec);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void scanRelocations(InputSectionBase<ELFT> &S,
|
||||
const typename ELFT::Shdr &RelSec) {
|
||||
@ -699,10 +688,35 @@ void scanRelocations(InputSectionBase<ELFT> &S,
|
||||
scanRelocs(S, EObj.rels(&RelSec));
|
||||
}
|
||||
|
||||
template void scanRelocations<ELF32LE>(InputSection<ELF32LE> &);
|
||||
template void scanRelocations<ELF32BE>(InputSection<ELF32BE> &);
|
||||
template void scanRelocations<ELF64LE>(InputSection<ELF64LE> &);
|
||||
template void scanRelocations<ELF64BE>(InputSection<ELF64BE> &);
|
||||
template <class ELFT, class RelTy>
|
||||
static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
const elf::ObjectFile<ELFT> &File = *C.getFile();
|
||||
for (const RelTy &Rel : Rels) {
|
||||
SymbolBody &Body = File.getRelocTargetSym(Rel);
|
||||
uint32_t Type = Rel.getType(Config->Mips64EL);
|
||||
RelExpr Expr = Target->getRelExpr(Type, Body);
|
||||
if (!isPreemptible(Body, Type) && needsPlt(Expr))
|
||||
Expr = fromPlt(Expr);
|
||||
Expr = Target->getThunkExpr(Expr, Type, File, Body);
|
||||
// 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, and ARM which requires interworking.
|
||||
if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
|
||||
auto *Sec = cast<InputSection<ELFT>>(&C);
|
||||
addThunk<ELFT>(Type, Body, *Sec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void createThunks(InputSectionBase<ELFT> &S,
|
||||
const typename ELFT::Shdr &RelSec) {
|
||||
ELFFile<ELFT> &EObj = S.getFile()->getObj();
|
||||
if (RelSec.sh_type == SHT_RELA)
|
||||
createThunks(S, EObj.relas(&RelSec));
|
||||
else
|
||||
createThunks(S, EObj.rels(&RelSec));
|
||||
}
|
||||
|
||||
template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &,
|
||||
const ELF32LE::Shdr &);
|
||||
@ -712,5 +726,14 @@ template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &,
|
||||
const ELF64LE::Shdr &);
|
||||
template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &,
|
||||
const ELF64BE::Shdr &);
|
||||
|
||||
template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &,
|
||||
const ELF32LE::Shdr &);
|
||||
template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &,
|
||||
const ELF32BE::Shdr &);
|
||||
template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &,
|
||||
const ELF64LE::Shdr &);
|
||||
template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &,
|
||||
const ELF64BE::Shdr &);
|
||||
}
|
||||
}
|
||||
|
@ -73,11 +73,12 @@ template <class ELFT> struct Relocation {
|
||||
SymbolBody *Sym;
|
||||
};
|
||||
|
||||
template <class ELFT> void scanRelocations(InputSection<ELFT> &);
|
||||
|
||||
template <class ELFT>
|
||||
void scanRelocations(InputSectionBase<ELFT> &, const typename ELFT::Shdr &);
|
||||
|
||||
template <class ELFT>
|
||||
void createThunks(InputSectionBase<ELFT> &, const typename ELFT::Shdr &);
|
||||
|
||||
template <class ELFT>
|
||||
static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
|
||||
return 0;
|
||||
|
@ -1496,6 +1496,7 @@ ARMTargetInfo::ARMTargetInfo() {
|
||||
PltHeaderSize = 20;
|
||||
// ARM uses Variant 1 TLS
|
||||
TcbSize = 8;
|
||||
NeedsThunks = true;
|
||||
}
|
||||
|
||||
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
|
||||
@ -1836,6 +1837,7 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
|
||||
PltHeaderSize = 32;
|
||||
CopyRel = R_MIPS_COPY;
|
||||
PltRel = R_MIPS_JUMP_SLOT;
|
||||
NeedsThunks = true;
|
||||
if (ELFT::Is64Bits) {
|
||||
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
|
||||
TlsGotRel = R_MIPS_TLS_TPREL64;
|
||||
|
@ -92,6 +92,8 @@ public:
|
||||
// Set to 0 for variant 2
|
||||
unsigned TcbSize = 0;
|
||||
|
||||
bool NeedsThunks = false;
|
||||
|
||||
virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
|
||||
RelExpr Expr) const;
|
||||
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
|
||||
|
@ -49,6 +49,9 @@ private:
|
||||
void copyLocalSymbols();
|
||||
void addReservedSymbols();
|
||||
std::vector<OutputSectionBase<ELFT> *> createSections();
|
||||
void forEachRelSec(
|
||||
std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
|
||||
Fn);
|
||||
void finalizeSections();
|
||||
void addPredefinedSections();
|
||||
bool needsGot();
|
||||
@ -632,6 +635,34 @@ template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
|
||||
reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::forEachRelSec(
|
||||
std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
|
||||
Fn) {
|
||||
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
|
||||
Symtab.getObjectFiles()) {
|
||||
for (InputSectionBase<ELFT> *C : F->getSections()) {
|
||||
if (isDiscarded(C))
|
||||
continue;
|
||||
// Scan all relocations. Each relocation goes through a series
|
||||
// of tests to determine if it needs special treatment, such as
|
||||
// creating GOT, PLT, copy relocations, etc.
|
||||
// Note that relocations for non-alloc sections are directly
|
||||
// processed by InputSection::relocateNonAlloc.
|
||||
if (!(C->getSectionHdr()->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
|
||||
for (const Elf_Shdr *RelSec : S->RelocSections)
|
||||
Fn(*S, *RelSec);
|
||||
continue;
|
||||
}
|
||||
if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
|
||||
if (S->RelocSection)
|
||||
Fn(*S, *S->RelocSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
std::vector<OutputSectionBase<ELFT> *> Writer<ELFT>::createSections() {
|
||||
std::vector<OutputSectionBase<ELFT> *> Result;
|
||||
@ -705,26 +736,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
Out<ELFT>::EhFrame->finalize();
|
||||
}
|
||||
|
||||
// Scan relocations. This must be done after every symbol is declared so that
|
||||
// we can correctly decide if a dynamic relocation is needed.
|
||||
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
|
||||
Symtab.getObjectFiles()) {
|
||||
for (InputSectionBase<ELFT> *C : F->getSections()) {
|
||||
if (isDiscarded(C))
|
||||
continue;
|
||||
if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
|
||||
scanRelocations(*S);
|
||||
continue;
|
||||
}
|
||||
if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
|
||||
if (S->RelocSection)
|
||||
scanRelocations(*S, *S->RelocSection);
|
||||
}
|
||||
}
|
||||
if (Target->NeedsThunks)
|
||||
forEachRelSec(createThunks<ELFT>);
|
||||
|
||||
for (OutputSectionBase<ELFT> *Sec : OutputSections)
|
||||
Sec->assignOffsets();
|
||||
|
||||
// Scan relocations. This must be done after every symbol is declared so that
|
||||
// we can correctly decide if a dynamic relocation is needed.
|
||||
forEachRelSec(scanRelocations<ELFT>);
|
||||
|
||||
// Now that we have defined all possible symbols including linker-
|
||||
// synthesized ones. Visit all symbols to give the finishing touches.
|
||||
std::vector<DefinedCommon *> CommonSymbols;
|
||||
|
Loading…
x
Reference in New Issue
Block a user