mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 11:39:35 +00:00
Make InputSection able to relocate itself.
This matches the organization used in COFF. llvm-svn: 248215
This commit is contained in:
parent
5805c4f509
commit
4ea00210f2
@ -10,9 +10,13 @@
|
||||
#include "Chunks.h"
|
||||
#include "Error.h"
|
||||
#include "InputFiles.h"
|
||||
#include "OutputSections.h"
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
using namespace llvm::object;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
@ -21,12 +25,134 @@ template <class ELFT>
|
||||
InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
|
||||
: File(F), Header(Header) {}
|
||||
|
||||
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
template <class ELFT>
|
||||
void InputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rel &Rel,
|
||||
uint32_t Type, uintX_t BaseAddr,
|
||||
uintX_t SymVA) {
|
||||
uintX_t Offset = Rel.r_offset;
|
||||
uint8_t *Location = Buf + Offset;
|
||||
switch (Type) {
|
||||
case R_386_32:
|
||||
support::endian::write32le(Location, SymVA);
|
||||
break;
|
||||
default:
|
||||
llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void InputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rela &Rel,
|
||||
uint32_t Type, uintX_t BaseAddr,
|
||||
uintX_t SymVA) {
|
||||
uintX_t Offset = Rel.r_offset;
|
||||
uint8_t *Location = Buf + Offset;
|
||||
switch (Type) {
|
||||
case R_X86_64_PC32:
|
||||
support::endian::write32le(Location,
|
||||
SymVA + (Rel.r_addend - (BaseAddr + Offset)));
|
||||
break;
|
||||
case R_X86_64_64:
|
||||
support::endian::write64le(Location, SymVA + Rel.r_addend);
|
||||
break;
|
||||
case R_X86_64_32: {
|
||||
case R_X86_64_32S:
|
||||
uint64_t VA = SymVA + Rel.r_addend;
|
||||
if (Type == R_X86_64_32 && !isUInt<32>(VA))
|
||||
error("R_X86_64_32 out of range");
|
||||
else if (!isInt<32>(VA))
|
||||
error("R_X86_64_32S out of range");
|
||||
|
||||
support::endian::write32le(Location, VA);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
template <bool isRela>
|
||||
void InputSection<ELFT>::relocate(
|
||||
uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
|
||||
const ObjectFile<ELFT> &File, uintX_t BaseAddr,
|
||||
const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec) {
|
||||
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
|
||||
bool IsMips64EL = File.getObj()->isMips64EL();
|
||||
for (const RelType &RI : Rels) {
|
||||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
uintX_t SymVA;
|
||||
|
||||
// Handle relocations for local symbols -- they never get
|
||||
// resolved so we don't allocate a SymbolBody.
|
||||
const Elf_Shdr *SymTab = File.getSymbolTable();
|
||||
if (SymIndex < SymTab->sh_info) {
|
||||
const Elf_Sym *Sym = File.getObj()->getRelocationSymbol(&RI, SymTab);
|
||||
if (!Sym)
|
||||
continue;
|
||||
SymVA = getLocalSymVA(Sym, File);
|
||||
} else {
|
||||
const SymbolBody *Body = File.getSymbolBody(SymIndex);
|
||||
if (!Body)
|
||||
continue;
|
||||
switch (Body->kind()) {
|
||||
case SymbolBody::DefinedRegularKind:
|
||||
SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
|
||||
break;
|
||||
case SymbolBody::DefinedAbsoluteKind:
|
||||
SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
|
||||
break;
|
||||
case SymbolBody::DefinedCommonKind: {
|
||||
auto *DC = cast<DefinedCommon<ELFT>>(Body);
|
||||
SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
|
||||
break;
|
||||
}
|
||||
case SymbolBody::SharedKind:
|
||||
if (relocNeedsPLT(Type)) {
|
||||
SymVA = PltSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
} else if (relocNeedsGOT(Type)) {
|
||||
SymVA = GotSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SymbolBody::UndefinedKind:
|
||||
assert(Body->isWeak() && "Undefined symbol reached writer");
|
||||
SymVA = 0;
|
||||
break;
|
||||
case SymbolBody::LazyKind:
|
||||
llvm_unreachable("Lazy symbol reached writer");
|
||||
}
|
||||
}
|
||||
|
||||
relocateOne(Buf, RI, Type, BaseAddr, SymVA);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void InputSection<ELFT>::writeTo(uint8_t *Buf, const PltSection<ELFT> &PltSec,
|
||||
const GotSection<ELFT> &GotSec) {
|
||||
if (Header->sh_type == SHT_NOBITS)
|
||||
return;
|
||||
// Copy section contents from source object file to output file.
|
||||
ArrayRef<uint8_t> Data = *File->getObj()->getSectionContents(Header);
|
||||
memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
|
||||
|
||||
const ObjectFile<ELFT> *File = getFile();
|
||||
ELFFile<ELFT> *EObj = File->getObj();
|
||||
uint8_t *Base = Buf + getOutputSectionOff();
|
||||
uintX_t BaseAddr = Out->getVA() + getOutputSectionOff();
|
||||
// Iterate over all relocation sections that apply to this section.
|
||||
for (const Elf_Shdr *RelSec : RelocSections) {
|
||||
if (RelSec->sh_type == SHT_RELA)
|
||||
relocate(Base, EObj->relas(RelSec), *File, BaseAddr, PltSec, GotSec);
|
||||
else
|
||||
relocate(Base, EObj->rels(RelSec), *File, BaseAddr, PltSec, GotSec);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> StringRef InputSection<ELFT>::getSectionName() const {
|
||||
|
@ -18,12 +18,15 @@ namespace elf2 {
|
||||
|
||||
template <class ELFT> class ObjectFile;
|
||||
template <class ELFT> class OutputSection;
|
||||
template <class ELFT> class PltSection;
|
||||
template <class ELFT> class GotSection;
|
||||
|
||||
// A chunk corresponding a section of an input file.
|
||||
template <class ELFT> class InputSection {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
public:
|
||||
@ -34,7 +37,8 @@ public:
|
||||
|
||||
// Write this chunk to a mmap'ed file, assuming Buf is pointing to
|
||||
// beginning of the output section.
|
||||
void writeTo(uint8_t *Buf);
|
||||
void writeTo(uint8_t *Buf, const PltSection<ELFT> &PltSec,
|
||||
const GotSection<ELFT> &GotSec);
|
||||
|
||||
StringRef getSectionName() const;
|
||||
const Elf_Shdr *getSectionHdr() const { return Header; }
|
||||
@ -56,6 +60,18 @@ public:
|
||||
SmallVector<const Elf_Shdr *, 1> RelocSections;
|
||||
|
||||
private:
|
||||
void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type,
|
||||
uintX_t BaseAddr, uintX_t SymVA);
|
||||
void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type,
|
||||
uintX_t BaseAddr, uintX_t SymVA);
|
||||
|
||||
template <bool isRela>
|
||||
void relocate(uint8_t *Buf,
|
||||
llvm::iterator_range<
|
||||
const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
|
||||
const ObjectFile<ELFT> &File, uintX_t BaseAddr,
|
||||
const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec);
|
||||
|
||||
// The offset from beginning of the output sections this chunk was assigned
|
||||
// to. The writer sets a value.
|
||||
uint64_t OutputSectionOff = 0;
|
||||
|
@ -259,53 +259,6 @@ void OutputSection<ELFT>::addChunk(InputSection<ELFT> *C) {
|
||||
this->Header.sh_size = Off;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rel &Rel,
|
||||
uint32_t Type, uintX_t BaseAddr,
|
||||
uintX_t SymVA) {
|
||||
uintX_t Offset = Rel.r_offset;
|
||||
uint8_t *Location = Buf + Offset;
|
||||
switch (Type) {
|
||||
case R_386_32:
|
||||
support::endian::write32le(Location, SymVA);
|
||||
break;
|
||||
default:
|
||||
llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rela &Rel,
|
||||
uint32_t Type, uintX_t BaseAddr,
|
||||
uintX_t SymVA) {
|
||||
uintX_t Offset = Rel.r_offset;
|
||||
uint8_t *Location = Buf + Offset;
|
||||
switch (Type) {
|
||||
case R_X86_64_PC32:
|
||||
support::endian::write32le(Location,
|
||||
SymVA + (Rel.r_addend - (BaseAddr + Offset)));
|
||||
break;
|
||||
case R_X86_64_64:
|
||||
support::endian::write64le(Location, SymVA + Rel.r_addend);
|
||||
break;
|
||||
case R_X86_64_32: {
|
||||
case R_X86_64_32S:
|
||||
uint64_t VA = SymVA + Rel.r_addend;
|
||||
if (Type == R_X86_64_32 && !isUInt<32>(VA))
|
||||
error("R_X86_64_32 out of range");
|
||||
else if (!isInt<32>(VA))
|
||||
error("R_X86_64_32S out of range");
|
||||
|
||||
support::endian::write32le(Location, VA);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename ELFFile<ELFT>::uintX_t
|
||||
lld::elf2::getSymVA(const DefinedRegular<ELFT> *DR) {
|
||||
@ -329,81 +282,9 @@ lld::elf2::getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym,
|
||||
return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
template <bool isRela>
|
||||
void OutputSection<ELFT>::relocate(
|
||||
uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
|
||||
const ObjectFile<ELFT> &File, uintX_t BaseAddr) {
|
||||
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
|
||||
bool IsMips64EL = File.getObj()->isMips64EL();
|
||||
for (const RelType &RI : Rels) {
|
||||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
uintX_t SymVA;
|
||||
|
||||
// Handle relocations for local symbols -- they never get
|
||||
// resolved so we don't allocate a SymbolBody.
|
||||
const Elf_Shdr *SymTab = File.getSymbolTable();
|
||||
if (SymIndex < SymTab->sh_info) {
|
||||
const Elf_Sym *Sym = File.getObj()->getRelocationSymbol(&RI, SymTab);
|
||||
if (!Sym)
|
||||
continue;
|
||||
SymVA = getLocalSymVA(Sym, File);
|
||||
} else {
|
||||
const SymbolBody *Body = File.getSymbolBody(SymIndex);
|
||||
if (!Body)
|
||||
continue;
|
||||
switch (Body->kind()) {
|
||||
case SymbolBody::DefinedRegularKind:
|
||||
SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
|
||||
break;
|
||||
case SymbolBody::DefinedAbsoluteKind:
|
||||
SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
|
||||
break;
|
||||
case SymbolBody::DefinedCommonKind: {
|
||||
auto *DC = cast<DefinedCommon<ELFT>>(Body);
|
||||
SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
|
||||
break;
|
||||
}
|
||||
case SymbolBody::SharedKind:
|
||||
if (relocNeedsPLT(Type)) {
|
||||
SymVA = PltSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
} else if (relocNeedsGOT(Type)) {
|
||||
SymVA = GotSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SymbolBody::UndefinedKind:
|
||||
assert(Body->isWeak() && "Undefined symbol reached writer");
|
||||
SymVA = 0;
|
||||
break;
|
||||
case SymbolBody::LazyKind:
|
||||
llvm_unreachable("Lazy symbol reached writer");
|
||||
}
|
||||
}
|
||||
|
||||
relocateOne(Buf, RI, Type, BaseAddr, SymVA);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
for (InputSection<ELFT> *C : Chunks) {
|
||||
C->writeTo(Buf);
|
||||
const ObjectFile<ELFT> *File = C->getFile();
|
||||
ELFFile<ELFT> *EObj = File->getObj();
|
||||
uint8_t *Base = Buf + C->getOutputSectionOff();
|
||||
uintX_t BaseAddr = this->getVA() + C->getOutputSectionOff();
|
||||
// Iterate over all relocation sections that apply to this section.
|
||||
for (const Elf_Shdr *RelSec : C->RelocSections) {
|
||||
if (RelSec->sh_type == SHT_RELA)
|
||||
relocate(Base, EObj->relas(RelSec), *File, BaseAddr);
|
||||
else
|
||||
relocate(Base, EObj->rels(RelSec), *File, BaseAddr);
|
||||
}
|
||||
}
|
||||
for (InputSection<ELFT> *C : Chunks)
|
||||
C->writeTo(Buf, PltSec, GotSec);
|
||||
}
|
||||
|
||||
template <bool Is64Bits>
|
||||
@ -582,5 +463,21 @@ getSymVA(const DefinedRegular<ELF64LE> *DR);
|
||||
|
||||
template typename ELFFile<ELF64BE>::uintX_t
|
||||
getSymVA(const DefinedRegular<ELF64BE> *DR);
|
||||
|
||||
template typename ELFFile<ELF32LE>::uintX_t
|
||||
lld::elf2::getLocalSymVA(const typename ELFFile<ELF32LE>::Elf_Sym *Sym,
|
||||
const ObjectFile<ELF32LE> &File);
|
||||
|
||||
template typename ELFFile<ELF32BE>::uintX_t
|
||||
lld::elf2::getLocalSymVA(const typename ELFFile<ELF32BE>::Elf_Sym *Sym,
|
||||
const ObjectFile<ELF32BE> &File);
|
||||
|
||||
template typename ELFFile<ELF64LE>::uintX_t
|
||||
lld::elf2::getLocalSymVA(const typename ELFFile<ELF64LE>::Elf_Sym *Sym,
|
||||
const ObjectFile<ELF64LE> &File);
|
||||
|
||||
template typename ELFFile<ELF64BE>::uintX_t
|
||||
lld::elf2::getLocalSymVA(const typename ELFFile<ELF64BE>::Elf_Sym *Sym,
|
||||
const ObjectFile<ELF64BE> &File);
|
||||
}
|
||||
}
|
||||
|
@ -245,17 +245,6 @@ public:
|
||||
void addChunk(InputSection<ELFT> *C);
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
|
||||
template <bool isRela>
|
||||
void relocate(uint8_t *Buf,
|
||||
llvm::iterator_range<
|
||||
const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
|
||||
const ObjectFile<ELFT> &File, uintX_t BaseAddr);
|
||||
|
||||
void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type,
|
||||
uintX_t BaseAddr, uintX_t SymVA);
|
||||
void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type,
|
||||
uintX_t BaseAddr, uintX_t SymVA);
|
||||
|
||||
private:
|
||||
std::vector<InputSection<ELFT> *> Chunks;
|
||||
const PltSection<ELFT> &PltSec;
|
||||
|
Loading…
Reference in New Issue
Block a user