mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-01 14:46:26 +00:00
[elf2] Add basic relocation support for x86-64.
This currently doesn't handle local symbols. Differential Revision: http://reviews.llvm.org/D11612 llvm-svn: 246234
This commit is contained in:
parent
572d742927
commit
67bc8d6b3f
@ -9,6 +9,7 @@
|
||||
|
||||
#include "Chunks.h"
|
||||
#include "Error.h"
|
||||
#include "InputFiles.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
@ -17,22 +18,19 @@ using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT>
|
||||
SectionChunk<ELFT>::SectionChunk(object::ELFFile<ELFT> *Obj,
|
||||
const Elf_Shdr *Header)
|
||||
: Obj(Obj), Header(Header) {}
|
||||
SectionChunk<ELFT>::SectionChunk(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
|
||||
: File(F), Header(Header) {}
|
||||
|
||||
template <class ELFT> void SectionChunk<ELFT>::writeTo(uint8_t *Buf) {
|
||||
if (Header->sh_type == SHT_NOBITS)
|
||||
return;
|
||||
// Copy section contents from source object file to output file.
|
||||
ArrayRef<uint8_t> Data = *Obj->getSectionContents(Header);
|
||||
ArrayRef<uint8_t> Data = *File->getObj()->getSectionContents(Header);
|
||||
memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
|
||||
|
||||
// FIXME: Relocations
|
||||
}
|
||||
|
||||
template <class ELFT> StringRef SectionChunk<ELFT>::getSectionName() const {
|
||||
ErrorOr<StringRef> Name = Obj->getSectionName(Header);
|
||||
ErrorOr<StringRef> Name = File->getObj()->getSectionName(Header);
|
||||
error(Name);
|
||||
return *Name;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ template <class ELFT> class SectionChunk {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
public:
|
||||
SectionChunk(llvm::object::ELFFile<ELFT> *Obj, const Elf_Shdr *Header);
|
||||
SectionChunk(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
|
||||
|
||||
// Returns the size of this chunk (even if this is a common or BSS.)
|
||||
size_t getSize() const { return Header->sh_size; }
|
||||
@ -38,6 +38,7 @@ public:
|
||||
|
||||
StringRef getSectionName() const;
|
||||
const Elf_Shdr *getSectionHdr() const { return Header; }
|
||||
ObjectFile<ELFT> *getFile() { return File; }
|
||||
|
||||
// The writer sets and uses the addresses.
|
||||
uintX_t getOutputSectionOff() const { return OutputSectionOff; }
|
||||
@ -47,13 +48,16 @@ public:
|
||||
void setOutputSection(OutputSection<ELFT> *O) { Out = O; }
|
||||
OutputSection<ELFT> *getOutputSection() const { return Out; }
|
||||
|
||||
// Relocation sections that refer to this one.
|
||||
SmallVector<const Elf_Shdr *, 1> RelocSections;
|
||||
|
||||
private:
|
||||
// The offset from beginning of the output sections this chunk was assigned
|
||||
// to. The writer sets a value.
|
||||
uint64_t OutputSectionOff = 0;
|
||||
|
||||
// A file this chunk was created from.
|
||||
llvm::object::ELFFile<ELFT> *Obj;
|
||||
// The file this chunk was created from.
|
||||
ObjectFile<ELFT> *File;
|
||||
|
||||
OutputSection<ELFT> *Out = nullptr;
|
||||
|
||||
|
@ -54,11 +54,20 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
}
|
||||
case SHT_STRTAB:
|
||||
case SHT_NULL:
|
||||
case SHT_RELA:
|
||||
case SHT_REL:
|
||||
break;
|
||||
case SHT_RELA:
|
||||
case SHT_REL: {
|
||||
uint32_t RelocatedSectionIndex = Sec.sh_info;
|
||||
if (RelocatedSectionIndex >= Size)
|
||||
error("Invalid relocated section index");
|
||||
SectionChunk<ELFT> *RelocatedSection = Chunks[RelocatedSectionIndex];
|
||||
if (!RelocatedSection)
|
||||
error("Unsupported relocation reference");
|
||||
RelocatedSection->RelocSections.push_back(&Sec);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Chunks[I] = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
|
||||
Chunks[I] = new (Alloc) SectionChunk<ELFT>(this, &Sec);
|
||||
break;
|
||||
}
|
||||
++I;
|
||||
|
@ -91,6 +91,13 @@ public:
|
||||
|
||||
ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
|
||||
|
||||
SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
|
||||
uint32_t FirstNonLocal = Symtab->sh_info;
|
||||
if (SymbolIndex < FirstNonLocal)
|
||||
return nullptr;
|
||||
return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement();
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeChunks();
|
||||
void initializeSymbols();
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
// has chosen the object among other objects having the same name,
|
||||
// you can access P->Backref->Body to get the resolver's result.
|
||||
void setBackref(Symbol *P) { Backref = P; }
|
||||
SymbolBody *getReplacement() { return Backref ? Backref->Body : this; }
|
||||
|
||||
// Decides which symbol should "win" in the symbol table, this or
|
||||
// the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
|
||||
|
@ -10,12 +10,14 @@
|
||||
#include "Chunks.h"
|
||||
#include "Config.h"
|
||||
#include "Error.h"
|
||||
#include "Symbols.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Writer.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
@ -77,6 +79,8 @@ class lld::elf2::OutputSection final
|
||||
: public OutputSectionBase<ELFT::Is64Bits> {
|
||||
public:
|
||||
typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
|
||||
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
|
||||
: OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags) {}
|
||||
|
||||
@ -215,9 +219,52 @@ void OutputSection<ELFT>::addChunk(SectionChunk<ELFT> *C) {
|
||||
this->Header.sh_size = Off;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static typename llvm::object::ELFFile<ELFT>::uintX_t
|
||||
getSymVA(DefinedRegular<ELFT> *DR) {
|
||||
const SectionChunk<ELFT> *SC = &DR->Section;
|
||||
OutputSection<ELFT> *OS = SC->getOutputSection();
|
||||
return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
for (SectionChunk<ELFT> *C : Chunks)
|
||||
for (SectionChunk<ELFT> *C : Chunks) {
|
||||
C->writeTo(Buf);
|
||||
ObjectFile<ELFT> *File = C->getFile();
|
||||
ELFFile<ELFT> *EObj = File->getObj();
|
||||
uint8_t *Base = Buf + C->getOutputSectionOff();
|
||||
|
||||
// Iterate over all relocation sections that apply to this section.
|
||||
for (const Elf_Shdr *RelSec : C->RelocSections) {
|
||||
// Only support RELA for now.
|
||||
if (RelSec->sh_type != SHT_RELA)
|
||||
continue;
|
||||
for (const Elf_Rela &RI : EObj->relas(RelSec)) {
|
||||
uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
|
||||
SymbolBody *Body = File->getSymbolBody(SymIndex);
|
||||
if (!Body)
|
||||
continue;
|
||||
// Skip undefined weak for now.
|
||||
if (isa<UndefinedWeak<ELFT>>(Body))
|
||||
continue;
|
||||
if (!isa<DefinedRegular<ELFT>>(Body))
|
||||
error(Twine("Can't relocate symbol ") + Body->getName());
|
||||
uintX_t Offset = RI.r_offset;
|
||||
uint32_t Type = RI.getType(EObj->isMips64EL());
|
||||
uintX_t P = this->getVA() + C->getOutputSectionOff();
|
||||
uintX_t SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
|
||||
switch (Type) {
|
||||
case llvm::ELF::R_X86_64_PC32:
|
||||
support::endian::write32le(Base + Offset,
|
||||
SymVA + (RI.r_addend - (P + Offset)));
|
||||
break;
|
||||
default:
|
||||
llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool Is64Bits>
|
||||
|
30
lld/test/elf2/invalid-relocations.test
Normal file
30
lld/test/elf2/invalid-relocations.test
Normal file
@ -0,0 +1,30 @@
|
||||
# RUN: yaml2obj -format elf %s -o %t
|
||||
# RUN: not lld -flavor gnu2 %t -o %tout 2>&1 | FileCheck %s
|
||||
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
OSABI: ELFOSABI_GNU
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: E800000000
|
||||
- Name: .rela.text
|
||||
Type: SHT_RELA
|
||||
Info: 12 # Invalid index
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000001
|
||||
Symbol: lulz
|
||||
Type: R_X86_64_PC32
|
||||
Addend: -4
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: lulz
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
|
||||
# CHECK: Invalid relocated section index
|
17
lld/test/elf2/relocation.s
Normal file
17
lld/test/elf2/relocation.s
Normal file
@ -0,0 +1,17 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
|
||||
// RUN: lld -flavor gnu2 %t -o %t2
|
||||
// RUN: llvm-objdump -d %t2 | FileCheck %s
|
||||
// REQUIRES: x86
|
||||
|
||||
|
||||
.section .text,"ax",@progbits,unique,1
|
||||
.global _start
|
||||
_start:
|
||||
call lulz
|
||||
|
||||
.section .text,"ax",@progbits,unique,2
|
||||
.zero 4
|
||||
.global lulz
|
||||
lulz:
|
||||
|
||||
// CHECK: e8 04 00 00 00 callq 4
|
Loading…
x
Reference in New Issue
Block a user