Index: src/IceELFObjectWriter.cpp |
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp |
index c4ff4f03d0ed7530391b5cb16ccbbd66fac6f1ff..21ea80dfcc4cb18f10b74f4d4d2f730e1ee481b1 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,20 +199,17 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) { |
assignRelLinkNum(SymTab->getNumber(), RelTextSections); |
assignRelLinkNum(SymTab->getNumber(), RelDataSections); |
- assignRelLinkNum(SymTab->getNumber(), RelRoDataSections); |
+ assignRelLinkNum(SymTab->getNumber(), RelRODataSections); |
SectionNumbersAssigned = true; |
} |
Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { |
- assert(llvm::isPowerOf2_32(Align)); |
Elf64_Off OffsetInFile = Str.tell(); |
- Elf64_Xword Mod = OffsetInFile & (Align - 1); |
- if (Mod == 0) |
+ Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align); |
+ if (AlignDiff == 0) |
return OffsetInFile; |
- Elf64_Xword AlignDiff = Align - Mod; |
Str.writeZeroPadding(AlignDiff); |
OffsetInFile += AlignDiff; |
- assert((OffsetInFile & (Align - 1)) == 0); |
return OffsetInFile; |
} |
@@ -191,9 +217,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, |
bool IsInternal, const Assembler *Asm) { |
assert(!SectionNumbersAssigned); |
ELFTextSection *Section = nullptr; |
- // TODO(jvoung): handle ffunction-sections. |
- IceString SectionName = ".text"; |
- if (TextSections.size() == 0) { |
+ ELFRelocationSection *RelSection = nullptr; |
+ if (TextSections.empty()) { |
+ // TODO(jvoung): handle ffunction-sections. |
+ IceString SectionName = ".text"; |
+ bool IsELF64 = isELF64(Ctx.getTargetArch()); |
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 +230,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 +258,158 @@ 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; |
+} |
+ |
+// 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::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; |
Jim Stichnoth
2015/01/28 20:35:08
Consider doing something like this to make the sec
jvoung (off chromium)
2015/01/28 23:37:52
Done sort of -- If I is type SectionType, then I++
Jim Stichnoth
2015/01/29 00:38:14
BTW, JF pointed out this would be possible using a
|
+ 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; |
+ for (auto *Var : Vars) { |
Jim Stichnoth
2015/01/28 20:35:08
auto --> VariableDeclaration
jvoung (off chromium)
2015/01/28 23:37:53
Done.
|
+ 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 (SectionType) { |
+ case SectionType::ROData: { |
+ SectionName = ".rodata"; |
+ // Only expecting to write the data sections all in one shot for now. |
+ assert(RODataSections.empty()); |
+ 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(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(ShAddralign)); |
+ 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(ShAddralign)); |
+ BSSSections.push_back(Section); |
+ break; |
+ } |
+ case SectionType::NumSectionTypes: |
+ llvm::report_fatal_error("Unknown SectionType"); |
+ break; |
+ } |
+ |
+ const uint8_t SymbolType = STT_OBJECT; |
+ for (auto *Var : Vars) { |
Jim Stichnoth
2015/01/28 20:35:08
auto --> VariableDeclaration
jvoung (off chromium)
2015/01/28 23:37:53
Done.
|
+ Elf64_Xword Align = Var->getAlignment(); |
+ Section->padToAlignment(Str, 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; |
+ } |
+ } |
+ } |
+ } |
+ } |
} |
void ELFObjectWriter::writeInitialELFHeader() { |
@@ -345,7 +493,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 +530,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, |