| Index: src/IceELFObjectWriter.cpp
|
| diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
|
| index f1b698b434a2058cdd7b7b8ea93ed205933a04f8..c15632194cd7d22d1ebd7ed5021a1c86dab5ea71 100644
|
| --- a/src/IceELFObjectWriter.cpp
|
| +++ b/src/IceELFObjectWriter.cpp
|
| @@ -11,6 +11,8 @@
|
| //
|
| //===----------------------------------------------------------------------===//
|
|
|
| +#include "llvm/Support/MathExtras.h"
|
| +
|
| #include "assembler.h"
|
| #include "IceDefs.h"
|
| #include "IceELFObjectWriter.h"
|
| @@ -103,6 +105,28 @@ T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType,
|
| return NewSection;
|
| }
|
|
|
| +ELFRelocationSection *
|
| +ELFObjectWriter::createRelocationSection(bool IsELF64,
|
| + 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 = IsELF64 ? SHT_RELA : SHT_REL;
|
| + IceString RelPrefix = IsELF64 ? ".rela" : ".rel";
|
| + IceString RelSectionName = RelPrefix + RelatedSection->getName();
|
| + const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
|
| + const Elf64_Xword ShEntSize =
|
| + IsELF64 ? 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,
|
| @@ -150,8 +174,13 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
|
| RelTextSections, AllSections);
|
| assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections,
|
| RelDataSections, AllSections);
|
| - assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RoDataSections,
|
| - RelRoDataSections, 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()));
|
| @@ -170,7 +199,7 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
|
|
|
| assignRelLinkNum(SymTab->getNumber(), RelTextSections);
|
| assignRelLinkNum(SymTab->getNumber(), RelDataSections);
|
| - assignRelLinkNum(SymTab->getNumber(), RelRoDataSections);
|
| + assignRelLinkNum(SymTab->getNumber(), RelRODataSections);
|
| SectionNumbersAssigned = true;
|
| }
|
|
|
| @@ -191,9 +220,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
|
| bool IsInternal, const Assembler *Asm) {
|
| assert(!SectionNumbersAssigned);
|
| ELFTextSection *Section = nullptr;
|
| + ELFRelocationSection *RelSection = nullptr;
|
| // TODO(jvoung): handle ffunction-sections.
|
| IceString SectionName = ".text";
|
| - if (TextSections.size() == 0) {
|
| + bool IsELF64 = isELF64(Ctx.getTargetArch());
|
| + if (TextSections.empty()) {
|
| const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
|
| // TODO(jvoung): Should be bundle size. Grab it from that target?
|
| const Elf64_Xword ShAlign = 32;
|
| @@ -202,8 +233,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
|
| Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
|
| Section->setFileOffset(OffsetInFile);
|
| TextSections.push_back(Section);
|
| + RelSection = createRelocationSection(IsELF64, 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,
|
| @@ -227,41 +261,170 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
|
| // fixup information from per-function Assembler memory to the object
|
| // writer's memory, for writing later.
|
| if (!Asm->fixups().empty()) {
|
| - bool IsELF64 = isELF64(Ctx.getTargetArch());
|
| - IceString RelSectionName = IsELF64 ? ".rela" : ".rel";
|
| - RelSectionName += SectionName;
|
| - ELFRelocationSection *RelSection = nullptr;
|
| - // TODO(jvoung): Make this more efficient if -ffunction-sections
|
| - // efficiency becomes a problem.
|
| - auto RSI =
|
| - std::find_if(RelTextSections.begin(), RelTextSections.end(),
|
| - [&RelSectionName](const ELFRelocationSection *S)
|
| - -> bool { return S->getName() == RelSectionName; });
|
| - if (RSI != RelTextSections.end()) {
|
| - RelSection = *RSI;
|
| - } else {
|
| - const Elf64_Word ShType = IsELF64 ? SHT_RELA : SHT_REL;
|
| - const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
|
| - const Elf64_Xword ShEntSize =
|
| - IsELF64 ? 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;
|
| - RelSection = createSection<ELFRelocationSection>(
|
| - RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
|
| - RelSection->setRelatedSection(Section);
|
| - RelTextSections.push_back(RelSection);
|
| - }
|
| RelSection->addRelocations(OffsetInSection, Asm->fixups());
|
| }
|
| }
|
|
|
| -void ELFObjectWriter::writeDataInitializer(const IceString &VarName,
|
| - const llvm::StringRef Data) {
|
| +namespace {
|
| +
|
| +ELFObjectWriter::SectionType
|
| +classifyGlobalSection(const VariableDeclaration *Var) {
|
| + if (Var->getIsConstant())
|
| + return ELFObjectWriter::ROData;
|
| + if (Var->hasNonzeroInitializer())
|
| + return ELFObjectWriter::Data;
|
| + return ELFObjectWriter::BSS;
|
| +}
|
| +
|
| +// TODO(jvoung): dedupe, use the GlobalContext version
|
| +// https://codereview.chromium.org/870653002/diff/200001/src/IceGlobalContext.h
|
| +bool matchSymbolName(const IceString &SymbolName, const IceString &Match) {
|
| + return Match.empty() || Match == SymbolName;
|
| +}
|
| +
|
| +// 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 (auto Var : Vars) {
|
| + if (matchSymbolName(Var->getName(), TranslateOnly)) {
|
| + size_t Section = classifyGlobalSection(Var);
|
| + assert(Section < ELFObjectWriter::SectionType::NumSectionTypes);
|
| + VarsBySection[Section].push_back(Var);
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // end of anonymous namespace
|
| +
|
| +void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
|
| + FixupKind RelocationKind) {
|
| assert(!SectionNumbersAssigned);
|
| - (void)Data;
|
| - llvm_unreachable("TODO");
|
| - StrTab->add(VarName);
|
| + VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
|
| + for (auto &SectionList : VarsBySection)
|
| + SectionList.reserve(Vars.size());
|
| + partitionGlobalsBySection(Vars, VarsBySection, Ctx.getFlags().TranslateOnly);
|
| + bool IsELF64 = isELF64(Ctx.getTargetArch());
|
| + for (size_t I = ELFObjectWriter::BaseSectionType;
|
| + I < ELFObjectWriter::NumSectionTypes; ++I) {
|
| + writeDataOfType(static_cast<SectionType>(I), VarsBySection[I],
|
| + RelocationKind, IsELF64);
|
| + }
|
| +}
|
| +
|
| +void ELFObjectWriter::writeDataOfType(SectionType SectionType,
|
| + const VariableDeclarationList &Vars,
|
| + FixupKind RelocationKind, bool IsELF64) {
|
| + ELFDataSection *Section;
|
| + ELFRelocationSection *RelSection;
|
| + // TODO(jvoung): Handle fdata-sections.
|
| + IceString SectionName;
|
| + Elf64_Xword ShAddralign = 0; // Actual load-time alignment unknown for now.
|
| + 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 (SectionType) {
|
| + case SectionType::ROData: {
|
| + SectionName = ".rodata";
|
| + // Only expecting to write the data sections all in one shot for now.
|
| + assert(RODataSections.empty());
|
| + // Create the section.
|
| + // A bunch of these properties can be looked up from a table
|
| + // so make it into a defs file?
|
| + const Elf64_Xword ShFlags = SHF_ALLOC;
|
| + Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
|
| + ShAddralign, ShEntsize);
|
| + // Assume file offset doesn't need to be aligned by much (only the
|
| + // sh_addralign is sensitive to the data alignment requirements)
|
| + Section->setFileOffset(alignFileOffset(4));
|
| + RODataSections.push_back(Section);
|
| + RelSection = createRelocationSection(IsELF64, Section);
|
| + RelRODataSections.push_back(RelSection);
|
| + break;
|
| + }
|
| + case SectionType::Data: {
|
| + SectionName = ".data";
|
| + assert(DataSections.empty());
|
| + const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
|
| + Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
|
| + ShAddralign, ShEntsize);
|
| + Section->setFileOffset(alignFileOffset(4));
|
| + DataSections.push_back(Section);
|
| + RelSection = createRelocationSection(IsELF64, Section);
|
| + RelDataSections.push_back(RelSection);
|
| + break;
|
| + }
|
| + case SectionType::BSS: {
|
| + SectionName = ".bss";
|
| + assert(BSSSections.empty());
|
| + const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
|
| + Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
|
| + ShAddralign, ShEntsize);
|
| + Section->setFileOffset(alignFileOffset(4));
|
| + BSSSections.push_back(Section);
|
| + break;
|
| + }
|
| + case SectionType::NumSectionTypes:
|
| + llvm_unreachable("Unknown SectionType");
|
| + break;
|
| + }
|
| +
|
| + const uint8_t SymbolType = STT_OBJECT;
|
| + bool WritePadding = SectionType != SectionType::BSS;
|
| + for (auto *Var : Vars) {
|
| + Elf64_Xword Align = Var->getAlignment();
|
| +
|
| + Section->padToAlignment(Str, WritePadding, Align);
|
| + ShAddralign = std::max(ShAddralign, Align);
|
| +
|
| + SizeT SymbolSize = Var->getNumBytes();
|
| + bool IsExternal = Var->isExternal() || Ctx.getFlags().DisableInternal;
|
| + 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(SectionType == SectionType::BSS ||
|
| + SectionType == SectionType::ROData);
|
| + if (SectionType == SectionType::ROData)
|
| + Section->appendZeros(Str, SymbolSize);
|
| + else
|
| + Section->setSize(Section->getCurrentSize() + SymbolSize);
|
| + } else {
|
| + assert(SectionType != SectionType::BSS);
|
| + for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
|
| + switch (Init->getKind()) {
|
| + case VariableDeclaration::Initializer::DataInitializerKind: {
|
| + const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
|
| + Init)->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);
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + Section->setAlignment(ShAddralign);
|
| }
|
|
|
| void ELFObjectWriter::writeInitialELFHeader() {
|
| @@ -345,7 +508,7 @@ template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
|
| SecStrBuf << ".rodata.cst" << WriteAmt;
|
| ELFDataSection *Section = createSection<ELFDataSection>(
|
| SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
|
| - RoDataSections.push_back(Section);
|
| + 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.
|
| @@ -382,7 +545,7 @@ template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
|
| void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) {
|
| writeRelocationSections(IsELF64, RelTextSections);
|
| writeRelocationSections(IsELF64, RelDataSections);
|
| - writeRelocationSections(IsELF64, RelRoDataSections);
|
| + writeRelocationSections(IsELF64, RelRODataSections);
|
| }
|
|
|
| void ELFObjectWriter::writeRelocationSections(bool IsELF64,
|
|
|