Reland "[llvm-objcopy] Add support for relocations"

This change adds support for SHT_REL and SHT_RELA sections in
llvm-objcopy.

Patch by Jake Ehrlich

Differential Revision: https://reviews.llvm.org/D36554

llvm-svn: 312680
This commit is contained in:
Petr Hosek 2017-09-06 23:41:02 +00:00
parent 92334e07ca
commit d7df9b20a2
4 changed files with 236 additions and 0 deletions

View File

@ -0,0 +1,91 @@
# RUN: yaml2obj %s > %t
# RUN: llvm-objcopy %t %t2
# RUN: llvm-readobj -relocations %t2 | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
- Name: .rel.text
Type: SHT_REL
Link: .symtab
Info: .text
Relocations:
- Offset: 0x1000
Symbol: foo
Type: R_X86_64_PC32
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x2000
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
- Name: .rel.data
Type: SHT_REL
Link: .symtab
Info: .data
Relocations:
- Offset: 0x2000
Symbol: bar
Type: R_X86_64_PC32
- Name: .rela.data
Type: SHT_RELA
Link: .symtab
Info: .data
Relocations:
- Offset: 0x2000
Symbol: barA
Type: R_X86_64_PC32
Addend: 0x17
- Name: .rela.text
Type: SHT_RELA
Link: .symtab
Info: .text
Relocations:
- Offset: 0x1000
Symbol: fooA
Type: R_X86_64_PC32
Addend: 0x13
Symbols:
Global:
- Name: _start
Type: STT_FUNC
Section: .text
Value: 0x1000
Size: 4
- Name: foo
Type: STT_FUNC
Size: 4
- Name: fooA
Type: STT_FUNC
Size: 4
- Name: bar
Type: STT_OBJECT
Size: 4
- Name: barA
Type: STT_OBJECT
Size: 4
# CHECK: Relocations [
# CHECK-NEXT: Section (2) .rel.text {
# CHECK-NEXT: 0x1000 R_X86_64_PC32 foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section (4) .rel.data {
# CHECK-NEXT: 0x2000 R_X86_64_PC32 bar 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section (5) .rela.data {
# CHECK-NEXT: 0x2000 R_X86_64_PC32 barA 0x17
# CHECK-NEXT: }
# CHECK-NEXT: Section (6) .rela.text {
# CHECK-NEXT: 0x1000 R_X86_64_PC32 fooA 0x13
# CHECK-NEXT: }
# CHECK-NEXT:]

View File

@ -0,0 +1,30 @@
# RUN: yaml2obj %s > %t
# RUN: llvm-objcopy %t %t2
# RUN: llvm-readobj -relocations %t2 | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
- Name: .rel.text
Type: SHT_REL
Link: .symtab
Info: .text
Relocations:
- Offset: 0x1000
Type: R_X86_64_RELATIVE
# CHECK: Relocations [
# CHECK-NEXT: Section (2) .rel.text {
# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x0
# CHECK-NEXT: }
# CHECK-NEXT:]

View File

