You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
718 lines
26 KiB
718 lines
26 KiB
//===- ELFObjectWriter.cpp ------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/LD/ELFObjectWriter.h"
|
|
|
|
#include "mcld/LinkerConfig.h"
|
|
#include "mcld/LinkerScript.h"
|
|
#include "mcld/Module.h"
|
|
#include "mcld/ADT/SizeTraits.h"
|
|
#include "mcld/Fragment/AlignFragment.h"
|
|
#include "mcld/Fragment/FillFragment.h"
|
|
#include "mcld/Fragment/NullFragment.h"
|
|
#include "mcld/Fragment/RegionFragment.h"
|
|
#include "mcld/Fragment/Stub.h"
|
|
#include "mcld/LD/DebugString.h"
|
|
#include "mcld/LD/EhFrame.h"
|
|
#include "mcld/LD/ELFFileFormat.h"
|
|
#include "mcld/LD/ELFSegment.h"
|
|
#include "mcld/LD/ELFSegmentFactory.h"
|
|
#include "mcld/LD/LDSection.h"
|
|
#include "mcld/LD/LDSymbol.h"
|
|
#include "mcld/LD/RelocData.h"
|
|
#include "mcld/LD/SectionData.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
#include "mcld/Target/GNUInfo.h"
|
|
#include "mcld/Target/GNULDBackend.h"
|
|
|
|
#include <llvm/Support/Casting.h>
|
|
#include <llvm/Support/ELF.h>
|
|
#include <llvm/Support/Errc.h>
|
|
#include <llvm/Support/ErrorHandling.h>
|
|
|
|
namespace mcld {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ELFObjectWriter
|
|
//===----------------------------------------------------------------------===//
|
|
ELFObjectWriter::ELFObjectWriter(GNULDBackend& pBackend,
|
|
const LinkerConfig& pConfig)
|
|
: ObjectWriter(), m_Backend(pBackend), m_Config(pConfig) {
|
|
}
|
|
|
|
ELFObjectWriter::~ELFObjectWriter() {
|
|
}
|
|
|
|
void ELFObjectWriter::writeSection(Module& pModule,
|
|
FileOutputBuffer& pOutput,
|
|
LDSection* section) {
|
|
MemoryRegion region;
|
|
// Request output region
|
|
switch (section->kind()) {
|
|
case LDFileFormat::Note:
|
|
if (section->getSectionData() == NULL)
|
|
return;
|
|
// Fall through
|
|
case LDFileFormat::TEXT:
|
|
case LDFileFormat::DATA:
|
|
case LDFileFormat::Relocation:
|
|
case LDFileFormat::Target:
|
|
case LDFileFormat::Debug:
|
|
case LDFileFormat::DebugString:
|
|
case LDFileFormat::GCCExceptTable:
|
|
case LDFileFormat::EhFrame: {
|
|
region = pOutput.request(section->offset(), section->size());
|
|
if (region.size() == 0) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case LDFileFormat::Null:
|
|
case LDFileFormat::NamePool:
|
|
case LDFileFormat::BSS:
|
|
case LDFileFormat::MetaData:
|
|
case LDFileFormat::Version:
|
|
case LDFileFormat::EhFrameHdr:
|
|
case LDFileFormat::StackNote:
|
|
// Ignore these sections
|
|
return;
|
|
default:
|
|
llvm::errs() << "WARNING: unsupported section kind: " << section->kind()
|
|
<< " of section " << section->name() << ".\n";
|
|
return;
|
|
}
|
|
|
|
// Write out sections with data
|
|
switch (section->kind()) {
|
|
case LDFileFormat::GCCExceptTable:
|
|
case LDFileFormat::TEXT:
|
|
case LDFileFormat::DATA:
|
|
case LDFileFormat::Debug:
|
|
case LDFileFormat::Note:
|
|
emitSectionData(*section, region);
|
|
break;
|
|
case LDFileFormat::EhFrame:
|
|
emitEhFrame(pModule, *section->getEhFrame(), region);
|
|
break;
|
|
case LDFileFormat::Relocation:
|
|
// sort relocation for the benefit of the dynamic linker.
|
|
target().sortRelocation(*section);
|
|
|
|
emitRelocation(m_Config, *section, region);
|
|
break;
|
|
case LDFileFormat::Target:
|
|
target().emitSectionData(*section, region);
|
|
break;
|
|
case LDFileFormat::DebugString:
|
|
section->getDebugString()->emit(region);
|
|
break;
|
|
default:
|
|
llvm_unreachable("invalid section kind");
|
|
}
|
|
}
|
|
|
|
std::error_code ELFObjectWriter::writeObject(Module& pModule,
|
|
FileOutputBuffer& pOutput) {
|
|
bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
|
|
bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
|
|
bool is_binary = m_Config.codeGenType() == LinkerConfig::Binary;
|
|
bool is_object = m_Config.codeGenType() == LinkerConfig::Object;
|
|
|
|
assert(is_dynobj || is_exec || is_binary || is_object);
|
|
|
|
if (is_dynobj || is_exec) {
|
|
// Allow backend to sort symbols before emitting
|
|
target().orderSymbolTable(pModule);
|
|
|
|
// Write out the interpreter section: .interp
|
|
target().emitInterp(pOutput);
|
|
|
|
// Write out name pool sections: .dynsym, .dynstr, .hash
|
|
target().emitDynNamePools(pModule, pOutput);
|
|
}
|
|
|
|
if (is_object || is_dynobj || is_exec) {
|
|
// Write out name pool sections: .symtab, .strtab
|
|
target().emitRegNamePools(pModule, pOutput);
|
|
}
|
|
|
|
if (is_binary) {
|
|
// Iterate over the loadable segments and write the corresponding sections
|
|
ELFSegmentFactory::iterator seg, segEnd = target().elfSegmentTable().end();
|
|
|
|
for (seg = target().elfSegmentTable().begin(); seg != segEnd; ++seg) {
|
|
if (llvm::ELF::PT_LOAD == (*seg)->type()) {
|
|
ELFSegment::iterator sect, sectEnd = (*seg)->end();
|
|
for (sect = (*seg)->begin(); sect != sectEnd; ++sect)
|
|
writeSection(pModule, pOutput, *sect);
|
|
}
|
|
}
|
|
} else {
|
|
// Write out regular ELF sections
|
|
Module::iterator sect, sectEnd = pModule.end();
|
|
for (sect = pModule.begin(); sect != sectEnd; ++sect)
|
|
writeSection(pModule, pOutput, *sect);
|
|
|
|
emitShStrTab(target().getOutputFormat()->getShStrTab(), pModule, pOutput);
|
|
|
|
if (m_Config.targets().is32Bits()) {
|
|
// Write out ELF header
|
|
// Write out section header table
|
|
writeELFHeader<32>(m_Config, pModule, pOutput);
|
|
if (is_dynobj || is_exec)
|
|
emitProgramHeader<32>(pOutput);
|
|
|
|
emitSectionHeader<32>(pModule, m_Config, pOutput);
|
|
} else if (m_Config.targets().is64Bits()) {
|
|
// Write out ELF header
|
|
// Write out section header table
|
|
writeELFHeader<64>(m_Config, pModule, pOutput);
|
|
if (is_dynobj || is_exec)
|
|
emitProgramHeader<64>(pOutput);
|
|
|
|
emitSectionHeader<64>(pModule, m_Config, pOutput);
|
|
} else {
|
|
return llvm::make_error_code(llvm::errc::function_not_supported);
|
|
}
|
|
}
|
|
|
|
return std::error_code();
|
|
}
|
|
|
|
// getOutputSize - count the final output size
|
|
size_t ELFObjectWriter::getOutputSize(const Module& pModule) const {
|
|
if (m_Config.targets().is32Bits()) {
|
|
return getLastStartOffset<32>(pModule) +
|
|
sizeof(ELFSizeTraits<32>::Shdr) * pModule.size();
|
|
} else if (m_Config.targets().is64Bits()) {
|
|
return getLastStartOffset<64>(pModule) +
|
|
sizeof(ELFSizeTraits<64>::Shdr) * pModule.size();
|
|
} else {
|
|
assert(0 && "Invalid ELF Class");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// writeELFHeader - emit ElfXX_Ehdr
|
|
template <size_t SIZE>
|
|
void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig,
|
|
const Module& pModule,
|
|
FileOutputBuffer& pOutput) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
|
|
typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
|
|
typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
|
|
|
|
// ELF header must start from 0x0
|
|
MemoryRegion region = pOutput.request(0, sizeof(ElfXX_Ehdr));
|
|
ElfXX_Ehdr* header = reinterpret_cast<ElfXX_Ehdr*>(region.begin());
|
|
|
|
memcpy(header->e_ident, llvm::ELF::ElfMagic, llvm::ELF::EI_MAG3 + 1);
|
|
|
|
header->e_ident[llvm::ELF::EI_CLASS] =
|
|
(SIZE == 32) ? llvm::ELF::ELFCLASS32 : llvm::ELF::ELFCLASS64;
|
|
header->e_ident[llvm::ELF::EI_DATA] =
|
|
pConfig.targets().isLittleEndian()
|
|
? llvm::ELF::ELFDATA2LSB : llvm::ELF::ELFDATA2MSB;
|
|
header->e_ident[llvm::ELF::EI_VERSION] = target().getInfo().ELFVersion();
|
|
header->e_ident[llvm::ELF::EI_OSABI] = target().getInfo().OSABI();
|
|
header->e_ident[llvm::ELF::EI_ABIVERSION] = target().getInfo().ABIVersion();
|
|
|
|
// FIXME: add processor-specific and core file types.
|
|
switch (pConfig.codeGenType()) {
|
|
case LinkerConfig::Object:
|
|
header->e_type = llvm::ELF::ET_REL;
|
|
break;
|
|
case LinkerConfig::DynObj:
|
|
header->e_type = llvm::ELF::ET_DYN;
|
|
break;
|
|
case LinkerConfig::Exec:
|
|
header->e_type = llvm::ELF::ET_EXEC;
|
|
break;
|
|
default:
|
|
llvm::errs() << "unspported output file type: " << pConfig.codeGenType()
|
|
<< ".\n";
|
|
header->e_type = llvm::ELF::ET_NONE;
|
|
}
|
|
header->e_machine = target().getInfo().machine();
|
|
header->e_version = header->e_ident[llvm::ELF::EI_VERSION];
|
|
header->e_entry = getEntryPoint(pConfig, pModule);
|
|
|
|
if (LinkerConfig::Object != pConfig.codeGenType())
|
|
header->e_phoff = sizeof(ElfXX_Ehdr);
|
|
else
|
|
header->e_phoff = 0x0;
|
|
|
|
header->e_shoff = getLastStartOffset<SIZE>(pModule);
|
|
header->e_flags = target().getInfo().flags();
|
|
header->e_ehsize = sizeof(ElfXX_Ehdr);
|
|
header->e_phentsize = sizeof(ElfXX_Phdr);
|
|
header->e_phnum = target().elfSegmentTable().size();
|
|
header->e_shentsize = sizeof(ElfXX_Shdr);
|
|
header->e_shnum = pModule.size();
|
|
header->e_shstrndx = pModule.getSection(".shstrtab")->index();
|
|
}
|
|
|
|
/// getEntryPoint
|
|
uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig,
|
|
const Module& pModule) const {
|
|
llvm::StringRef entry_name = target().getEntry(pModule);
|
|
uint64_t result = 0x0;
|
|
|
|
bool issue_warning = (pModule.getScript().hasEntry() &&
|
|
LinkerConfig::Object != pConfig.codeGenType() &&
|
|
LinkerConfig::DynObj != pConfig.codeGenType());
|
|
|
|
const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name);
|
|
|
|
// found the symbol
|
|
if (entry_symbol != NULL) {
|
|
if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
|
|
llvm::errs() << "WARNING: entry symbol '" << entry_symbol->name()
|
|
<< "' exists but is not defined.\n";
|
|
}
|
|
result = entry_symbol->value();
|
|
} else {
|
|
// not in the symbol pool
|
|
// We should parse entry as a number.
|
|
// @ref GNU ld manual, Options -e. e.g., -e 0x1000.
|
|
char* endptr;
|
|
result = strtoull(entry_name.data(), &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
if (issue_warning) {
|
|
llvm::errs() << "cannot find entry symbol '" << entry_name.data()
|
|
<< "'.\n";
|
|
}
|
|
result = 0x0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// emitSectionHeader - emit ElfXX_Shdr
|
|
template <size_t SIZE>
|
|
void ELFObjectWriter::emitSectionHeader(const Module& pModule,
|
|
const LinkerConfig& pConfig,
|
|
FileOutputBuffer& pOutput) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
|
|
|
|
// emit section header
|
|
unsigned int sectNum = pModule.size();
|
|
unsigned int header_size = sizeof(ElfXX_Shdr) * sectNum;
|
|
MemoryRegion region =
|
|
pOutput.request(getLastStartOffset<SIZE>(pModule), header_size);
|
|
ElfXX_Shdr* shdr = reinterpret_cast<ElfXX_Shdr*>(region.begin());
|
|
|
|
// Iterate the SectionTable in LDContext
|
|
unsigned int sectIdx = 0;
|
|
unsigned int shstridx = 0; // NULL section has empty name
|
|
for (; sectIdx < sectNum; ++sectIdx) {
|
|
const LDSection* ld_sect = pModule.getSectionTable().at(sectIdx);
|
|
shdr[sectIdx].sh_name = shstridx;
|
|
shdr[sectIdx].sh_type = ld_sect->type();
|
|
shdr[sectIdx].sh_flags = ld_sect->flag();
|
|
shdr[sectIdx].sh_addr = ld_sect->addr();
|
|
shdr[sectIdx].sh_offset = ld_sect->offset();
|
|
shdr[sectIdx].sh_size = ld_sect->size();
|
|
shdr[sectIdx].sh_addralign = ld_sect->align();
|
|
shdr[sectIdx].sh_entsize = getSectEntrySize<SIZE>(*ld_sect);
|
|
shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig);
|
|
shdr[sectIdx].sh_info = getSectInfo(*ld_sect);
|
|
|
|
// adjust strshidx
|
|
shstridx += ld_sect->name().size() + 1;
|
|
}
|
|
}
|
|
|
|
// emitProgramHeader - emit ElfXX_Phdr
|
|
template <size_t SIZE>
|
|
void ELFObjectWriter::emitProgramHeader(FileOutputBuffer& pOutput) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
|
|
typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
|
|
|
|
uint64_t start_offset, phdr_size;
|
|
|
|
start_offset = sizeof(ElfXX_Ehdr);
|
|
phdr_size = sizeof(ElfXX_Phdr);
|
|
// Program header must start directly after ELF header
|
|
MemoryRegion region = pOutput.request(
|
|
start_offset, target().elfSegmentTable().size() * phdr_size);
|
|
|
|
ElfXX_Phdr* phdr = reinterpret_cast<ElfXX_Phdr*>(region.begin());
|
|
|
|
// Iterate the elf segment table in GNULDBackend
|
|
size_t index = 0;
|
|
ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(),
|
|
segEnd = target().elfSegmentTable().end();
|
|
for (; seg != segEnd; ++seg, ++index) {
|
|
phdr[index].p_type = (*seg)->type();
|
|
phdr[index].p_flags = (*seg)->flag();
|
|
phdr[index].p_offset = (*seg)->offset();
|
|
phdr[index].p_vaddr = (*seg)->vaddr();
|
|
phdr[index].p_paddr = (*seg)->paddr();
|
|
phdr[index].p_filesz = (*seg)->filesz();
|
|
phdr[index].p_memsz = (*seg)->memsz();
|
|
phdr[index].p_align = (*seg)->align();
|
|
}
|
|
}
|
|
|
|
/// emitShStrTab - emit section string table
|
|
void ELFObjectWriter::emitShStrTab(const LDSection& pShStrTab,
|
|
const Module& pModule,
|
|
FileOutputBuffer& pOutput) {
|
|
// write out data
|
|
MemoryRegion region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
|
|
char* data = reinterpret_cast<char*>(region.begin());
|
|
size_t shstrsize = 0;
|
|
Module::const_iterator section, sectEnd = pModule.end();
|
|
for (section = pModule.begin(); section != sectEnd; ++section) {
|
|
::memcpy(reinterpret_cast<char*>(data + shstrsize),
|
|
(*section)->name().data(),
|
|
(*section)->name().size());
|
|
shstrsize += (*section)->name().size() + 1;
|
|
}
|
|
}
|
|
|
|
/// emitSectionData
|
|
void ELFObjectWriter::emitSectionData(const LDSection& pSection,
|
|
MemoryRegion& pRegion) const {
|
|
const SectionData* sd = NULL;
|
|
switch (pSection.kind()) {
|
|
case LDFileFormat::Relocation:
|
|
assert(pSection.hasRelocData());
|
|
return;
|
|
case LDFileFormat::EhFrame:
|
|
assert(pSection.hasEhFrame());
|
|
sd = pSection.getEhFrame()->getSectionData();
|
|
break;
|
|
default:
|
|
assert(pSection.hasSectionData());
|
|
sd = pSection.getSectionData();
|
|
break;
|
|
}
|
|
emitSectionData(*sd, pRegion);
|
|
}
|
|
|
|
/// emitEhFrame
|
|
void ELFObjectWriter::emitEhFrame(Module& pModule,
|
|
EhFrame& pFrame,
|
|
MemoryRegion& pRegion) const {
|
|
emitSectionData(*pFrame.getSectionData(), pRegion);
|
|
|
|
// Patch FDE field (offset to CIE)
|
|
for (EhFrame::cie_iterator i = pFrame.cie_begin(), e = pFrame.cie_end();
|
|
i != e;
|
|
++i) {
|
|
EhFrame::CIE& cie = **i;
|
|
for (EhFrame::fde_iterator fi = cie.begin(), fe = cie.end(); fi != fe;
|
|
++fi) {
|
|
EhFrame::FDE& fde = **fi;
|
|
if (fde.getRecordType() == EhFrame::RECORD_GENERATED) {
|
|
// Patch PLT offset
|
|
LDSection* plt_sect = pModule.getSection(".plt");
|
|
assert(plt_sect && "We have no plt but have corresponding eh_frame?");
|
|
uint64_t plt_offset = plt_sect->offset();
|
|
// FDE entry for PLT is always 32-bit
|
|
uint64_t fde_offset = pFrame.getSection().offset() + fde.getOffset() +
|
|
EhFrame::getDataStartOffset<32>();
|
|
int32_t offset = fde_offset - plt_offset;
|
|
if (plt_offset < fde_offset)
|
|
offset = -offset;
|
|
memcpy(pRegion.begin() + fde.getOffset() +
|
|
EhFrame::getDataStartOffset<32>(),
|
|
&offset,
|
|
4);
|
|
uint32_t size = plt_sect->size();
|
|
memcpy(pRegion.begin() + fde.getOffset() +
|
|
EhFrame::getDataStartOffset<32>() + 4,
|
|
&size,
|
|
4);
|
|
}
|
|
uint64_t fde_cie_ptr_offset = fde.getOffset() +
|
|
EhFrame::getDataStartOffset<32>() -
|
|
/*ID*/ 4;
|
|
uint64_t cie_start_offset = cie.getOffset();
|
|
int32_t offset = fde_cie_ptr_offset - cie_start_offset;
|
|
if (fde_cie_ptr_offset < cie_start_offset)
|
|
offset = -offset;
|
|
memcpy(pRegion.begin() + fde_cie_ptr_offset, &offset, 4);
|
|
} // for loop fde_iterator
|
|
} // for loop cie_iterator
|
|
}
|
|
|
|
/// emitRelocation
|
|
void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig,
|
|
const LDSection& pSection,
|
|
MemoryRegion& pRegion) const {
|
|
const RelocData* sect_data = pSection.getRelocData();
|
|
assert(sect_data != NULL && "SectionData is NULL in emitRelocation!");
|
|
|
|
if (pSection.type() == llvm::ELF::SHT_REL) {
|
|
if (pConfig.targets().is32Bits())
|
|
emitRel<32>(pConfig, *sect_data, pRegion);
|
|
else if (pConfig.targets().is64Bits())
|
|
emitRel<64>(pConfig, *sect_data, pRegion);
|
|
else {
|
|
fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
|
|
<< pConfig.targets().bitclass();
|
|
}
|
|
} else if (pSection.type() == llvm::ELF::SHT_RELA) {
|
|
if (pConfig.targets().is32Bits())
|
|
emitRela<32>(pConfig, *sect_data, pRegion);
|
|
else if (pConfig.targets().is64Bits())
|
|
emitRela<64>(pConfig, *sect_data, pRegion);
|
|
else {
|
|
fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
|
|
<< pConfig.targets().bitclass();
|
|
}
|
|
} else
|
|
llvm::report_fatal_error("unsupported relocation section type!");
|
|
}
|
|
|
|
// emitRel - emit ElfXX_Rel
|
|
template <size_t SIZE>
|
|
void ELFObjectWriter::emitRel(const LinkerConfig& pConfig,
|
|
const RelocData& pRelocData,
|
|
MemoryRegion& pRegion) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel;
|
|
typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
|
|
typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
|
|
|
|
ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.begin());
|
|
|
|
const Relocation* relocation = 0;
|
|
const FragmentRef* frag_ref = 0;
|
|
|
|
for (RelocData::const_iterator it = pRelocData.begin(), ie = pRelocData.end();
|
|
it != ie;
|
|
++it, ++rel) {
|
|
ElfXX_Addr r_offset = 0;
|
|
ElfXX_Word r_sym = 0;
|
|
|
|
relocation = &(llvm::cast<Relocation>(*it));
|
|
frag_ref = &(relocation->targetRef());
|
|
|
|
if (LinkerConfig::DynObj == pConfig.codeGenType() ||
|
|
LinkerConfig::Exec == pConfig.codeGenType()) {
|
|
r_offset = static_cast<ElfXX_Addr>(
|
|
frag_ref->frag()->getParent()->getSection().addr() +
|
|
frag_ref->getOutputOffset());
|
|
} else {
|
|
r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
|
|
}
|
|
|
|
if (relocation->symInfo() == NULL)
|
|
r_sym = 0;
|
|
else
|
|
r_sym = static_cast<ElfXX_Word>(
|
|
target().getSymbolIdx(relocation->symInfo()->outSymbol()));
|
|
|
|
target().emitRelocation(*rel, relocation->type(), r_sym, r_offset);
|
|
}
|
|
}
|
|
|
|
// emitRela - emit ElfXX_Rela
|
|
template <size_t SIZE>
|
|
void ELFObjectWriter::emitRela(const LinkerConfig& pConfig,
|
|
const RelocData& pRelocData,
|
|
MemoryRegion& pRegion) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
|
|
typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
|
|
typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
|
|
|
|
ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.begin());
|
|
|
|
const Relocation* relocation = 0;
|
|
const FragmentRef* frag_ref = 0;
|
|
|
|
for (RelocData::const_iterator it = pRelocData.begin(), ie = pRelocData.end();
|
|
it != ie;
|
|
++it, ++rel) {
|
|
ElfXX_Addr r_offset = 0;
|
|
ElfXX_Word r_sym = 0;
|
|
|
|
relocation = &(llvm::cast<Relocation>(*it));
|
|
frag_ref = &(relocation->targetRef());
|
|
|
|
if (LinkerConfig::DynObj == pConfig.codeGenType() ||
|
|
LinkerConfig::Exec == pConfig.codeGenType()) {
|
|
r_offset = static_cast<ElfXX_Addr>(
|
|
frag_ref->frag()->getParent()->getSection().addr() +
|
|
frag_ref->getOutputOffset());
|
|
} else {
|
|
r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
|
|
}
|
|
|
|
if (relocation->symInfo() == NULL)
|
|
r_sym = 0;
|
|
else
|
|
r_sym = static_cast<ElfXX_Word>(
|
|
target().getSymbolIdx(relocation->symInfo()->outSymbol()));
|
|
|
|
target().emitRelocation(
|
|
*rel, relocation->type(), r_sym, r_offset, relocation->addend());
|
|
}
|
|
}
|
|
|
|
/// getSectEntrySize - compute ElfXX_Shdr::sh_entsize
|
|
template <size_t SIZE>
|
|
uint64_t ELFObjectWriter::getSectEntrySize(const LDSection& pSection) const {
|
|
typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
|
|
typedef typename ELFSizeTraits<SIZE>::Sym ElfXX_Sym;
|
|
typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel;
|
|
typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
|
|
typedef typename ELFSizeTraits<SIZE>::Dyn ElfXX_Dyn;
|
|
|
|
if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
|
|
llvm::ELF::SHT_SYMTAB == pSection.type())
|
|
return sizeof(ElfXX_Sym);
|
|
if (llvm::ELF::SHT_REL == pSection.type())
|
|
return sizeof(ElfXX_Rel);
|
|
if (llvm::ELF::SHT_RELA == pSection.type())
|
|
return sizeof(ElfXX_Rela);
|
|
if (llvm::ELF::SHT_HASH == pSection.type() ||
|
|
llvm::ELF::SHT_GNU_HASH == pSection.type())
|
|
return sizeof(ElfXX_Word);
|
|
if (llvm::ELF::SHT_DYNAMIC == pSection.type())
|
|
return sizeof(ElfXX_Dyn);
|
|
// FIXME: We should get the entsize from input since the size of each
|
|
// character is specified in the section header's sh_entsize field.
|
|
// For example, traditional string is 0x1, UCS-2 is 0x2, ... and so on.
|
|
// Ref: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html
|
|
if (pSection.flag() & llvm::ELF::SHF_STRINGS)
|
|
return 0x1;
|
|
return 0x0;
|
|
}
|
|
|
|
/// getSectLink - compute ElfXX_Shdr::sh_link
|
|
uint64_t ELFObjectWriter::getSectLink(const LDSection& pSection,
|
|
const LinkerConfig& pConfig) const {
|
|
if (llvm::ELF::SHT_SYMTAB == pSection.type())
|
|
return target().getOutputFormat()->getStrTab().index();
|
|
if (llvm::ELF::SHT_DYNSYM == pSection.type())
|
|
return target().getOutputFormat()->getDynStrTab().index();
|
|
if (llvm::ELF::SHT_DYNAMIC == pSection.type())
|
|
return target().getOutputFormat()->getDynStrTab().index();
|
|
if (llvm::ELF::SHT_HASH == pSection.type() ||
|
|
llvm::ELF::SHT_GNU_HASH == pSection.type())
|
|
return target().getOutputFormat()->getDynSymTab().index();
|
|
if (llvm::ELF::SHT_REL == pSection.type() ||
|
|
llvm::ELF::SHT_RELA == pSection.type()) {
|
|
if (LinkerConfig::Object == pConfig.codeGenType())
|
|
return target().getOutputFormat()->getSymTab().index();
|
|
else
|
|
return target().getOutputFormat()->getDynSymTab().index();
|
|
}
|
|
// FIXME: currently we link ARM_EXIDX section to output text section here
|
|
if (llvm::ELF::SHT_ARM_EXIDX == pSection.type())
|
|
return target().getOutputFormat()->getText().index();
|
|
return llvm::ELF::SHN_UNDEF;
|
|
}
|
|
|
|
/// getSectInfo - compute ElfXX_Shdr::sh_info
|
|
uint64_t ELFObjectWriter::getSectInfo(const LDSection& pSection) const {
|
|
if (llvm::ELF::SHT_SYMTAB == pSection.type() ||
|
|
llvm::ELF::SHT_DYNSYM == pSection.type())
|
|
return pSection.getInfo();
|
|
|
|
if (llvm::ELF::SHT_REL == pSection.type() ||
|
|
llvm::ELF::SHT_RELA == pSection.type()) {
|
|
const LDSection* info_link = pSection.getLink();
|
|
if (info_link != NULL)
|
|
return info_link->index();
|
|
}
|
|
|
|
return 0x0;
|
|
}
|
|
|
|
/// getLastStartOffset
|
|
template <>
|
|
uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const {
|
|
const LDSection* lastSect = pModule.back();
|
|
assert(lastSect != NULL);
|
|
return Align<32>(lastSect->offset() + lastSect->size());
|
|
}
|
|
|
|
/// getLastStartOffset
|
|
template <>
|
|
uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const {
|
|
const LDSection* lastSect = pModule.back();
|
|
assert(lastSect != NULL);
|
|
return Align<64>(lastSect->offset() + lastSect->size());
|
|
}
|
|
|
|
/// emitSectionData
|
|
void ELFObjectWriter::emitSectionData(const SectionData& pSD,
|
|
MemoryRegion& pRegion) const {
|
|
SectionData::const_iterator fragIter, fragEnd = pSD.end();
|
|
size_t cur_offset = 0;
|
|
for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) {
|
|
size_t size = fragIter->size();
|
|
switch (fragIter->getKind()) {
|
|
case Fragment::Region: {
|
|
const RegionFragment& region_frag =
|
|
llvm::cast<RegionFragment>(*fragIter);
|
|
const char* from = region_frag.getRegion().begin();
|
|
memcpy(pRegion.begin() + cur_offset, from, size);
|
|
break;
|
|
}
|
|
case Fragment::Alignment: {
|
|
// TODO: emit values with different sizes (> 1 byte), and emit nops
|
|
const AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter);
|
|
uint64_t count = size / align_frag.getValueSize();
|
|
switch (align_frag.getValueSize()) {
|
|
case 1u:
|
|
std::memset(
|
|
pRegion.begin() + cur_offset, align_frag.getValue(), count);
|
|
break;
|
|
default:
|
|
llvm::report_fatal_error(
|
|
"unsupported value size for align fragment emission yet.\n");
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case Fragment::Fillment: {
|
|
const FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter);
|
|
if (0 == size || 0 == fill_frag.getValueSize() ||
|
|
0 == fill_frag.size()) {
|
|
// ignore virtual fillment
|
|
break;
|
|
}
|
|
|
|
uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize();
|
|
for (uint64_t i = 0; i != num_tiles; ++i) {
|
|
std::memset(pRegion.begin() + cur_offset,
|
|
fill_frag.getValue(),
|
|
fill_frag.getValueSize());
|
|
}
|
|
break;
|
|
}
|
|
case Fragment::Stub: {
|
|
const Stub& stub_frag = llvm::cast<Stub>(*fragIter);
|
|
memcpy(pRegion.begin() + cur_offset, stub_frag.getContent(), size);
|
|
break;
|
|
}
|
|
case Fragment::Null: {
|
|
assert(0x0 == size);
|
|
break;
|
|
}
|
|
case Fragment::Target:
|
|
llvm::report_fatal_error(
|
|
"Target fragment should not be in a regular section.\n");
|
|
break;
|
|
default:
|
|
llvm::report_fatal_error(
|
|
"invalid fragment should not be in a regular section.\n");
|
|
break;
|
|
}
|
|
cur_offset += size;
|
|
}
|
|
}
|
|
|
|
} // namespace mcld
|