[ELF] Customize a relocation table output format (rel / rela).

Add new virtual virtual function `isRelaOutputFormat` to the
`ELFLinkingContext` class. Call this function everywhere we need to
select a relocation table format.

Patch reviewed by Shankar Easwaran and Rui Ueyama.

llvm-svn: 199973
This commit is contained in:
Simon Atanasyan 2014-01-24 05:21:21 +00:00
parent 4d97536ad0
commit d8cadd6f17
8 changed files with 138 additions and 49 deletions

View File

@ -93,6 +93,9 @@ public:
static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
/// \brief Use Elf_Rela format to output relocation tables.
virtual bool isRelaOutputFormat() const { return true; }
/// \brief Does this relocation belong in the dynamic plt relocation table?
///
/// This table holds all of the relocations used for delayed symbol binding.

View File

@ -270,7 +270,8 @@ public:
RelocationTable<ELFT> *getDynamicRelocationTable() {
if (!_dynamicRelocationTable) {
_dynamicRelocationTable.reset(new (_allocator) RelocationTable<ELFT>(
_context, ".rela.dyn", ORDER_DYNAMIC_RELOCS));
_context, _context.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
ORDER_DYNAMIC_RELOCS));
addSection(_dynamicRelocationTable.get());
}
return _dynamicRelocationTable.get();
@ -280,7 +281,8 @@ public:
RelocationTable<ELFT> *getPLTRelocationTable() {
if (!_pltRelocationTable) {
_pltRelocationTable.reset(new (_allocator) RelocationTable<ELFT>(
_context, ".rela.plt", ORDER_DYNAMIC_PLT_RELOCS));
_context, _context.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
ORDER_DYNAMIC_PLT_RELOCS));
addSection(_pltRelocationTable.get());
}
return _pltRelocationTable.get();

View File

