blob: 89d58d0bc166d9228ee502d982ebd27fc3128869 [file] [log] [blame]
//===- subzero/src/IceELFSection.cpp - Representation of ELF sections -----===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines how ELF sections are represented.
///
//===----------------------------------------------------------------------===//
#include "IceELFSection.h"
#include "IceDefs.h"
#include "IceELFStreamer.h"
#include "llvm/Support/MathExtras.h"
using namespace llvm::ELF;
namespace Ice {
// Text sections.
void ELFTextSection::appendData(ELFStreamer &Str,
const llvm::StringRef MoreData) {
Str.writeBytes(MoreData);
Header.sh_size += MoreData.size();
}
// Data sections.
void ELFDataSection::appendData(ELFStreamer &Str,
const llvm::StringRef MoreData) {
Str.writeBytes(MoreData);
Header.sh_size += MoreData.size();
}
void ELFDataSection::appendZeros(ELFStreamer &Str, SizeT NumBytes) {
Str.writeZeroPadding(NumBytes);
Header.sh_size += NumBytes;
}
void ELFDataSection::appendRelocationOffset(ELFStreamer &Str, bool IsRela,
RelocOffsetT RelocOffset) {
const SizeT RelocAddrSize = typeWidthInBytes(getPointerType());
if (IsRela) {
appendZeros(Str, RelocAddrSize);
return;
}
assert(RelocAddrSize == 4 && " writeLE32 assumes RelocAddrSize is 4");
Str.writeLE32(RelocOffset);
Header.sh_size += RelocAddrSize;
}
void ELFDataSection::padToAlignment(ELFStreamer &Str, Elf64_Xword Align) {
assert(llvm::isPowerOf2_32(Align));
Elf64_Xword AlignDiff = Utils::OffsetToAlignment(Header.sh_size, Align);
if (AlignDiff == 0)
return;
if (Header.sh_type != llvm::ELF::SHT_NOBITS)
Str.writeZeroPadding(AlignDiff);
Header.sh_size += AlignDiff;
}
// Relocation sections.
void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff,
const FixupRefList &FixupRefs,
ELFSymbolTableSection *SymTab) {
for (const AssemblerFixup *FR : FixupRefs) {
Fixups.push_back(*FR);
AssemblerFixup &F = Fixups.back();
F.set_position(BaseOff + F.position());
assert(!F.valueIsSymbol());
if (!F.isNullSymbol()) {
// Do an early lookup in the symbol table. If the symbol is found,
// replace the Constant in the symbol with the ELFSym, and calculate the
// final value of the addend. As such, a local label allocated from the
// Assembler arena will be converted to a symbol before the Assembler
// arena goes away.
if (const ELFSym *Sym = SymTab->findSymbol(F.symbol())) {
F.set_addend(F.offset());
F.set_value(Sym);
}
}
}
}
size_t ELFRelocationSection::getSectionDataSize() const {
return Fixups.size() * Header.sh_entsize;
}
// Symbol tables.
void ELFSymbolTableSection::createNullSymbol(ELFSection *NullSection,
GlobalContext *Ctx) {
// The first entry in the symbol table should be a NULL entry, so make sure
// the map is still empty.
assert(LocalSymbols.empty());
// Explicitly set the null symbol name to the empty string, so that
// GlobalString::operator<() orders the null string first.
NullSymbolName = GlobalString::createWithString(Ctx, "");
createDefinedSym(NullSymbolName, STT_NOTYPE, STB_LOCAL, NullSection, 0, 0);
NullSymbol = findSymbol(NullSymbolName);
}
void ELFSymbolTableSection::createDefinedSym(GlobalString Name, uint8_t Type,
uint8_t Binding,
ELFSection *Section,
RelocOffsetT Offset, SizeT Size) {
ELFSym NewSymbol = ELFSym();
NewSymbol.Sym.setBindingAndType(Binding, Type);
NewSymbol.Sym.st_value = Offset;
NewSymbol.Sym.st_size = Size;
NewSymbol.Section = Section;
NewSymbol.Number = ELFSym::UnknownNumber;
bool Unique;
if (Binding == STB_LOCAL)
Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
else
Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
assert(Unique);
(void)Unique;
}
void ELFSymbolTableSection::noteUndefinedSym(GlobalString Name,
ELFSection *NullSection) {
ELFSym NewSymbol = ELFSym();
NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
NewSymbol.Section = NullSection;
NewSymbol.Number = ELFSym::UnknownNumber;
bool Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
if (!Unique) {
std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer);
StrBuf << "Symbol external and defined: " << Name;
llvm::report_fatal_error(StrBuf.str());
}
(void)Unique;
}
const ELFSym *ELFSymbolTableSection::findSymbol(GlobalString Name) const {
auto I = LocalSymbols.find(Name);
if (I != LocalSymbols.end())
return &I->second;
I = GlobalSymbols.find(Name);
if (I != GlobalSymbols.end())
return &I->second;
return nullptr;
}
void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) {
SizeT SymNumber = 0;
for (auto &KeyValue : LocalSymbols) {
GlobalString Name = KeyValue.first;
ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (Name != NullSymbolName && Name.hasStdString())
SymInfo.st_name = StrTab->getIndex(Name.toString());
SymInfo.st_shndx = Section->getNumber();
KeyValue.second.setNumber(SymNumber++);
}
for (auto &KeyValue : GlobalSymbols) {
const std::string &Name = KeyValue.first.toString();
ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (!Name.empty())
SymInfo.st_name = StrTab->getIndex(Name);
SymInfo.st_shndx = Section->getNumber();
KeyValue.second.setNumber(SymNumber++);
}
}
void ELFSymbolTableSection::writeData(ELFStreamer &Str, bool IsELF64) {
if (IsELF64) {
writeSymbolMap<true>(Str, LocalSymbols);
writeSymbolMap<true>(Str, GlobalSymbols);
} else {
writeSymbolMap<false>(Str, LocalSymbols);
writeSymbolMap<false>(Str, GlobalSymbols);
}
}
// String tables.
void ELFStringTableSection::add(const std::string &Str) {
assert(!isLaidOut());
assert(!Str.empty());
StringToIndexMap.insert(std::make_pair(Str, UnknownIndex));
}
size_t ELFStringTableSection::getIndex(const std::string &Str) const {
assert(isLaidOut());
StringToIndexType::const_iterator It = StringToIndexMap.find(Str);
if (It == StringToIndexMap.end()) {
llvm::report_fatal_error("String index not found: " + Str);
return UnknownIndex;
}
return It->second;
}
bool ELFStringTableSection::SuffixComparator::operator()(
const std::string &StrA, const std::string &StrB) const {
size_t LenA = StrA.size();
size_t LenB = StrB.size();
size_t CommonLen = std::min(LenA, LenB);
// If there is a difference in the common suffix, use that diff to sort.
for (size_t i = 0; i < CommonLen; ++i) {
char a = StrA[LenA - i - 1];
char b = StrB[LenB - i - 1];
if (a != b)
return a > b;
}
// If the common suffixes are completely equal, let the longer one come
// first, so that it can be laid out first and its characters shared.
return LenA > LenB;
}
void ELFStringTableSection::doLayout() {
assert(!isLaidOut());
llvm::StringRef Prev;
// String table starts with 0 byte.
StringData.push_back(0);
for (auto &StringIndex : StringToIndexMap) {
assert(StringIndex.second == UnknownIndex);
llvm::StringRef Cur = llvm::StringRef(StringIndex.first);
if (Prev.endswith(Cur)) {
// Prev is already in the StringData, and Cur is shorter than Prev based
// on the sort.
StringIndex.second = StringData.size() - Cur.size() - 1;
continue;
}
StringIndex.second = StringData.size();
std::copy(Cur.begin(), Cur.end(), back_inserter(StringData));
StringData.push_back(0);
Prev = Cur;
}
}
} // end of namespace Ice