llvm/lib/MC/ELFObjectWriter.cpp

1655 lines
57 KiB
C++
Raw Normal View History

//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements ELF object file writer information.
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELF.h"
#include "llvm/MC/MCELFSymbolFlags.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include <vector>
using namespace llvm;
#undef DEBUG_TYPE
#define DEBUG_TYPE "reloc-info"
namespace {
class ELFObjectWriter : public MCObjectWriter {
protected:
static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);
static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant);
static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout);
static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data,
bool Used, bool Renamed);
static bool isLocal(const MCSymbolData &Data, bool isSignature,
bool isUsedInReloc);
static bool IsELFMetaDataSection(const MCSectionData &SD);
static uint64_t DataSectionSize(const MCSectionData &SD);
static uint64_t GetSectionFileSize(const MCAsmLayout &Layout,
const MCSectionData &SD);
static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout,
const MCSectionData &SD);
void WriteDataSectionData(MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCSectionELF &Section);
/*static bool isFixupKindX86RIPRel(unsigned Kind) {
return Kind == X86::reloc_riprel_4byte ||
Kind == X86::reloc_riprel_4byte_movq_load;
}*/
/// ELFSymbolData - Helper struct for containing some precomputed
/// information on symbols.
struct ELFSymbolData {
MCSymbolData *SymbolData;
uint64_t StringIndex;
uint32_t SectionIndex;
// Support lexicographic sorting.
bool operator<(const ELFSymbolData &RHS) const {
return SymbolData->getSymbol().getName() <
RHS.SymbolData->getSymbol().getName();
}
};
/// The target specific ELF writer instance.
std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter;
SmallPtrSet<const MCSymbol *, 16> UsedInReloc;
SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc;
DenseMap<const MCSymbol *, const MCSymbol *> Renames;
llvm::DenseMap<const MCSectionData*,
std::vector<ELFRelocationEntry> > Relocations;
DenseMap<const MCSection*, uint64_t> SectionStringTableIndex;
/// @}
/// @name Symbol Table Data
/// @{
SmallString<256> StringTable;
std::vector<uint64_t> FileSymbolData;
std::vector<ELFSymbolData> LocalSymbolData;
std::vector<ELFSymbolData> ExternalSymbolData;
std::vector<ELFSymbolData> UndefinedSymbolData;
/// @}
bool NeedsGOT;
bool NeedsSymtabShndx;
// This holds the symbol table index of the last local symbol.
unsigned LastLocalSymbolIndex;
// This holds the .strtab section index.
unsigned StringTableIndex;
// This holds the .symtab section index.
unsigned SymbolTableIndex;
unsigned ShstrtabIndex;
const MCSymbol *SymbolToReloc(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const;
// TargetObjectWriter wrappers.
const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const {
return TargetObjectWriter->ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel);
}
const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
return TargetObjectWriter->undefinedExplicitRelSym(Target, Fixup,
IsPCRel);
}
bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
bool hasRelocationAddend() const {
return TargetObjectWriter->hasRelocationAddend();
}
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel, bool IsRelocWithSymbol,
int64_t Addend) const {
return TargetObjectWriter->GetRelocType(Target, Fixup, IsPCRel,
IsRelocWithSymbol, Addend);
}
public:
ELFObjectWriter(MCELFObjectTargetWriter *MOTW,
raw_ostream &_OS, bool IsLittleEndian)
: MCObjectWriter(_OS, IsLittleEndian),
TargetObjectWriter(MOTW),
NeedsGOT(false), NeedsSymtabShndx(false) {
}
virtual ~ELFObjectWriter();
void WriteWord(uint64_t W) {
if (is64Bit())
Write64(W);
else
Write32(W);
}
void StringLE16(char *buf, uint16_t Value) {
buf[0] = char(Value >> 0);
buf[1] = char(Value >> 8);
}
void StringLE32(char *buf, uint32_t Value) {
StringLE16(buf, uint16_t(Value >> 0));
StringLE16(buf + 2, uint16_t(Value >> 16));
}
void StringLE64(char *buf, uint64_t Value) {
StringLE32(buf, uint32_t(Value >> 0));
StringLE32(buf + 4, uint32_t(Value >> 32));
}
void StringBE16(char *buf ,uint16_t Value) {
buf[0] = char(Value >> 8);
buf[1] = char(Value >> 0);
}
void StringBE32(char *buf, uint32_t Value) {
StringBE16(buf, uint16_t(Value >> 16));
StringBE16(buf + 2, uint16_t(Value >> 0));
}
void StringBE64(char *buf, uint64_t Value) {
StringBE32(buf, uint32_t(Value >> 32));
StringBE32(buf + 4, uint32_t(Value >> 0));
}
void String8(MCDataFragment &F, uint8_t Value) {
char buf[1];
buf[0] = Value;
F.getContents().append(&buf[0], &buf[1]);
}
void String16(MCDataFragment &F, uint16_t Value) {
char buf[2];
if (isLittleEndian())
StringLE16(buf, Value);
else
StringBE16(buf, Value);
F.getContents().append(&buf[0], &buf[2]);
}
void String32(MCDataFragment &F, uint32_t Value) {
char buf[4];
if (isLittleEndian())
StringLE32(buf, Value);
else
StringBE32(buf, Value);
F.getContents().append(&buf[0], &buf[4]);
}
void String64(MCDataFragment &F, uint64_t Value) {
char buf[8];
if (isLittleEndian())
StringLE64(buf, Value);
else
StringBE64(buf, Value);
F.getContents().append(&buf[0], &buf[8]);
}
void WriteHeader(const MCAssembler &Asm,
uint64_t SectionDataSize,
unsigned NumberOfSections);
void WriteSymbolEntry(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
uint64_t name, uint8_t info,
uint64_t value, uint64_t size,
uint8_t other, uint32_t shndx,
bool Reserved);
void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF,
ELFSymbolData &MSD,
const MCAsmLayout &Layout);
typedef DenseMap<const MCSectionELF*, uint32_t> SectionIndexMapTy;
void WriteSymbolTable(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
const MCAssembler &Asm,
const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap);
virtual void RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup,
MCValue Target, uint64_t &FixedValue);
uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm,
const MCSymbol *S);
// Map from a group section to the signature symbol
typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy;
// Map from a signature symbol to the group section
typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy;
// Map from a section to the section with the relocations
typedef DenseMap<const MCSectionELF*, const MCSectionELF*> RelMapTy;
// Map from a section to its offset
typedef DenseMap<const MCSectionELF*, uint64_t> SectionOffsetMapTy;
/// ComputeSymbolTable - Compute the symbol table data
///
/// \param Asm - The assembler.
/// \param SectionIndexMap - Maps a section to its index.
/// \param RevGroupMap - Maps a signature symbol to the group section.
/// \param NumRegularSections - Number of non-relocation sections.
void ComputeSymbolTable(MCAssembler &Asm,
const SectionIndexMapTy &SectionIndexMap,
RevGroupMapTy RevGroupMap,
unsigned NumRegularSections);
void ComputeIndexMap(MCAssembler &Asm,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap);
void CreateRelocationSections(MCAssembler &Asm, MCAsmLayout &Layout,
RelMapTy &RelMap);
void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout,
const RelMapTy &RelMap);
void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap);
// Create the sections that show up in the symbol table. Currently
// those are the .note.GNU-stack section and the group sections.
void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout,
GroupMapTy &GroupMap,
RevGroupMapTy &RevGroupMap,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap);
virtual void ExecutePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout);
void WriteSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap,
const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetMapTy &SectionOffsetMap);
void ComputeSectionOrder(MCAssembler &Asm,
std::vector<const MCSectionELF*> &Sections);
void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
uint64_t Address, uint64_t Offset,
uint64_t Size, uint32_t Link, uint32_t Info,
uint64_t Alignment, uint64_t EntrySize);
void WriteRelocationsFragment(const MCAssembler &Asm,
MCDataFragment *F,
const MCSectionData *SD);
virtual bool
IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
const MCSymbolData &DataA,
const MCFragment &FB,
bool InSet,
bool IsPCRel) const;
virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout);
void WriteSection(MCAssembler &Asm,
const SectionIndexMapTy &SectionIndexMap,
uint32_t GroupSymbolIndex,
uint64_t Offset, uint64_t Size, uint64_t Alignment,
const MCSectionELF &Section);
};
}
bool ELFObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) {
const MCFixupKindInfo &FKI =
Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind);
return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel;
}
bool ELFObjectWriter::RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) {
switch (Variant) {
default:
return false;
case MCSymbolRefExpr::VK_GOT:
case MCSymbolRefExpr::VK_PLT:
case MCSymbolRefExpr::VK_GOTPCREL:
case MCSymbolRefExpr::VK_GOTOFF:
case MCSymbolRefExpr::VK_TPOFF:
case MCSymbolRefExpr::VK_TLSGD:
case MCSymbolRefExpr::VK_GOTTPOFF:
case MCSymbolRefExpr::VK_INDNTPOFF:
case MCSymbolRefExpr::VK_NTPOFF:
case MCSymbolRefExpr::VK_GOTNTPOFF:
case MCSymbolRefExpr::VK_TLSLDM:
case MCSymbolRefExpr::VK_DTPOFF:
case MCSymbolRefExpr::VK_TLSLD:
return true;
}
}
ELFObjectWriter::~ELFObjectWriter()
{}
// Emit the ELF header.
void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
uint64_t SectionDataSize,
unsigned NumberOfSections) {
// ELF Header
// ----------
//
// Note
// ----
// emitWord method behaves differently for ELF32 and ELF64, writing
// 4 bytes in the former and 8 in the latter.
Write8(0x7f); // e_ident[EI_MAG0]
Write8('E'); // e_ident[EI_MAG1]
Write8('L'); // e_ident[EI_MAG2]
Write8('F'); // e_ident[EI_MAG3]
Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS]
// e_ident[EI_DATA]
Write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB);
Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION]
// e_ident[EI_OSABI]
Write8(TargetObjectWriter->getOSABI());
Write8(0); // e_ident[EI_ABIVERSION]
WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD);
Write16(ELF::ET_REL); // e_type
Write16(TargetObjectWriter->getEMachine()); // e_machine = target
Write32(ELF::EV_CURRENT); // e_version
WriteWord(0); // e_entry, no entry point in .o file
WriteWord(0); // e_phoff, no program header for .o
WriteWord(SectionDataSize + (is64Bit() ? sizeof(ELF::Elf64_Ehdr) :
sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes
// e_flags = whatever the target wants
Write32(Asm.getELFHeaderEFlags());
// e_ehsize = ELF header size
Write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr));
Write16(0); // e_phentsize = prog header entry size
Write16(0); // e_phnum = # prog header entries = 0
// e_shentsize = Section header entry size
Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr));
// e_shnum = # of section header ents
if (NumberOfSections >= ELF::SHN_LORESERVE)
Write16(ELF::SHN_UNDEF);
else
Write16(NumberOfSections);
// e_shstrndx = Section # of '.shstrtab'
if (ShstrtabIndex >= ELF::SHN_LORESERVE)
Write16(ELF::SHN_XINDEX);
else
Write16(ShstrtabIndex);
}
void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
uint64_t name,
uint8_t info, uint64_t value,
uint64_t size, uint8_t other,
uint32_t shndx,
bool Reserved) {
if (ShndxF) {
if (shndx >= ELF::SHN_LORESERVE && !Reserved)
String32(*ShndxF, shndx);
else
String32(*ShndxF, 0);
}
uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ?
uint16_t(ELF::SHN_XINDEX) : shndx;
if (is64Bit()) {
String32(*SymtabF, name); // st_name
String8(*SymtabF, info); // st_info
String8(*SymtabF, other); // st_other
String16(*SymtabF, Index); // st_shndx
String64(*SymtabF, value); // st_value
String64(*SymtabF, size); // st_size
} else {
String32(*SymtabF, name); // st_name
String32(*SymtabF, value); // st_value
String32(*SymtabF, size); // st_size
String8(*SymtabF, info); // st_info
String8(*SymtabF, other); // st_other
String16(*SymtabF, Index); // st_shndx
}
}
uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data,
const MCAsmLayout &Layout) {
if (Data.isCommon() && Data.isExternal())
return Data.getCommonAlignment();
const MCSymbol &Symbol = Data.getSymbol();
if (Symbol.isAbsolute() && Symbol.isVariable()) {
if (const MCExpr *Value = Symbol.getVariableValue()) {
int64_t IntValue;
if (Value->EvaluateAsAbsolute(IntValue, Layout))
return (uint64_t)IntValue;
}
}
if (!Symbol.isInSection())
return 0;
if (Data.getFragment()) {
if (Data.getFlags() & ELF_Other_ThumbFunc)
return Layout.getSymbolOffset(&Data)+1;
else
return Layout.getSymbolOffset(&Data);
}
return 0;
}
void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// The presence of symbol versions causes undefined symbols and
// versions declared with @@@ to be renamed.
for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
ie = Asm.symbol_end(); it != ie; ++it) {
const MCSymbol &Alias = it->getSymbol();
const MCSymbol &Symbol = Alias.AliasedSymbol();
MCSymbolData &SD = Asm.getSymbolData(Symbol);
// Not an alias.
if (&Symbol == &Alias)
continue;
StringRef AliasName = Alias.getName();
size_t Pos = AliasName.find('@');
if (Pos == StringRef::npos)
continue;
// Aliases defined with .symvar copy the binding from the symbol they alias.
// This is the first place we are able to copy this information.
it->setExternal(SD.isExternal());
MCELF::SetBinding(*it, MCELF::GetBinding(SD));
StringRef Rest = AliasName.substr(Pos);
if (!Symbol.isUndefined() && !Rest.startswith("@@@"))
continue;
// FIXME: produce a better error message.
if (Symbol.isUndefined() && Rest.startswith("@@") &&
!Rest.startswith("@@@"))
report_fatal_error("A @@ version cannot be undefined");
Renames.insert(std::make_pair(&Symbol, &Alias));
}
}
static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) {
uint8_t Type = newType;
// Propagation rules:
// IFUNC > FUNC > OBJECT > NOTYPE
// TLS_OBJECT > OBJECT > NOTYPE
//
// dont let the new type degrade the old type
switch (origType) {
default:
break;
case ELF::STT_GNU_IFUNC:
if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT ||
Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS)
Type = ELF::STT_GNU_IFUNC;
break;
case ELF::STT_FUNC:
if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
Type == ELF::STT_TLS)
Type = ELF::STT_FUNC;
break;
case ELF::STT_OBJECT:
if (Type == ELF::STT_NOTYPE)
Type = ELF::STT_OBJECT;
break;
case ELF::STT_TLS:
if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC)
Type = ELF::STT_TLS;
break;
}
return Type;
}
void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
ELFSymbolData &MSD,
const MCAsmLayout &Layout) {
MCSymbolData &OrigData = *MSD.SymbolData;
MCSymbolData &Data =
Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol());
bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() ||
Data.getSymbol().isVariable();
// Binding and Type share the same byte as upper and lower nibbles
uint8_t Binding = MCELF::GetBinding(OrigData);
uint8_t Type = mergeTypeForSet(MCELF::GetType(OrigData), MCELF::GetType(Data));
uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift);
// Other and Visibility share the same byte with Visibility using the lower
// 2 bits
uint8_t Visibility = MCELF::GetVisibility(OrigData);
uint8_t Other = MCELF::getOther(OrigData) << (ELF_STO_Shift - ELF_STV_Shift);
Other |= Visibility;
uint64_t Value = SymbolValue(Data, Layout);
uint64_t Size = 0;
assert(!(Data.isCommon() && !Data.isExternal()));
const MCExpr *ESize = Data.getSize();
if (ESize) {
int64_t Res;
if (!ESize->EvaluateAsAbsolute(Res, Layout))
report_fatal_error("Size expression must be absolute.");
Size = Res;
}
// Write out the symbol table entry
WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value,
Size, Other, MSD.SectionIndex, IsReserved);
}
void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
const MCAssembler &Asm,
const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap) {
// The string table must be emitted first because we need the index
// into the string table for all the symbol names.
assert(StringTable.size() && "Missing string table");
// FIXME: Make sure the start of the symbol table is aligned.
// The first entry is the undefined symbol entry.
WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false);
for (unsigned i = 0, e = FileSymbolData.size(); i != e; ++i) {
WriteSymbolEntry(SymtabF, ShndxF, FileSymbolData[i],
ELF::STT_FILE | ELF::STB_LOCAL, 0, 0,
ELF::STV_DEFAULT, ELF::SHN_ABS, true);
}
// Write the symbol table entries.
LastLocalSymbolIndex = FileSymbolData.size() + LocalSymbolData.size() + 1;
for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) {
ELFSymbolData &MSD = LocalSymbolData[i];
WriteSymbol(SymtabF, ShndxF, MSD, Layout);
}
// Write out a symbol table entry for each regular section.
for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e;
++i) {
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(i->getSection());
if (Section.getType() == ELF::SHT_RELA ||
Section.getType() == ELF::SHT_REL ||
Section.getType() == ELF::SHT_STRTAB ||
Section.getType() == ELF::SHT_SYMTAB ||
Section.getType() == ELF::SHT_SYMTAB_SHNDX)
continue;
WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0,
ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section),
false);
LastLocalSymbolIndex++;
}
for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) {
ELFSymbolData &MSD = ExternalSymbolData[i];
MCSymbolData &Data = *MSD.SymbolData;
assert(((Data.getFlags() & ELF_STB_Global) ||
(Data.getFlags() & ELF_STB_Weak)) &&
"External symbol requires STB_GLOBAL or STB_WEAK flag");
WriteSymbol(SymtabF, ShndxF, MSD, Layout);
if (MCELF::GetBinding(Data) == ELF::STB_LOCAL)
LastLocalSymbolIndex++;
}
for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) {
ELFSymbolData &MSD = UndefinedSymbolData[i];
MCSymbolData &Data = *MSD.SymbolData;
WriteSymbol(SymtabF, ShndxF, MSD, Layout);
if (MCELF::GetBinding(Data) == ELF::STB_LOCAL)
LastLocalSymbolIndex++;
}
}
const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const {
const MCSymbol &Symbol = Target.getSymA()->getSymbol();
const MCSymbol &ASymbol = Symbol.AliasedSymbol();
const MCSymbol *Renamed = Renames.lookup(&Symbol);
const MCSymbolData &SD = Asm.getSymbolData(Symbol);
if (ASymbol.isUndefined()) {
if (Renamed)
return Renamed;
return undefinedExplicitRelSym(Target, Fixup, IsPCRel);
}
if (SD.isExternal()) {
if (Renamed)
return Renamed;
return &Symbol;
}
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(ASymbol.getSection());
const SectionKind secKind = Section.getKind();
if (secKind.isBSS())
return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel);
if (secKind.isThreadLocal()) {
if (Renamed)
return Renamed;
return &Symbol;
}
MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind();
const MCSectionELF &Sec2 =
static_cast<const MCSectionELF&>(F.getParent()->getSection());
if (&Sec2 != &Section &&
(Kind == MCSymbolRefExpr::VK_PLT ||
Kind == MCSymbolRefExpr::VK_GOTPCREL ||
Kind == MCSymbolRefExpr::VK_GOTOFF)) {
if (Renamed)
return Renamed;
return &Symbol;
}
if (Section.getFlags() & ELF::SHF_MERGE) {
if (Target.getConstant() == 0)
return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel);
if (Renamed)
return Renamed;
return &Symbol;
}
return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel);
}
void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup,
MCValue Target,
uint64_t &FixedValue) {
int64_t Addend = 0;
int Index = 0;
int64_t Value = Target.getConstant();
const MCSymbol *RelocSymbol = NULL;
bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
if (!Target.isAbsolute()) {
const MCSymbol &Symbol = Target.getSymA()->getSymbol();
const MCSymbol &ASymbol = Symbol.AliasedSymbol();
RelocSymbol = SymbolToReloc(Asm, Target, *Fragment, Fixup, IsPCRel);
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
const MCSymbol &SymbolB = RefB->getSymbol();
MCSymbolData &SDB = Asm.getSymbolData(SymbolB);
IsPCRel = true;
if (!SDB.getFragment())
Asm.getContext().FatalError(
Fixup.getLoc(),
Twine("symbol '") + SymbolB.getName() +
"' can not be undefined in a subtraction expression");
// Offset of the symbol in the section
int64_t a = Layout.getSymbolOffset(&SDB);
// Offset of the relocation in the section
int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
Value += b - a;
}
if (!RelocSymbol) {
MCSymbolData &SD = Asm.getSymbolData(ASymbol);
MCFragment *F = SD.getFragment();
if (F) {
Index = F->getParent()->getOrdinal() + 1;
// Offset of the symbol in the section
Value += Layout.getSymbolOffset(&SD);
} else {
Index = 0;
}
} else {
if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref)
WeakrefUsedInReloc.insert(RelocSymbol);
else
UsedInReloc.insert(RelocSymbol);
Index = -1;
}
Addend = Value;
if (hasRelocationAddend())
Value = 0;
}
FixedValue = Value;
unsigned Type = GetRelocType(Target, Fixup, IsPCRel,
(RelocSymbol != 0), Addend);
MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
if (RelocNeedsGOT(Modifier))
NeedsGOT = true;
uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) +
Fixup.getOffset();
if (!hasRelocationAddend())
Addend = 0;
if (is64Bit())
assert(isInt<64>(Addend));
else
assert(isInt<32>(Addend));
ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend, Fixup);
Relocations[Fragment->getParent()].push_back(ERE);
}
uint64_t
ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm,
const MCSymbol *S) {
MCSymbolData &SD = Asm.getSymbolData(*S);
return SD.getIndex();
}
bool ELFObjectWriter::isInSymtab(const MCAssembler &Asm,
const MCSymbolData &Data,
bool Used, bool Renamed) {
if (Data.getFlags() & ELF_Other_Weakref)
return false;
if (Used)
return true;
if (Renamed)
return false;
const MCSymbol &Symbol = Data.getSymbol();
if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_")
return true;
const MCSymbol &A = Symbol.AliasedSymbol();
if (Symbol.isVariable() && !A.isVariable() && A.isUndefined())
return false;
bool IsGlobal = MCELF::GetBinding(Data) == ELF::STB_GLOBAL;
if (!Symbol.isVariable() && Symbol.isUndefined() && !IsGlobal)
return false;
if (Symbol.isTemporary())
return false;
return true;
}
bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isSignature,
bool isUsedInReloc) {
if (Data.isExternal())
return false;
const MCSymbol &Symbol = Data.getSymbol();
const MCSymbol &RefSymbol = Symbol.AliasedSymbol();
if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) {
if (isSignature && !isUsedInReloc)
return true;
return false;
}
return true;
}
void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap) {
unsigned Index = 1;
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(it->getSection());
if (Section.getType() != ELF::SHT_GROUP)
continue;
SectionIndexMap[&Section] = Index++;
}
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(it->getSection());
if (Section.getType() == ELF::SHT_GROUP ||
Section.getType() == ELF::SHT_REL ||
Section.getType() == ELF::SHT_RELA)
continue;
SectionIndexMap[&Section] = Index++;
const MCSectionELF *RelSection = RelMap.lookup(&Section);
if (RelSection)
SectionIndexMap[RelSection] = Index++;
}
}
void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm,
const SectionIndexMapTy &SectionIndexMap,
RevGroupMapTy RevGroupMap,
unsigned NumRegularSections) {
// FIXME: Is this the correct place to do this?
// FIXME: Why is an undefined reference to _GLOBAL_OFFSET_TABLE_ needed?
if (NeedsGOT) {
StringRef Name = "_GLOBAL_OFFSET_TABLE_";
MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name);
MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym);
Data.setExternal(true);
MCELF::SetBinding(Data, ELF::STB_GLOBAL);
}
// Index 0 is always the empty string.
StringMap<uint64_t> StringIndexMap;
StringTable += '\x00';
// FIXME: We could optimize suffixes in strtab in the same way we
// optimize them in shstrtab.
for (MCAssembler::const_file_name_iterator it = Asm.file_names_begin(),
ie = Asm.file_names_end();
it != ie;
++it) {
StringRef Name = *it;
uint64_t &Entry = StringIndexMap[Name];
if (!Entry) {
Entry = StringTable.size();
StringTable += Name;
StringTable += '\x00';
}
FileSymbolData.push_back(Entry);
}
// Add the data for the symbols.
for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
ie = Asm.symbol_end(); it != ie; ++it) {
const MCSymbol &Symbol = it->getSymbol();
bool Used = UsedInReloc.count(&Symbol);
bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol);
bool isSignature = RevGroupMap.count(&Symbol);
if (!isInSymtab(Asm, *it,
Used || WeakrefUsed || isSignature,
Renames.count(&Symbol)))
continue;
ELFSymbolData MSD;
MSD.SymbolData = it;
const MCSymbol &RefSymbol = Symbol.AliasedSymbol();
// Undefined symbols are global, but this is the first place we
// are able to set it.
bool Local = isLocal(*it, isSignature, Used);
if (!Local && MCELF::GetBinding(*it) == ELF::STB_LOCAL) {
MCSymbolData &SD = Asm.getSymbolData(RefSymbol);
MCELF::SetBinding(*it, ELF::STB_GLOBAL);
MCELF::SetBinding(SD, ELF::STB_GLOBAL);
}
if (RefSymbol.isUndefined() && !Used && WeakrefUsed)
MCELF::SetBinding(*it, ELF::STB_WEAK);
if (it->isCommon()) {
assert(!Local);
MSD.SectionIndex = ELF::SHN_COMMON;
} else if (Symbol.isAbsolute() || RefSymbol.isVariable()) {
MSD.SectionIndex = ELF::SHN_ABS;
} else if (RefSymbol.isUndefined()) {
if (isSignature && !Used)
MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]);
else
MSD.SectionIndex = ELF::SHN_UNDEF;
} else {
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(RefSymbol.getSection());
MSD.SectionIndex = SectionIndexMap.lookup(&Section);
if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
NeedsSymtabShndx = true;
assert(MSD.SectionIndex && "Invalid section index!");
}
// The @@@ in symbol version is replaced with @ in undefined symbols and
// @@ in defined ones.
StringRef Name = Symbol.getName();
SmallString<32> Buf;
size_t Pos = Name.find("@@@");
if (Pos != StringRef::npos) {
Buf += Name.substr(0, Pos);
unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1;
Buf += Name.substr(Pos + Skip);
Name = Buf;
}
uint64_t &Entry = StringIndexMap[Name];
if (!Entry) {
Entry = StringTable.size();
StringTable += Name;
StringTable += '\x00';
}
MSD.StringIndex = Entry;
if (MSD.SectionIndex == ELF::SHN_UNDEF)
UndefinedSymbolData.push_back(MSD);
else if (Local)
LocalSymbolData.push_back(MSD);
else
ExternalSymbolData.push_back(MSD);
}
// Symbols are required to be in lexicographic order.
array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end());
array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
array_pod_sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end());
// Set the symbol indices. Local symbols must come before all other
// symbols with non-local bindings.
unsigned Index = FileSymbolData.size() + 1;
for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
LocalSymbolData[i].SymbolData->setIndex(Index++);
Index += NumRegularSections;
for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
ExternalSymbolData[i].SymbolData->setIndex(Index++);
for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
UndefinedSymbolData[i].SymbolData->setIndex(Index++);
if (Index >= ELF::SHN_LORESERVE)
NeedsSymtabShndx = true;
}
void ELFObjectWriter::CreateRelocationSections(MCAssembler &Asm,
MCAsmLayout &Layout,
RelMapTy &RelMap) {
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionData &SD = *it;
if (Relocations[&SD].empty())
continue;
MCContext &Ctx = Asm.getContext();
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(SD.getSection());
const StringRef SectionName = Section.getSectionName();
std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel";
RelaSectionName += SectionName;
unsigned EntrySize;
if (hasRelocationAddend())
EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela);
else
EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel);
unsigned Flags = 0;
StringRef Group = "";
if (Section.getFlags() & ELF::SHF_GROUP) {
Flags = ELF::SHF_GROUP;
Group = Section.getGroup()->getName();
}
const MCSectionELF *RelaSection =
Ctx.getELFSection(RelaSectionName, hasRelocationAddend() ?
ELF::SHT_RELA : ELF::SHT_REL, Flags,
SectionKind::getReadOnly(),
EntrySize, Group);
RelMap[&Section] = RelaSection;
Asm.getOrCreateSectionData(*RelaSection);
}
}
void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout,
const RelMapTy &RelMap) {
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionData &SD = *it;
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(SD.getSection());
const MCSectionELF *RelaSection = RelMap.lookup(&Section);
if (!RelaSection)
continue;
MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection);
RelaSD.setAlignment(is64Bit() ? 8 : 4);
MCDataFragment *F = new MCDataFragment(&RelaSD);
WriteRelocationsFragment(Asm, F, &*it);
}
}
void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type,
uint64_t Flags, uint64_t Address,
uint64_t Offset, uint64_t Size,
uint32_t Link, uint32_t Info,
uint64_t Alignment,
uint64_t EntrySize) {
Write32(Name); // sh_name: index into string table
Write32(Type); // sh_type
WriteWord(Flags); // sh_flags
WriteWord(Address); // sh_addr
WriteWord(Offset); // sh_offset
WriteWord(Size); // sh_size
Write32(Link); // sh_link
Write32(Info); // sh_info
WriteWord(Alignment); // sh_addralign
WriteWord(EntrySize); // sh_entsize
}
void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm,
MCDataFragment *F,
const MCSectionData *SD) {
std::vector<ELFRelocationEntry> &Relocs = Relocations[SD];
// Sort the relocation entries. Most targets just sort by r_offset, but some
// (e.g., MIPS) have additional constraints.
TargetObjectWriter->sortRelocs(Asm, Relocs);
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
ELFRelocationEntry entry = Relocs[e - i - 1];
if (!entry.Index)
;
else if (entry.Index < 0)
entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol);
else
entry.Index += FileSymbolData.size() + LocalSymbolData.size();
if (is64Bit()) {
String64(*F, entry.r_offset);
The ELF relocation record format is different for N64 which many Mips 64 ABIs use than for O64 which many if not all other target ABIs use. Most architectures have the following 64 bit relocation record format: typedef struct { Elf64_Addr r_offset; /* Address of reference */ Elf64_Xword r_info; /* Symbol index and type of relocation */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; Whereas N64 has the following format: typedef struct { Elf64_Addr r_offset;/* Address of reference */ Elf64_Word r_sym; /* Symbol index */ Elf64_Byte r_ssym; /* Special symbol */ Elf64_Byte r_type3; /* Relocation type */ Elf64_Byte r_type2; /* Relocation type */ Elf64_Byte r_type; /* Relocation type */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset;/* Address of reference */ Elf64_Word r_sym; /* Symbol index */ Elf64_Byte r_ssym; /* Special symbol */ Elf64_Byte r_type3; /* Relocation type */ Elf64_Byte r_type2; /* Relocation type */ Elf64_Byte r_type; /* Relocation type */ Elf64_Sxword r_addend; } Elf64_Rela; The structure is the same size, but the r_info data element is now 5 separate elements. Besides the content aspects, endian byte reordering will be different for the area with each element being endianized separately. I treat this as generic and continue to pass r_type as an integer masking and unmasking the byte sized N64 values for N64 mode. I've implemented this and it causes no affect on other current targets. This passes make check. Jack git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159299 91177308-0d34-0410-b5e6-96231b3b80d8
2012-06-27 22:28:30 +00:00
if (TargetObjectWriter->isN64()) {
String32(*F, entry.Index);
The ELF relocation record format is different for N64 which many Mips 64 ABIs use than for O64 which many if not all other target ABIs use. Most architectures have the following 64 bit relocation record format: typedef struct { Elf64_Addr r_offset; /* Address of reference */ Elf64_Xword r_info; /* Symbol index and type of relocation */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; Whereas N64 has the following format: typedef struct { Elf64_Addr r_offset;/* Address of reference */ Elf64_Word r_sym; /* Symbol index */ Elf64_Byte r_ssym; /* Special symbol */ Elf64_Byte r_type3; /* Relocation type */ Elf64_Byte r_type2; /* Relocation type */ Elf64_Byte r_type; /* Relocation type */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset;/* Address of reference */ Elf64_Word r_sym; /* Symbol index */ Elf64_Byte r_ssym; /* Special symbol */ Elf64_Byte r_type3; /* Relocation type */ Elf64_Byte r_type2; /* Relocation type */ Elf64_Byte r_type; /* Relocation type */ Elf64_Sxword r_addend; } Elf64_Rela; The structure is the same size, but the r_info data element is now 5 separate elements. Besides the content aspects, endian byte reordering will be different for the area with each element being endianized separately. I treat this as generic and continue to pass r_type as an integer masking and unmasking the byte sized N64 values for N64 mode. I've implemented this and it causes no affect on other current targets. This passes make check. Jack git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159299 91177308-0d34-0410-b5e6-96231b3b80d8
2012-06-27 22:28:30 +00:00
String8(*F, TargetObjectWriter->getRSsym(entry.Type));
String8(*F, TargetObjectWriter->getRType3(entry.Type));
String8(*F, TargetObjectWriter->getRType2(entry.Type));
String8(*F, TargetObjectWriter->getRType(entry.Type));
}
else {
struct ELF::Elf64_Rela ERE64;
ERE64.setSymbolAndType(entry.Index, entry.Type);
String64(*F, ERE64.r_info);
}
if (hasRelocationAddend())
String64(*F, entry.r_addend);
} else {
String32(*F, entry.r_offset);
struct ELF::Elf32_Rela ERE32;
ERE32.setSymbolAndType(entry.Index, entry.Type);
String32(*F, ERE32.r_info);
if (hasRelocationAddend())
String32(*F, entry.r_addend);
}
}
}
static int compareBySuffix(const MCSectionELF *const *a,
const MCSectionELF *const *b) {
const StringRef &NameA = (*a)->getSectionName();
const StringRef &NameB = (*b)->getSectionName();
const unsigned sizeA = NameA.size();
const unsigned sizeB = NameB.size();
const unsigned len = std::min(sizeA, sizeB);
for (unsigned int i = 0; i < len; ++i) {
char ca = NameA[sizeA - i - 1];
char cb = NameB[sizeB - i - 1];
if (ca != cb)
return cb - ca;
}
return sizeB - sizeA;
}
void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm,
MCAsmLayout &Layout,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap) {
MCContext &Ctx = Asm.getContext();
MCDataFragment *F;
unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32;
// We construct .shstrtab, .symtab and .strtab in this order to match gnu as.
const MCSectionELF *ShstrtabSection =
Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0,
SectionKind::getReadOnly());
MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection);
ShstrtabSD.setAlignment(1);
const MCSectionELF *SymtabSection =
Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0,
SectionKind::getReadOnly(),
EntrySize, "");
MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection);
SymtabSD.setAlignment(is64Bit() ? 8 : 4);
MCSectionData *SymtabShndxSD = NULL;
if (NeedsSymtabShndx) {
const MCSectionELF *SymtabShndxSection =
Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0,
SectionKind::getReadOnly(), 4, "");
SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection);
SymtabShndxSD->setAlignment(4);
}
const MCSectionELF *StrtabSection;
StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0,
SectionKind::getReadOnly());
MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection);
StrtabSD.setAlignment(1);
ComputeIndexMap(Asm, SectionIndexMap, RelMap);
ShstrtabIndex = SectionIndexMap.lookup(ShstrtabSection);
SymbolTableIndex = SectionIndexMap.lookup(SymtabSection);
StringTableIndex = SectionIndexMap.lookup(StrtabSection);
// Symbol table
F = new MCDataFragment(&SymtabSD);
MCDataFragment *ShndxF = NULL;
if (NeedsSymtabShndx) {
ShndxF = new MCDataFragment(SymtabShndxSD);
}
WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap);
F = new MCDataFragment(&StrtabSD);
F->getContents().append(StringTable.begin(), StringTable.end());
F = new MCDataFragment(&ShstrtabSD);
std::vector<const MCSectionELF*> Sections;
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(it->getSection());
Sections.push_back(&Section);
}
array_pod_sort(Sections.begin(), Sections.end(), compareBySuffix);
// Section header string table.
//
// The first entry of a string table holds a null character so skip
// section 0.
uint64_t Index = 1;
F->getContents().push_back('\x00');
for (unsigned int I = 0, E = Sections.size(); I != E; ++I) {
const MCSectionELF &Section = *Sections[I];
StringRef Name = Section.getSectionName();
if (I != 0) {
StringRef PreviousName = Sections[I - 1]->getSectionName();
if (PreviousName.endswith(Name)) {
SectionStringTableIndex[&Section] = Index - Name.size() - 1;
continue;
}
}
// Remember the index into the string table so we can write it
// into the sh_name field of the section header table.
SectionStringTableIndex[&Section] = Index;
Index += Name.size() + 1;
F->getContents().append(Name.begin(), Name.end());
F->getContents().push_back('\x00');
}
}
void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm,
MCAsmLayout &Layout,
GroupMapTy &GroupMap,
RevGroupMapTy &RevGroupMap,
SectionIndexMapTy &SectionIndexMap,
const RelMapTy &RelMap) {
// Create the .note.GNU-stack section if needed.
MCContext &Ctx = Asm.getContext();
if (Asm.getNoExecStack()) {
const MCSectionELF *GnuStackSection =
Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0,
SectionKind::getReadOnly());
Asm.getOrCreateSectionData(*GnuStackSection);
}
// Build the groups
for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(it->getSection());
if (!(Section.getFlags() & ELF::SHF_GROUP))
continue;
const MCSymbol *SignatureSymbol = Section.getGroup();
Asm.getOrCreateSymbolData(*SignatureSymbol);
const MCSectionELF *&Group = RevGroupMap[SignatureSymbol];
if (!Group) {
Group = Ctx.CreateELFGroupSection();
MCSectionData &Data = Asm.getOrCreateSectionData(*Group);
Data.setAlignment(4);
MCDataFragment *F = new MCDataFragment(&Data);
String32(*F, ELF::GRP_COMDAT);
}
GroupMap[Group] = SignatureSymbol;
}
ComputeIndexMap(Asm, SectionIndexMap, RelMap);
// Add sections to the groups
for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(it->getSection());
if (!(Section.getFlags() & ELF::SHF_GROUP))
continue;
const MCSectionELF *Group = RevGroupMap[Section.getGroup()];
MCSectionData &Data = Asm.getOrCreateSectionData(*Group);
// FIXME: we could use the previous fragment
MCDataFragment *F = new MCDataFragment(&Data);
unsigned Index = SectionIndexMap.lookup(&Section);
String32(*F, Index);
}
}
void ELFObjectWriter::WriteSection(MCAssembler &Asm,
const SectionIndexMapTy &SectionIndexMap,
uint32_t GroupSymbolIndex,
uint64_t Offset, uint64_t Size,
uint64_t Alignment,
const MCSectionELF &Section) {
uint64_t sh_link = 0;
uint64_t sh_info = 0;
switch(Section.getType()) {
case ELF::SHT_DYNAMIC:
sh_link = SectionStringTableIndex[&Section];
sh_info = 0;
break;
case ELF::SHT_REL:
case ELF::SHT_RELA: {
const MCSectionELF *SymtabSection;
const MCSectionELF *InfoSection;
SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB,
0,
SectionKind::getReadOnly());
sh_link = SectionIndexMap.lookup(SymtabSection);
assert(sh_link && ".symtab not found");
// Remove ".rel" and ".rela" prefixes.
unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5;
StringRef SectionName = Section.getSectionName().substr(SecNameLen);
StringRef GroupName =
Section.getGroup() ? Section.getGroup()->getName() : "";
InfoSection = Asm.getContext().getELFSection(SectionName, ELF::SHT_PROGBITS,
0, SectionKind::getReadOnly(),
0, GroupName);
sh_info = SectionIndexMap.lookup(InfoSection);
break;
}
case ELF::SHT_SYMTAB:
case ELF::SHT_DYNSYM:
sh_link = StringTableIndex;
sh_info = LastLocalSymbolIndex;
break;
case ELF::SHT_SYMTAB_SHNDX:
sh_link = SymbolTableIndex;
break;
case ELF::SHT_PROGBITS:
case ELF::SHT_STRTAB:
case ELF::SHT_NOBITS:
case ELF::SHT_NOTE:
case ELF::SHT_NULL:
case ELF::SHT_ARM_ATTRIBUTES:
case ELF::SHT_INIT_ARRAY:
case ELF::SHT_FINI_ARRAY:
case ELF::SHT_PREINIT_ARRAY:
case ELF::SHT_X86_64_UNWIND:
case ELF::SHT_MIPS_REGINFO:
case ELF::SHT_MIPS_OPTIONS:
// Nothing to do.
break;
case ELF::SHT_GROUP:
sh_link = SymbolTableIndex;
sh_info = GroupSymbolIndex;
break;
default:
assert(0 && "FIXME: sh_type value not supported!");
break;
}
if (TargetObjectWriter->getEMachine() == ELF::EM_ARM &&
Section.getType() == ELF::SHT_ARM_EXIDX) {
StringRef SecName(Section.getSectionName());
if (SecName == ".ARM.exidx") {
sh_link = SectionIndexMap.lookup(
Asm.getContext().getELFSection(".text",
ELF::SHT_PROGBITS,
ELF::SHF_EXECINSTR | ELF::SHF_ALLOC,
SectionKind::getText()));
} else if (SecName.startswith(".ARM.exidx")) {
StringRef GroupName =
Section.getGroup() ? Section.getGroup()->getName() : "";
sh_link = SectionIndexMap.lookup(Asm.getContext().getELFSection(
SecName.substr(sizeof(".ARM.exidx") - 1), ELF::SHT_PROGBITS,
ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, SectionKind::getText(), 0,
GroupName));
}
}
WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(),
Section.getFlags(), 0, Offset, Size, sh_link, sh_info,
Alignment, Section.getEntrySize());
}
bool ELFObjectWriter::IsELFMetaDataSection(const MCSectionData &SD) {
return SD.getOrdinal() == ~UINT32_C(0) &&
!SD.getSection().isVirtualSection();
}
uint64_t ELFObjectWriter::DataSectionSize(const MCSectionData &SD) {
uint64_t Ret = 0;
for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e;
++i) {
const MCFragment &F = *i;
assert(F.getKind() == MCFragment::FT_Data);
Ret += cast<MCDataFragment>(F).getContents().size();
}
return Ret;
}
uint64_t ELFObjectWriter::GetSectionFileSize(const MCAsmLayout &Layout,
const MCSectionData &SD) {
if (IsELFMetaDataSection(SD))
return DataSectionSize(SD);
return Layout.getSectionFileSize(&SD);
}
uint64_t ELFObjectWriter::GetSectionAddressSize(const MCAsmLayout &Layout,
const MCSectionData &SD) {
if (IsELFMetaDataSection(SD))
return DataSectionSize(SD);
return Layout.getSectionAddressSize(&SD);
}
void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCSectionELF &Section) {
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment());
WriteZeros(Padding);
if (IsELFMetaDataSection(SD)) {
for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e;
++i) {
const MCFragment &F = *i;
assert(F.getKind() == MCFragment::FT_Data);
WriteBytes(cast<MCDataFragment>(F).getContents());
}
} else {
Asm.writeSectionData(&SD, Layout);
}
}
void ELFObjectWriter::WriteSectionHeader(MCAssembler &Asm,
const GroupMapTy &GroupMap,
const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetMapTy &SectionOffsetMap) {
const unsigned NumSections = Asm.size() + 1;
std::vector<const MCSectionELF*> Sections;
Sections.resize(NumSections - 1);
for (SectionIndexMapTy::const_iterator i=
SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) {
const std::pair<const MCSectionELF*, uint32_t> &p = *i;
Sections[p.second - 1] = p.first;
}
// Null section first.
uint64_t FirstSectionSize =
NumSections >= ELF::SHN_LORESERVE ? NumSections : 0;
uint32_t FirstSectionLink =
ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0;
WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0);
for (unsigned i = 0; i < NumSections - 1; ++i) {
const MCSectionELF &Section = *Sections[i];
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
uint32_t GroupSymbolIndex;
if (Section.getType() != ELF::SHT_GROUP)
GroupSymbolIndex = 0;
else
GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm,
GroupMap.lookup(&Section));
uint64_t Size = GetSectionAddressSize(Layout, SD);
WriteSection(Asm, SectionIndexMap, GroupSymbolIndex,
SectionOffsetMap.lookup(&Section), Size,
SD.getAlignment(), Section);
}
}
void ELFObjectWriter::ComputeSectionOrder(MCAssembler &Asm,
std::vector<const MCSectionELF*> &Sections) {
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(it->getSection());
if (Section.getType() == ELF::SHT_GROUP)
Sections.push_back(&Section);
}
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(it->getSection());
if (Section.getType() != ELF::SHT_GROUP &&
Section.getType() != ELF::SHT_REL &&
Section.getType() != ELF::SHT_RELA)
Sections.push_back(&Section);
}
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(it->getSection());
if (Section.getType() == ELF::SHT_REL ||
Section.getType() == ELF::SHT_RELA)
Sections.push_back(&Section);
}
}
void ELFObjectWriter::WriteObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
GroupMapTy GroupMap;
RevGroupMapTy RevGroupMap;
SectionIndexMapTy SectionIndexMap;
unsigned NumUserSections = Asm.size();
DenseMap<const MCSectionELF*, const MCSectionELF*> RelMap;
CreateRelocationSections(Asm, const_cast<MCAsmLayout&>(Layout), RelMap);
const unsigned NumUserAndRelocSections = Asm.size();
CreateIndexedSections(Asm, const_cast<MCAsmLayout&>(Layout), GroupMap,
RevGroupMap, SectionIndexMap, RelMap);
const unsigned AllSections = Asm.size();
const unsigned NumIndexedSections = AllSections - NumUserAndRelocSections;
unsigned NumRegularSections = NumUserSections + NumIndexedSections;
// Compute symbol table information.
ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap, NumRegularSections);
WriteRelocations(Asm, const_cast<MCAsmLayout&>(Layout), RelMap);
CreateMetadataSections(const_cast<MCAssembler&>(Asm),
const_cast<MCAsmLayout&>(Layout),
SectionIndexMap,
RelMap);
uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) :
sizeof(ELF::Elf32_Ehdr);
uint64_t FileOff = HeaderSize;
std::vector<const MCSectionELF*> Sections;
ComputeSectionOrder(Asm, Sections);
unsigned NumSections = Sections.size();
SectionOffsetMapTy SectionOffsetMap;
for (unsigned i = 0; i < NumRegularSections + 1; ++i) {
const MCSectionELF &Section = *Sections[i];
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
FileOff = RoundUpToAlignment(FileOff, SD.getAlignment());
// Remember the offset into the file for this section.
SectionOffsetMap[&Section] = FileOff;
// Get the size of the section in the output file (including padding).
FileOff += GetSectionFileSize(Layout, SD);
}
FileOff = RoundUpToAlignment(FileOff, NaturalAlignment);
const unsigned SectionHeaderOffset = FileOff - HeaderSize;
uint64_t SectionHeaderEntrySize = is64Bit() ?
sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr);
FileOff += (NumSections + 1) * SectionHeaderEntrySize;
for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) {
const MCSectionELF &Section = *Sections[i];
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
FileOff = RoundUpToAlignment(FileOff, SD.getAlignment());
// Remember the offset into the file for this section.
SectionOffsetMap[&Section] = FileOff;
// Get the size of the section in the output file (including padding).
FileOff += GetSectionFileSize(Layout, SD);
}
// Write out the ELF header ...
WriteHeader(Asm, SectionHeaderOffset, NumSections + 1);
// ... then the regular sections ...
// + because of .shstrtab
for (unsigned i = 0; i < NumRegularSections + 1; ++i)
WriteDataSectionData(Asm, Layout, *Sections[i]);
uint64_t Padding = OffsetToAlignment(OS.tell(), NaturalAlignment);
WriteZeros(Padding);
// ... then the section header table ...
WriteSectionHeader(Asm, GroupMap, Layout, SectionIndexMap,
SectionOffsetMap);
// ... and then the remaining sections ...
for (unsigned i = NumRegularSections + 1; i < NumSections; ++i)
WriteDataSectionData(Asm, Layout, *Sections[i]);
}
bool
ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
const MCSymbolData &DataA,
const MCFragment &FB,
bool InSet,
bool IsPCRel) const {
if (DataA.getFlags() & ELF_STB_Weak || MCELF::GetType(DataA) == ELF::STT_GNU_IFUNC)
return false;
return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(
Asm, DataA, FB,InSet, IsPCRel);
}
MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW,
raw_ostream &OS,
bool IsLittleEndian) {
return new ELFObjectWriter(MOTW, OS, IsLittleEndian);
}