@ -55,8 +55,13 @@ void ExecutableWriter<ELFT>::addDefaultAtoms() {
_runtimeFile->addAbsoluteAtom("__preinit_array_end");
_runtimeFile->addAbsoluteAtom("__init_array_start");
_runtimeFile->addAbsoluteAtom("__init_array_end");
_runtimeFile->addAbsoluteAtom("__rela_iplt_start");
_runtimeFile->addAbsoluteAtom("__rela_iplt_end");
if (this->_context.isRelaOutputFormat()) {
_runtimeFile->addAbsoluteAtom("__rela_iplt_start");
_runtimeFile->addAbsoluteAtom("__rela_iplt_end");
} else {
_runtimeFile->addAbsoluteAtom("__rel_iplt_start");
_runtimeFile->addAbsoluteAtom("__rel_iplt_end");
}
_runtimeFile->addAbsoluteAtom("__fini_array_start");
_runtimeFile->addAbsoluteAtom("__fini_array_end");
}
@ -111,7 +116,10 @@ template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
startEnd("preinit_array", ".preinit_array");
startEnd("init_array", ".init_array");
startEnd("rela_iplt", ".rela.plt");
if (this->_context.isRelaOutputFormat())
startEnd("rela_iplt", ".rela.plt");
else
startEnd("rel_iplt", ".rel.plt");
startEnd("fini_array", ".fini_array");
assert(!(bssStartAtomIter == this->_layout->absoluteAtoms().end() ||

View File

@ -45,6 +45,7 @@ public:
virtual StringRef entrySymbolName() const;
virtual StringRef getDefaultInterpreter() const;
virtual void addPasses(PassManager &pm);
virtual bool isRelaOutputFormat() const { return false; }
virtual bool isPLTRelocation(const DefinedAtom &, const Reference &r) const;
};

View File

@ -900,22 +900,29 @@ private:
template <class ELFT> class RelocationTable : public Section<ELFT> {
public:
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
RelocationTable(const ELFLinkingContext &context, StringRef str,
int32_t order)
: Section<ELFT>(context, str), _symbolTable(nullptr) {
this->setOrder(order);
this->_entSize = sizeof(Elf_Rela);
this->_align2 = llvm::alignOf<Elf_Rela>();
this->_type = SHT_RELA;
this->_flags = SHF_ALLOC;
if (context.isRelaOutputFormat()) {
this->_entSize = sizeof(Elf_Rela);
this->_align2 = llvm::alignOf<Elf_Rela>();
this->_type = SHT_RELA;
} else {
this->_entSize = sizeof(Elf_Rel);
this->_align2 = llvm::alignOf<Elf_Rel>();
this->_type = SHT_REL;
}
}
/// \returns the index of the relocation added.
uint32_t addRelocation(const DefinedAtom &da, const Reference &r) {
_relocs.emplace_back(&da, &r);
this->_fsize = _relocs.size() * sizeof(Elf_Rela);
this->_fsize = _relocs.size() * this->_entSize;
this->_msize = this->_fsize;
return _relocs.size() - 1;
}
@ -945,34 +952,52 @@ public:
}
virtual void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
uint8_t *chunkBuffer = buffer.getBufferStart();
uint8_t *dest = chunkBuffer + this->fileOffset();
uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
for (const auto &rel : _relocs) {
Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest);
uint32_t index =
_symbolTable ? _symbolTable->getSymbolTableIndex(rel.second->target())
: (uint32_t) STN_UNDEF;
r->setSymbolAndType(index, rel.second->kindValue());
r->r_offset =
writer->addressOfAtom(rel.first) + rel.second->offsetInAtom();
r->r_addend = 0;
// The addend is used only by relative relocations
if (this->_context.isRelativeReloc(*rel.second))
r->r_addend =
writer->addressOfAtom(rel.second->target()) + rel.second->addend();
dest += sizeof(Elf_Rela);
DEBUG_WITH_TYPE("ELFRelocationTable",
llvm::dbgs() << rel.second->kindValue()
<< " relocation at " << rel.first->name()
<< "@" << r->r_offset << " to "
<< rel.second->target()->name() << "@"
<< r->r_addend << "\n";);
if (this->_context.isRelaOutputFormat())
writeRela(writer, *reinterpret_cast<Elf_Rela *>(dest), *rel.first,
*rel.second);
else
writeRel(writer, *reinterpret_cast<Elf_Rel *>(dest), *rel.first,
*rel.second);
dest += this->_entSize;
}
}
private:
std::vector<std::pair<const DefinedAtom *, const Reference *> > _relocs;
const DynamicSymbolTable<ELFT> *_symbolTable;
void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
const Reference &ref) {
uint32_t index =
_symbolTable ? _symbolTable->getSymbolTableIndex(ref.target())
: (uint32_t)STN_UNDEF;
r.setSymbolAndType(index, ref.kindValue());
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
r.r_addend = 0;
// The addend is used only by relative relocations
if (this->_context.isRelativeReloc(ref))
r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
DEBUG_WITH_TYPE("ELFRelocationTable",
llvm::dbgs() << ref.kindValue() << " relocation at "
<< atom.name() << "@" << r.r_offset << " to "
<< ref.target()->name() << "@" << r.r_addend
<< "\n";);
}
void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
const Reference &ref) {
uint32_t index =
_symbolTable ? _symbolTable->getSymbolTableIndex(ref.target())
: (uint32_t)STN_UNDEF;
r.setSymbolAndType(index, ref.kindValue());
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
DEBUG_WITH_TYPE("ELFRelocationTable",
llvm::dbgs() << ref.kindValue() << " relocation at "
<< atom.name() << "@" << r.r_offset << " to "
<< ref.target()->name() << "\n";);
}
};
template <class ELFT> class HashSection;
@ -1017,6 +1042,8 @@ public:
}
virtual void createDefaultEntries() {
bool isRela = this->_context.isRelaOutputFormat();
Elf_Dyn dyn;
dyn.d_un.d_val = 0;
@ -1035,11 +1062,11 @@ public:
dyn.d_tag = DT_FINI_ARRAYSZ;
_dt_fini_arraysz = addEntry(dyn);
if (_layout->hasDynamicRelocationTable()) {
dyn.d_tag = DT_RELA;
dyn.d_tag = isRela ? DT_RELA : DT_REL;
_dt_rela = addEntry(dyn);
dyn.d_tag = DT_RELASZ;
dyn.d_tag = isRela ? DT_RELASZ : DT_RELSZ;
_dt_relasz = addEntry(dyn);
dyn.d_tag = DT_RELAENT;
dyn.d_tag = isRela ? DT_RELAENT : DT_RELENT;
_dt_relaent = addEntry(dyn);
}
if (_layout->hasPLTRelocationTable()) {
@ -1048,7 +1075,7 @@ public:
dyn.d_tag = DT_PLTGOT;
_dt_pltgot = addEntry(dyn);
dyn.d_tag = DT_PLTREL;
dyn.d_un.d_val = DT_RELA;
dyn.d_un.d_val = isRela ? DT_RELA : DT_REL;
_dt_pltrel = addEntry(dyn);
dyn.d_un.d_val = 0;
dyn.d_tag = DT_JMPREL;

View File

@ -0,0 +1,48 @@
# Check MIPS specific tags in the dynamic table in case executable linking.
# Build shared library
# RUN: llvm-mc -triple=mipsel -filetype=obj -relocation-model=pic \
# RUN: -o=%t-obj %p/Inputs/ext.s
# RUN: lld -flavor gnu -target mipsel -shared -o %t-so %t-obj
# Build executable
# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-obj %s
# RUN: lld -flavor gnu -target mipsel -e glob -o %t-exe %t-obj %t-so
# RUN: llvm-readobj -dynamic-table %t-exe | FileCheck %s
# CHECK: Format: ELF32-mips
# CHECK: Arch: mipsel
# CHECK: AddressSize: 32bit
# CHECK: LoadName:
# CHECK: DynamicSection [ (20 entries)
# CHECK: Tag Type Name/Value
# CHECK: 0x00000004 HASH 0x400110
# CHECK: 0x00000005 STRTAB 0x400144
# CHECK: 0x00000006 SYMTAB 0x400124
# CHECK: 0x0000000A STRSZ 30 (bytes)
# CHECK: 0x0000000B SYMENT 16 (bytes)
# CHECK: 0x0000001A FINI_ARRAY 0x0
# CHECK: 0x0000001C FINI_ARRAYSZ 0 (bytes)
# CHECK: 0x00000002 PLTRELSZ 8 (bytes)
# CHECK: 0x00000003 PLTGOT 0x402000
# CHECK: 0x00000014 PLTREL REL
# CHECK: 0x00000017 JMPREL 0x400162
# CHECK: 0x70000001 MIPS_RLD_VERSION 1
# CHECK: 0x70000005 MIPS_FLAGS 0x2
# CHECK: 0x70000006 MIPS_BASE_ADDRESS 0x400000
# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 2
# CHECK: 0x70000011 MIPS_SYMTABNO 2
# CHECK: 0x70000013 MIPS_GOTSYM 0x2
# CHECK: 0x00000001 NEEDED SharedLibrary (exe-dynamic.test.{{.*}})
# CHECK: 0x00000000 NULL 0x0
# CHECK: ]
.abicalls
.global glob
.ent glob
loc:
jal ext1
glob:
jal loc
jal glob
.end glob

View File

@ -27,7 +27,7 @@
# CHECK: Type: Executable (0x2)
# CHECK: Machine: EM_MIPS (0x8)
# CHECK: Version: 1
# CHECK: Entry: 0x4001B0
# CHECK: Entry: 0x4001A0
# CHECK: ProgramHeaderOffset: 0x34
# CHECK: SectionHeaderOffset: 0x2268
# CHECK: Flags [ (0x70001005)

View File

@ -24,7 +24,7 @@
# Executable file has the only relocation for external symbol
# EXE-REL: Relocations [
# EXE-REL: Section (5) .rela.plt {
# EXE-REL: Section (5) .rel.plt {
# EXE-REL: 0x402008 R_MIPS_JUMP_SLOT ext1 0x0
# EXE-REL: }
# EXE-REL: ]
@ -32,32 +32,32 @@
# EXE: Disassembly of section .plt:
# EXE: .plt:
# PLTA entry. Points to the .got.plt[1]
# EXE: 400190: 40 00 0f 3c lui $15, 64
# EXE: 400194: 08 20 f9 8d lw $25, 8200($15)
# EXE: 400198: 08 00 20 03 jr $25
# EXE: 40019c: 08 20 f8 25 addiu $24, $15, 8200
# EXE: 400180: 40 00 0f 3c lui $15, 64
# EXE: 400184: 08 20 f9 8d lw $25, 8200($15)
# EXE: 400188: 08 00 20 03 jr $25
# EXE: 40018c: 08 20 f8 25 addiu $24, $15, 8200
# EXE: Disassembly of section .text:
# EXE: glob:
# EXE: 4001a0: 09 f8 20 03 jalr $25
# EXE: 4001a4: 00 00 00 00 nop
# EXE: 400190: 09 f8 20 03 jalr $25
# EXE: 400194: 00 00 00 00 nop
#
# Jump to 'loc' label address
# EXE: 4001a8: 6c 00 10 0c jal 4194736
# EXE: 4001ac: 00 00 00 00 nop
# EXE: 400198: 6c 00 10 0c jal 4194736
# EXE: 40019c: 00 00 00 00 nop
#
# EXE: loc:
# Jump to 'glob' label address
# EXE: 4001b0: 68 00 10 0c jal 4194720
# EXE: 4001b4: 00 00 00 00 nop
# EXE: 4001a0: 64 00 10 0c jal 4194704
# EXE: 4001a4: 00 00 00 00 nop
#
# Jump to the first PLT entry (.plt + 32) for ext1 entry
# EXE: 4001b8: 64 00 10 0c jal 4194704
# EXE: 4001bc: 00 00 00 00 nop
# EXE: 4001a8: 60 00 10 0c jal 4194688
# EXE: 4001ac: 00 00 00 00 nop
# EXE: Sections:
# EXE: Idx Name Size Address Type
# EXE: 6 .plt 00000030 0000000000400170 TEXT DATA
# EXE: 6 .plt 00000030 0000000000400160 TEXT DATA
# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
.abicalls