+namespace {
+/// \brief "Single point of truth" for the ELF file construction.
+/// TODO: This class still has a ways to go before it is truly a "single
+/// point of truth".
+template <class ELFT>
+class ELFState {
+ typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
+ typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ typedef typename object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ typedef typename object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+
+ /// \brief The future ".strtab" section.
+ StringTableBuilder DotStrtab;
+
+ /// \brief The future ".shstrtab" section.
+ StringTableBuilder DotShStrtab;
+
+ NameToIdxMap SN2I;
+ NameToIdxMap SymN2I;
+ const ELFYAML::Object &Doc;
+
+ bool buildSectionIndex();
+ bool buildSymbolIndex(std::size_t &StartIndex,
+ const std::vector<ELFYAML::Symbol> &Symbols);
+ void initELFHeader(Elf_Ehdr &Header);
+ bool initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
+ ContiguousBlobAccumulator &CBA);
+ void initSymtabSectionHeader(Elf_Shdr &SHeader,
+ ContiguousBlobAccumulator &CBA);
+ void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
+ StringTableBuilder &STB,
+ ContiguousBlobAccumulator &CBA);
+ void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
+ std::vector<Elf_Sym> &Syms, unsigned SymbolBinding);
+ void writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::RawContentSection &Section,
+ ContiguousBlobAccumulator &CBA);
+ bool writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::RelocationSection &Section,
+ ContiguousBlobAccumulator &CBA);
+ bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group,
+ ContiguousBlobAccumulator &CBA);
+
+ // - SHT_NULL entry (placed first, i.e. 0'th entry)
+ // - symbol table (.symtab) (placed third to last)
+ // - string table (.strtab) (placed second to last)
+ // - section header string table (.shstrtab) (placed last)
+ unsigned getDotSymTabSecNo() const { return Doc.Sections.size() + 1; }
+ unsigned getDotStrTabSecNo() const { return Doc.Sections.size() + 2; }
+ unsigned getDotShStrTabSecNo() const { return Doc.Sections.size() + 3; }
+ unsigned getSectionCount() const { return Doc.Sections.size() + 4; }
+
+ ELFState(const ELFYAML::Object &D) : Doc(D) {}
+
+public:
+ static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc);
+};
+} // end anonymous namespace
+
+template <class ELFT>
+void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
+ using namespace llvm::ELF;
+ zero(Header);
+ Header.e_ident[EI_MAG0] = 0x7f;
+ Header.e_ident[EI_MAG1] = 'E';
+ Header.e_ident[EI_MAG2] = 'L';
+ Header.e_ident[EI_MAG3] = 'F';
+ Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+ bool IsLittleEndian = ELFT::TargetEndianness == support::little;
+ Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
+ Header.e_ident[EI_VERSION] = EV_CURRENT;
+ Header.e_ident[EI_OSABI] = Doc.Header.OSABI;
+ Header.e_ident[EI_ABIVERSION] = 0;
+ Header.e_type = Doc.Header.Type;
+ Header.e_machine = Doc.Header.Machine;
+ Header.e_version = EV_CURRENT;
+ Header.e_entry = Doc.Header.Entry;
+ Header.e_flags = Doc.Header.Flags;
+ Header.e_ehsize = sizeof(Elf_Ehdr);
+ Header.e_shentsize = sizeof(Elf_Shdr);
+ // Immediately following the ELF header.
+ Header.e_shoff = sizeof(Header);
+ Header.e_shnum = getSectionCount();
+ Header.e_shstrndx = getDotShStrTabSecNo();
+}
+
+template <class ELFT>
+bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
+ ContiguousBlobAccumulator &CBA) {
+ // Ensure SHN_UNDEF entry is present. An all-zero section header is a
+ // valid SHN_UNDEF entry since SHT_NULL == 0.
+ Elf_Shdr SHeader;
+ zero(SHeader);
+ SHeaders.push_back(SHeader);
+
+ for (const auto &Sec : Doc.Sections)
+ DotShStrtab.add(Sec->Name);
+ DotShStrtab.finalize(StringTableBuilder::ELF);
+
+ for (const auto &Sec : Doc.Sections) {
+ zero(SHeader);
+ SHeader.sh_name = DotShStrtab.getOffset(Sec->Name);
+ SHeader.sh_type = Sec->Type;
+ SHeader.sh_flags = Sec->Flags;
+ SHeader.sh_addr = Sec->Address;
+ SHeader.sh_addralign = Sec->AddressAlign;
+
+ if (!Sec->Link.empty()) {
+ unsigned Index;
+ if (SN2I.lookup(Sec->Link, Index)) {
+ errs() << "error: Unknown section referenced: '" << Sec->Link
+ << "' at YAML section '" << Sec->Name << "'.\n";
+ return false;
+ }
+ SHeader.sh_link = Index;
+ }
+
+ if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec.get()))
+ writeSectionContent(SHeader, *S, CBA);
+ else if (auto S = dyn_cast<ELFYAML::RelocationSection>(Sec.get())) {
+ if (S->Link.empty())
+ // For relocation section set link to .symtab by default.
+ SHeader.sh_link = getDotSymTabSecNo();
+
+ unsigned Index;
+ if (SN2I.lookup(S->Info, Index)) {
+ errs() << "error: Unknown section referenced: '" << S->Info
+ << "' at YAML section '" << S->Name << "'.\n";
+ return false;
+ }
+ SHeader.sh_info = Index;
+
+ if (!writeSectionContent(SHeader, *S, CBA))
+ return false;
+ } else if (auto S = dyn_cast<ELFYAML::Group>(Sec.get())) {
+ unsigned SymIdx;
+ if (SymN2I.lookup(S->Info, SymIdx)) {
+ errs() << "error: Unknown symbol referenced: '" << S->Info
+ << "' at YAML section '" << S->Name << "'.\n";
+ return false;
+ }
+ SHeader.sh_info = SymIdx;
+ if (!writeSectionContent(SHeader, *S, CBA))
+ return false;
+ } else
+ llvm_unreachable("Unknown section type");
+
+ SHeaders.push_back(SHeader);
+ }
+ return true;