@ -154,6 +154,39 @@ void SymbolTableSectionImpl<ELFT>::writeSection(
}
}
template <class ELFT> void RelocationSection<ELFT>::finalize() {
this->Link = Symbols->Index;
this->Info = SecToApplyRel->Index;
}
template <class ELFT>
void setAddend(Elf_Rel_Impl<ELFT, false> &Rel, uint64_t Addend) {}
template <class ELFT>
void setAddend(Elf_Rel_Impl<ELFT, true> &Rela, uint64_t Addend) {
Rela.r_addend = Addend;
}
template <class ELFT>
template <class T>
void RelocationSection<ELFT>::writeRel(T *Buf) const {
for (const auto &Reloc : Relocations) {
Buf->r_offset = Reloc.Offset;
setAddend(*Buf, Reloc.Addend);
Buf->setSymbolAndType(Reloc.RelocSymbol->Index, Reloc.Type, false);
++Buf;
}
}
template <class ELFT>
void RelocationSection<ELFT>::writeSection(llvm::FileOutputBuffer &Out) const {
uint8_t *Buf = Out.getBufferStart() + Offset;
if (Type == SHT_REL)
writeRel(reinterpret_cast<Elf_Rel *>(Buf));
else
writeRel(reinterpret_cast<Elf_Rela *>(Buf));
}
// Returns true IFF a section is wholly inside the range of a segment
static bool sectionWithinSegment(const SectionBase &Section,
const Segment &Segment) {
@ -230,12 +263,36 @@ void Object<ELFT>::initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
}
}
template <class ELFT>
static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, false> &Rel) {}
template <class ELFT>
static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, true> &Rela) {
ToSet = Rela.r_addend;
}
template <class ELFT, class T>
void initRelocations(RelocationSection<ELFT> *Relocs,
SymbolTableSection *SymbolTable, T RelRange) {
for (const auto &Rel : RelRange) {
Relocation ToAdd;
ToAdd.Offset = Rel.r_offset;
getAddend(ToAdd.Addend, Rel);
ToAdd.Type = Rel.getType(false);
ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Rel.getSymbol(false));
Relocs->addRelocation(ToAdd);
}
}
template <class ELFT>
std::unique_ptr<SectionBase>
Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
const Elf_Shdr &Shdr) {
ArrayRef<uint8_t> Data;
switch (Shdr.sh_type) {
case SHT_REL:
case SHT_RELA:
return llvm::make_unique<RelocationSection<ELFT>>();
case SHT_STRTAB:
return llvm::make_unique<StringTableSection>();
case SHT_SYMTAB: {
@ -279,6 +336,35 @@ void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
// details about symbol tables.
if (SymbolTable)
initSymbolTable(ElfFile, SymbolTable);
// Now that all sections and symbols have been added we can add
// relocations that reference symbols and set the link and info fields for
// relocation sections.
for (auto &Section : Sections) {
if (auto RelSec = dyn_cast<RelocationSection<ELFT>>(Section.get())) {
if (RelSec->Link - 1 >= Sections.size() || RelSec->Link == 0) {
error("Link field value " + Twine(RelSec->Link) + " in section " +
RelSec->Name + " is invalid");
}
if (RelSec->Info - 1 >= Sections.size() || RelSec->Info == 0) {
error("Info field value " + Twine(RelSec->Link) + " in section " +
RelSec->Name + " is invalid");
}
auto SymTab =
dyn_cast<SymbolTableSection>(Sections[RelSec->Link - 1].get());
if (SymTab == nullptr) {
error("Link field of relocation section " + RelSec->Name +
" is not a symbol table");
}
RelSec->setSymTab(SymTab);
RelSec->setSection(Sections[RelSec->Info - 1].get());
auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index;
if (RelSec->Type == SHT_REL)
initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.rels(Shdr)));
else
initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.relas(Shdr)));
}
}
}
template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {

View File

@ -146,6 +146,35 @@ template <class ELFT> class SymbolTableSectionImpl : public SymbolTableSection {
void writeSection(llvm::FileOutputBuffer &Out) const override;
};
struct Relocation {
const Symbol *RelocSymbol;
uint64_t Offset;
uint64_t Addend;
uint32_t Type;
};
template <class ELFT> class RelocationSection : public SectionBase {
private:
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
std::vector<Relocation> Relocations;
SymbolTableSection *Symbols;
SectionBase *SecToApplyRel;
template <class T> void writeRel(T *Buf) const;
public:
void setSymTab(SymbolTableSection *StrTab) { Symbols = StrTab; }
void setSection(SectionBase *Sec) { SecToApplyRel = Sec; }
void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
void finalize() override;
void writeSection(llvm::FileOutputBuffer &Out) const override;
static bool classof(const SectionBase *S) {
return S->Type == llvm::ELF::SHT_REL || S->Type == llvm::ELF::SHT_RELA;
}
};
template <class ELFT> class Object {
private:
typedef std::unique_ptr<SectionBase> SecPtr;