Index: test/tools/llvm-objcopy/basic-relocations.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/basic-relocations.test @@ -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:] Index: test/tools/llvm-objcopy/no-symbol-relocation.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/no-symbol-relocation.test @@ -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:] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -146,6 +146,35 @@ void writeSection(llvm::FileOutputBuffer &Out) const override; }; +struct Relocation { + const Symbol *Symbol; + uint64_t Offset; + uint64_t Addend; + uint32_t Type; +}; + +template class RelocationSection : public SectionBase { +private: + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + + std::vector Relocations; + SymbolTableSection *Symbols; + SectionBase *SecToApplyRel; + + template 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 Object { private: typedef std::unique_ptr SecPtr; Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -154,6 +154,39 @@ } } +template void RelocationSection::finalize() { + this->Link = Symbols->Index; + this->Info = SecToApplyRel->Index; +} + +template +void setAddend(Elf_Rel_Impl &Rel, uint64_t Addend) {} + +template +void setAddend(Elf_Rel_Impl &Rela, uint64_t Addend) { + Rela.r_addend = Addend; +} + +template +template +void RelocationSection::writeRel(T *Buf) const { + for (const auto &Reloc : Relocations) { + Buf->r_offset = Reloc.Offset; + setAddend(*Buf, Reloc.Addend); + Buf->setSymbolAndType(Reloc.Symbol->Index, Reloc.Type, false); + ++Buf; + } +} + +template +void RelocationSection::writeSection(llvm::FileOutputBuffer &Out) const { + uint8_t *Buf = Out.getBufferStart() + Offset; + if (Type == SHT_REL) + writeRel(reinterpret_cast(Buf)); + else + writeRel(reinterpret_cast(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 @@ } } +template +static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl &Rel) {} + +template +static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl &Rela) { + ToSet = Rela.r_addend; +} + +template +void initRelocations(RelocationSection *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.Symbol = SymbolTable->getSymbolByIndex(Rel.getSymbol(false)); + Relocs->addRelocation(ToAdd); + } +} + template std::unique_ptr Object::makeSection(const llvm::object::ELFFile &ElfFile, const Elf_Shdr &Shdr) { ArrayRef Data; switch (Shdr.sh_type) { + case SHT_REL: + case SHT_RELA: + return llvm::make_unique>(); case SHT_STRTAB: return llvm::make_unique(); case SHT_SYMTAB: { @@ -279,6 +336,35 @@ // details about symbol tables. if (SymbolTable) initSymbolTable(ElfFile, SymbolTable); + + // Now that all sections and symbols have been added and we can add + // relocations that reference symbols and we can set link and info for + // relocation sections. + for (auto &Section : Sections) { + if (auto RelSec = dyn_cast>(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(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 Object::Object(const ELFObjectFile &Obj) {