Index: src/IceELFObjectWriter.cpp |
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f3a63df5c23558caa3938a94c7a3238cfbf4bd20 |
--- /dev/null |
+++ b/src/IceELFObjectWriter.cpp |
@@ -0,0 +1,347 @@ |
+//===- 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. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// This file defines the writer for ELF relocatable object files. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "IceDefs.h" |
+#include "IceELFObjectWriter.h" |
+#include "IceELFSection.h" |
+#include "IceELFStreamer.h" |
+#include "IceGlobalContext.h" |
+#include "IceGlobalInits.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), SectionNumbersAssigned(false) { |
+ // 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"); |
+ bool IsELF64 = isELF64(Ctx.getTargetArch()); |
+ const Elf64_Xword SymTabAlign = IsELF64 ? 8 : 4; |
+ const Elf64_Xword SymTabEntSize = |
+ IsELF64 ? 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); |
+ // The first entry in the symbol table should be a NULL entry. |
+ const IceString NullSymName(""); |
+ SymTab->createDefinedSym(NullSymName, STT_NOTYPE, STB_LOCAL, NullSection, 0, |
+ 0); |
+ |
+ 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; |
+} |
+ |
+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) { |
+ ELFRelocationSectionBase *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 (ELFRelocationSectionBase *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); |
+ 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) { |
+ assert(llvm::isPowerOf2_32(Align)); |
+ Elf64_Off OffsetInFile = Str.tell(); |
+ Elf64_Xword Mod = OffsetInFile & (Align - 1); |
+ if (Mod == 0) |
+ return OffsetInFile; |
+ Elf64_Xword AlignDiff = Align - Mod; |
+ Str.writeZeroPadding(AlignDiff); |
+ OffsetInFile += AlignDiff; |
+ assert((OffsetInFile & (Align - 1)) == 0); |
+ return OffsetInFile; |
+} |
+ |
+void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, |
+ bool IsInternal, |
+ const llvm::StringRef Data) { |
+ assert(!SectionNumbersAssigned); |
+ // TODO(jvoung): handle ffunction-sections. |
+ IceString SectionName = ".text"; |
+ ELFTextSection *Section = nullptr; |
+ if (TextSections.size() == 0) { |
+ const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR; |
+ // TODO(jvoung): Should be bundle size. Grab it from that target? |
+ const Elf64_Xword ShAlign = 32; |
+ Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags, |
+ ShAlign, 0); |
+ Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign()); |
+ Section->setFileOffset(OffsetInFile); |
+ TextSections.push_back(Section); |
+ } else { |
+ Section = TextSections[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, Data); |
+ uint8_t SymbolType; |
+ uint8_t SymbolBinding; |
+ if (IsInternal) { |
+ SymbolType = STT_NOTYPE; |
+ SymbolBinding = STB_LOCAL; |
+ } else { |
+ SymbolType = STT_FUNC; |
+ SymbolBinding = STB_GLOBAL; |
+ } |
+ SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section, |
+ OffsetInSection, SymbolSize); |
+ StrTab->add(FuncName); |
+} |
+ |
+void ELFObjectWriter::writeDataInitializer(const IceString &VarName, |
+ const llvm::StringRef Data) { |
+ assert(!SectionNumbersAssigned); |
+ (void)Data; |
+ llvm_unreachable("TODO"); |
+ StrTab->add(VarName); |
+} |
+ |
+void ELFObjectWriter::writeInitialELFHeader() { |
+ assert(!SectionNumbersAssigned); |
+ const size_t DummySHOffset = 0; |
+ const SizeT DummySHStrIndex = 0; |
+ const SizeT DummyNumSections = 0; |
+ if (isELF64(Ctx.getTargetArch())) { |
+ writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex, |
+ DummyNumSections); |
+ } else { |
+ writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex, |
+ DummyNumSections); |
+ } |
+} |
+ |
+template <bool IsELF64> |
+void ELFObjectWriter::writeELFHeaderInternal(size_t 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); |
+ |
+ // 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.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(Ctx.getTargetArch())); // 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 |
+} |
+ |
+void ELFObjectWriter::writeNonUserSections() { |
+ bool IsELF64 = isELF64(Ctx.getTargetArch()); |
+ |
+ // 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, IsELF64); |
+ |
+ Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign()); |
+ StrTab->setFileOffset(StrTabOffset); |
+ Str.writeBytes(StrTab->getSectionData()); |
+ |
+ // TODO: Write out the relocation sections. |
+ // May also be able to seek around the file and resolve function calls |
+ // that are for functions within the same section. |
+ |
+ // Write out the section headers. |
+ const size_t ShdrAlign = IsELF64 ? 8 : 4; |
+ Elf64_Off ShOffset = alignFileOffset(ShdrAlign); |
+ for (const auto S : AllSections) { |
+ if (IsELF64) |
+ 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 (IsELF64) { |
+ writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(), |
+ AllSections.size()); |
+ } else { |
+ writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(), |
+ AllSections.size()); |
+ } |
+} |
+ |
+} // end of namespace Ice |