blob: 37b1d58acdf274fc727997e4867a685902417f1f [file] [log] [blame]
//===- subzero/src/IceELFObjectWriter.cpp - ELF object file writer --------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the writer for ELF relocatable object files.
///
//===----------------------------------------------------------------------===//
#include "IceELFObjectWriter.h"
#include "IceAssembler.h"
#include "IceDefs.h"
#include "IceELFSection.h"
#include "IceELFStreamer.h"
#include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceOperand.h"
#include "llvm/Support/MathExtras.h"
using namespace llvm::ELF;
namespace Ice {
namespace {
struct {
bool IsELF64;
uint16_t ELFMachine;
uint32_t ELFFlags;
} ELFTargetInfo[] = {
#define X(tag, str, is_elf64, e_machine, e_flags) \
{ is_elf64, e_machine, e_flags } \
,
TARGETARCH_TABLE
#undef X
};
bool isELF64(TargetArch Arch) {
if (Arch < TargetArch_NUM)
return ELFTargetInfo[Arch].IsELF64;
llvm_unreachable("Invalid target arch for isELF64");
return false;
}
uint16_t getELFMachine(TargetArch Arch) {
if (Arch < TargetArch_NUM)
return ELFTargetInfo[Arch].ELFMachine;
llvm_unreachable("Invalid target arch for getELFMachine");
return EM_NONE;
}
uint32_t getELFFlags(TargetArch Arch) {
if (Arch < TargetArch_NUM)
return ELFTargetInfo[Arch].ELFFlags;
llvm_unreachable("Invalid target arch for getELFFlags");
return 0;
}
} // end of anonymous namespace
ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out)
: Ctx(Ctx), Str(Out), ELF64(isELF64(Ctx.getFlags().getTargetArch())) {
// Create the special bookkeeping sections now.
const IceString NullSectionName("");
NullSection = new (Ctx.allocate<ELFSection>())
ELFSection(NullSectionName, SHT_NULL, 0, 0, 0);
const IceString ShStrTabName(".shstrtab");
ShStrTab = new (Ctx.allocate<ELFStringTableSection>())
ELFStringTableSection(ShStrTabName, SHT_STRTAB, 0, 1, 0);
ShStrTab->add(ShStrTabName);
const IceString SymTabName(".symtab");
const Elf64_Xword SymTabAlign = ELF64 ? 8 : 4;
const Elf64_Xword SymTabEntSize =
ELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16,
"Elf_Sym sizes cannot be derived from sizeof");
SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0,
SymTabAlign, SymTabEntSize);
SymTab->createNullSymbol(NullSection);
const IceString StrTabName(".strtab");
StrTab =
createSection<ELFStringTableSection>(StrTabName, SHT_STRTAB, 0, 1, 0);
}
template <typename T>
T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType,
Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
Elf64_Xword ShEntsize) {
assert(!SectionNumbersAssigned);
T *NewSection =
new (Ctx.allocate<T>()) T(Name, ShType, ShFlags, ShAddralign, ShEntsize);
ShStrTab->add(Name);
return NewSection;
}
ELFRelocationSection *
ELFObjectWriter::createRelocationSection(const ELFSection *RelatedSection) {
// Choice of RELA vs REL is actually separate from elf64 vs elf32,
// but in practice we've only had .rela for elf64 (x86-64).
// In the future, the two properties may need to be decoupled
// and the ShEntSize can vary more.
const Elf64_Word ShType = ELF64 ? SHT_RELA : SHT_REL;
IceString RelPrefix = ELF64 ? ".rela" : ".rel";
IceString RelSectionName = RelPrefix + RelatedSection->getName();
const Elf64_Xword ShAlign = ELF64 ? 8 : 4;
const Elf64_Xword ShEntSize = ELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
"Elf_Rel/Rela sizes cannot be derived from sizeof");
const Elf64_Xword ShFlags = 0;
ELFRelocationSection *RelSection = createSection<ELFRelocationSection>(
RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
RelSection->setRelatedSection(RelatedSection);
return RelSection;
}
template <typename UserSectionList>
void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
UserSectionList &UserSections,
RelSectionList &RelSections,
SectionList &AllSections) {
RelSectionList::iterator RelIt = RelSections.begin();
RelSectionList::iterator RelE = RelSections.end();
for (ELFSection *UserSection : UserSections) {
UserSection->setNumber(CurSectionNumber++);
UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName()));
AllSections.push_back(UserSection);
if (RelIt != RelE) {
ELFRelocationSection *RelSection = *RelIt;
if (RelSection->getRelatedSection() == UserSection) {
RelSection->setInfoNum(UserSection->getNumber());
RelSection->setNumber(CurSectionNumber++);
RelSection->setNameStrIndex(ShStrTab->getIndex(RelSection->getName()));
AllSections.push_back(RelSection);
++RelIt;
}
}
}
// Should finish with UserIt at the same time as RelIt.
assert(RelIt == RelE);
return;
}
void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber,
RelSectionList &RelSections) {
for (ELFRelocationSection *S : RelSections) {
S->setLinkNum(SymTabNumber);
}
}
void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
// Go through each section, assigning them section numbers and
// and fill in the size for sections that aren't incrementally updated.
assert(!SectionNumbersAssigned);
SizeT CurSectionNumber = 0;
NullSection->setNumber(CurSectionNumber++);
// The rest of the fields are initialized to 0, and stay that way.
AllSections.push_back(NullSection);
assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections,
RelTextSections, AllSections);
assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections,
RelDataSections, AllSections);
for (ELFSection *BSSSection : BSSSections) {
BSSSection->setNumber(CurSectionNumber++);
BSSSection->setNameStrIndex(ShStrTab->getIndex(BSSSection->getName()));
AllSections.push_back(BSSSection);
}
assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RODataSections,
RelRODataSections, AllSections);
ShStrTab->setNumber(CurSectionNumber++);
ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName()));
AllSections.push_back(ShStrTab);
SymTab->setNumber(CurSectionNumber++);
SymTab->setNameStrIndex(ShStrTab->getIndex(SymTab->getName()));
AllSections.push_back(SymTab);
StrTab->setNumber(CurSectionNumber++);
StrTab->setNameStrIndex(ShStrTab->getIndex(StrTab->getName()));
AllSections.push_back(StrTab);
SymTab->setLinkNum(StrTab->getNumber());
SymTab->setInfoNum(SymTab->getNumLocals());
assignRelLinkNum(SymTab->getNumber(), RelTextSections);
assignRelLinkNum(SymTab->getNumber(), RelDataSections);
assignRelLinkNum(SymTab->getNumber(), RelRODataSections);
SectionNumbersAssigned = true;
}
Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
Elf64_Off OffsetInFile = Str.tell();
Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align);
if (AlignDiff == 0)
return OffsetInFile;
Str.writeZeroPadding(AlignDiff);
OffsetInFile += AlignDiff;
return OffsetInFile;
}
void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
bool IsInternal, const Assembler *Asm) {
assert(!SectionNumbersAssigned);
ELFTextSection *Section = nullptr;
ELFRelocationSection *RelSection = nullptr;
const bool FunctionSections = Ctx.getFlags().getFunctionSections();
if (TextSections.empty() || FunctionSections) {
IceString SectionName = ".text";
if (FunctionSections)
SectionName += "." + FuncName;
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
const Elf64_Xword ShAlign = 1 << Asm->getBundleAlignLog2Bytes();
Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAlign, 0);
Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
Section->setFileOffset(OffsetInFile);
TextSections.push_back(Section);
RelSection = createRelocationSection(Section);
RelTextSections.push_back(RelSection);
} else {
Section = TextSections[0];
RelSection = RelTextSections[0];
}
RelocOffsetT OffsetInSection = Section->getCurrentSize();
// Function symbols are set to 0 size in the symbol table,
// in contrast to data symbols which have a proper size.
SizeT SymbolSize = 0;
Section->appendData(Str, Asm->getBufferView());
uint8_t SymbolType;
uint8_t SymbolBinding;
if (IsInternal && !Ctx.getFlags().getDisableInternal()) {
SymbolType = STT_NOTYPE;
SymbolBinding = STB_LOCAL;
} else {
SymbolType = STT_FUNC;
SymbolBinding = STB_GLOBAL;
}
SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section,
OffsetInSection, SymbolSize);
StrTab->add(FuncName);
// Copy the fixup information from per-function Assembler memory to the
// object writer's memory, for writing later.
if (!Asm->fixups().empty()) {
RelSection->addRelocations(OffsetInSection, Asm->fixups());
}
}
namespace {
ELFObjectWriter::SectionType
classifyGlobalSection(const VariableDeclaration *Var) {
if (Var->getIsConstant())
return ELFObjectWriter::ROData;
if (Var->hasNonzeroInitializer())
return ELFObjectWriter::Data;
return ELFObjectWriter::BSS;
}
// Partition the Vars list by SectionType into VarsBySection.
// If TranslateOnly is non-empty, then only the TranslateOnly variable
// is kept for emission.
void partitionGlobalsBySection(const VariableDeclarationList &Vars,
VariableDeclarationList VarsBySection[],
const IceString &TranslateOnly) {
for (VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
size_t Section = classifyGlobalSection(Var);
assert(Section < ELFObjectWriter::NumSectionTypes);
VarsBySection[Section].push_back(Var);
}
}
}
} // end of anonymous namespace
void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind,
const IceString &SectionSuffix) {
assert(!SectionNumbersAssigned);
VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
for (auto &SectionList : VarsBySection)
SectionList.reserve(Vars.size());
partitionGlobalsBySection(Vars, VarsBySection,
Ctx.getFlags().getTranslateOnly());
size_t I = 0;
for (auto &SectionList : VarsBySection) {
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
SectionSuffix);
}
}
namespace {
IceString MangleSectionName(const char Base[], const IceString &Suffix) {
if (Suffix.empty())
return Base;
return Base + ("." + Suffix);
}
} // end of anonymous namespace
// TODO(jvoung): Handle fdata-sections.
void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars,
FixupKind RelocationKind,
const IceString &SectionSuffix) {
if (Vars.empty())
return;
ELFDataSection *Section;
ELFRelocationSection *RelSection;
IceString SectionName;
Elf64_Xword ShAddralign = 1;
for (VariableDeclaration *Var : Vars) {
Elf64_Xword Align = Var->getAlignment();
ShAddralign = std::max(ShAddralign, Align);
}
const Elf64_Xword ShEntsize = 0; // non-uniform data element size.
// Lift this out, so it can be re-used if we do fdata-sections?
switch (ST) {
case ROData: {
const IceString SectionName = MangleSectionName(".rodata", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
RODataSections.push_back(Section);
RelSection = createRelocationSection(Section);
RelRODataSections.push_back(RelSection);
break;
}
case Data: {
const IceString SectionName = MangleSectionName(".data", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
DataSections.push_back(Section);
RelSection = createRelocationSection(Section);
RelDataSections.push_back(RelSection);
break;
}
case BSS: {
const IceString SectionName = MangleSectionName(".bss", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
BSSSections.push_back(Section);
break;
}
case NumSectionTypes:
llvm::report_fatal_error("Unknown SectionType");
break;
}
const uint8_t SymbolType = STT_OBJECT;
for (VariableDeclaration *Var : Vars) {
// If the variable declaration does not have an initializer, its symtab
// entry will be created separately.
if (!Var->hasInitializer())
continue;
Elf64_Xword Align = Var->getAlignment();
const Elf64_Xword MinAlign = 1;
Align = std::max(Align, MinAlign);
Section->padToAlignment(Str, Align);
SizeT SymbolSize = Var->getNumBytes();
bool IsExternal = Var->isExternal() || Ctx.getFlags().getDisableInternal();
const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
IceString MangledName = Var->mangleName(&Ctx);
SymTab->createDefinedSym(MangledName, SymbolType, SymbolBinding, Section,
Section->getCurrentSize(), SymbolSize);
StrTab->add(MangledName);
if (!Var->hasNonzeroInitializer()) {
assert(ST == BSS || ST == ROData);
if (ST == ROData)
Section->appendZeros(Str, SymbolSize);
else
Section->setSize(Section->getCurrentSize() + SymbolSize);
} else {
assert(ST != BSS);
for (const std::unique_ptr<VariableDeclaration::Initializer> &Init :
Var->getInitializers()) {
switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: {
const auto &Data =
llvm::cast<VariableDeclaration::DataInitializer>(Init.get())
->getContents();
Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
break;
}
case VariableDeclaration::Initializer::ZeroInitializerKind:
Section->appendZeros(Str, Init->getNumBytes());
break;
case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init.get());
AssemblerFixup NewFixup;
NewFixup.set_position(Section->getCurrentSize());
NewFixup.set_kind(RelocationKind);
const bool SuppressMangling = true;
NewFixup.set_value(Ctx.getConstantSym(
Reloc->getOffset(), Reloc->getDeclaration()->mangleName(&Ctx),
SuppressMangling));
RelSection->addRelocation(NewFixup);
Section->appendRelocationOffset(Str, RelSection->isRela(),
Reloc->getOffset());
break;
}
}
}
}
}
}
void ELFObjectWriter::writeInitialELFHeader() {
assert(!SectionNumbersAssigned);
const Elf64_Off DummySHOffset = 0;
const SizeT DummySHStrIndex = 0;
const SizeT DummyNumSections = 0;
if (ELF64) {
writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex,
DummyNumSections);
} else {
writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex,
DummyNumSections);
}
}
template <bool IsELF64>
void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
SizeT SectHeaderStrIndex,
SizeT NumSections) {
// Write the e_ident: magic number, class, etc.
// The e_ident is byte order and ELF class independent.
Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic)));
Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32);
Str.write8(ELFDATA2LSB);
Str.write8(EV_CURRENT);
Str.write8(ELFOSABI_NONE);
const uint8_t ELF_ABIVersion = 0;
Str.write8(ELF_ABIVersion);
Str.writeZeroPadding(EI_NIDENT - EI_PAD);
// TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc:
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html
// e_shnum should be 0 and then actual number of sections is
// stored in the sh_size member of the 0th section.
assert(NumSections < SHN_LORESERVE);
assert(SectHeaderStrIndex < SHN_LORESERVE);
const TargetArch Arch = Ctx.getFlags().getTargetArch();
// Write the rest of the file header, which does depend on byte order
// and ELF class.
Str.writeLE16(ET_REL); // e_type
Str.writeLE16(getELFMachine(Ctx.getFlags().getTargetArch())); // e_machine
Str.writeELFWord<IsELF64>(1); // e_version
// Since this is for a relocatable object, there is no entry point,
// and no program headers.
Str.writeAddrOrOffset<IsELF64>(0); // e_entry
Str.writeAddrOrOffset<IsELF64>(0); // e_phoff
Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff
Str.writeELFWord<IsELF64>(getELFFlags(Arch)); // e_flags
Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize
static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52,
"Elf_Ehdr sizes cannot be derived from sizeof");
Str.writeLE16(0); // e_phentsize
Str.writeLE16(0); // e_phnum
Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr)
: sizeof(Elf32_Shdr)); // e_shentsize
static_assert(sizeof(Elf64_Shdr) == 64 && sizeof(Elf32_Shdr) == 40,
"Elf_Shdr sizes cannot be derived from sizeof");
Str.writeLE16(static_cast<Elf64_Half>(NumSections)); // e_shnum
Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx
}
template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
ConstantList Pool = Ctx.getConstantPool(Ty);
if (Pool.empty()) {
return;
}
SizeT Align = typeAlignInBytes(Ty);
size_t EntSize = typeWidthInBytes(Ty);
char Buf[20];
SizeT WriteAmt = std::min(EntSize, llvm::array_lengthof(Buf));
// Check that we write the full PrimType.
assert(WriteAmt == EntSize);
// Assume that writing WriteAmt bytes at a time allows us to avoid aligning
// between entries.
assert(WriteAmt % Align == 0);
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_MERGE;
std::string SecBuffer;
llvm::raw_string_ostream SecStrBuf(SecBuffer);
SecStrBuf << ".rodata.cst" << WriteAmt;
ELFDataSection *Section = createSection<ELFDataSection>(
SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
RODataSections.push_back(Section);
SizeT OffsetInSection = 0;
// The symbol table entry doesn't need to know the defined symbol's
// size since this is in a section with a fixed Entry Size.
const SizeT SymbolSize = 0;
Section->setFileOffset(alignFileOffset(Align));
// If the -reorder-pooled-constant option is set to true, we should shuffle
// the constants before we emit them.
auto *CtxPtr = &Ctx;
if (Ctx.getFlags().shouldReorderPooledConstants())
RandomShuffle(Pool.begin(), Pool.end(), [CtxPtr](uint64_t N) {
return (uint32_t)CtxPtr->getRNG().next(N);
});
// Write the data.
for (Constant *C : Pool) {
if (!C->getShouldBePooled())
continue;
auto Const = llvm::cast<ConstType>(C);
std::string SymBuffer;
llvm::raw_string_ostream SymStrBuf(SymBuffer);
Const->emitPoolLabel(SymStrBuf);
std::string &SymName = SymStrBuf.str();
SymTab->createDefinedSym(SymName, STT_NOTYPE, STB_LOCAL, Section,
OffsetInSection, SymbolSize);
StrTab->add(SymName);
typename ConstType::PrimType Value = Const->getValue();
memcpy(Buf, &Value, WriteAmt);
Str.writeBytes(llvm::StringRef(Buf, WriteAmt));
OffsetInSection += WriteAmt;
}
Section->setSize(OffsetInSection);
}
// Instantiate known needed versions of the template, since we are
// defining the function in the .cpp file instead of the .h file.
// We may need to instantiate constant pools for integers as well
// if we do constant-pooling of large integers to remove them
// from the instruction stream (fewer bytes controlled by an attacker).
template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
template void ELFObjectWriter::writeConstantPool<ConstantInteger32>(Type Ty);
void ELFObjectWriter::writeAllRelocationSections() {
writeRelocationSections(RelTextSections);
writeRelocationSections(RelDataSections);
writeRelocationSections(RelRODataSections);
}
void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
for (const Constant *S : UndefSyms) {
const auto Sym = llvm::cast<ConstantRelocatable>(S);
const IceString &Name = Sym->getName();
bool BadIntrinsic;
const Intrinsics::FullIntrinsicInfo *Info =
Ctx.getIntrinsicsInfo().find(Name, BadIntrinsic);
if (Info)
continue;
assert(!BadIntrinsic);
assert(Sym->getOffset() == 0);
assert(Sym->getSuppressMangling());
SymTab->noteUndefinedSym(Name, NullSection);
StrTab->add(Name);
}
}
void ELFObjectWriter::writeRelocationSections(RelSectionList &RelSections) {
for (ELFRelocationSection *RelSec : RelSections) {
Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
RelSec->setFileOffset(Offset);
RelSec->setSize(RelSec->getSectionDataSize());
if (ELF64) {
RelSec->writeData<true>(Ctx, Str, SymTab);
} else {
RelSec->writeData<false>(Ctx, Str, SymTab);
}
}
}
void ELFObjectWriter::writeNonUserSections() {
// Write out the shstrtab now that all sections are known.
ShStrTab->doLayout();
ShStrTab->setSize(ShStrTab->getSectionDataSize());
Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign());
ShStrTab->setFileOffset(ShStrTabOffset);
Str.writeBytes(ShStrTab->getSectionData());
SectionList AllSections;
assignSectionNumbersInfo(AllSections);
// Finalize the regular StrTab and fix up references in the SymTab.
StrTab->doLayout();
StrTab->setSize(StrTab->getSectionDataSize());
SymTab->updateIndices(StrTab);
Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign());
SymTab->setFileOffset(SymTabOffset);
SymTab->setSize(SymTab->getSectionDataSize());
SymTab->writeData(Str, ELF64);
Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign());
StrTab->setFileOffset(StrTabOffset);
Str.writeBytes(StrTab->getSectionData());
writeAllRelocationSections();
// Write out the section headers.
const size_t ShdrAlign = ELF64 ? 8 : 4;
Elf64_Off ShOffset = alignFileOffset(ShdrAlign);
for (const auto S : AllSections) {
if (ELF64)
S->writeHeader<true>(Str);
else
S->writeHeader<false>(Str);
}
// Finally write the updated ELF header w/ the correct number of sections.
Str.seek(0);
if (ELF64) {
writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(),
AllSections.size());
} else {
writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(),
AllSections.size());
}
}
} // end of namespace Ice