X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fyaml2obj%2Fyaml2elf.cpp;h=44c8c12da89df6ba6fe7ed3be34f0274cdc22d97;hb=19afe671570c300ac176a510b40ea11d0081e403;hp=2f4774f56203c99cf69867b8956f14861b6691d1;hpb=f3f3523b9c714d9b98f6102ce79ed3d0c9050169;p=oota-llvm.git diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 2f4774f5620..44c8c12da89 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -13,7 +13,9 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" -#include "llvm/Object/ELF.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFYAML.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MemoryBuffer.h" @@ -22,81 +24,49 @@ using namespace llvm; -// There is similar code in yaml2coff, but with some slight COFF-specific -// variations like different initial state. Might be able to deduplicate -// some day, but also want to make sure that the Mach-O use case is served. -// -// This class has a deliberately small interface, since a lot of -// implementation variation is possible. -// -// TODO: Use an ordered container with a suffix-based comparison in order -// to deduplicate suffixes. std::map<> with a custom comparator is likely -// to be the simplest implementation, but a suffix trie could be more -// suitable for the job. -namespace { -class StringTableBuilder { - /// \brief Indices of strings currently present in `Buf`. - StringMap StringIndices; - /// \brief The contents of the string table as we build it. - std::string Buf; -public: - StringTableBuilder() { - Buf.push_back('\0'); - } - /// \returns Index of string in string table. - unsigned addString(StringRef S) { - StringMapEntry &Entry = StringIndices.GetOrCreateValue(S); - unsigned &I = Entry.getValue(); - if (I != 0) - return I; - I = Buf.size(); - Buf.append(S.begin(), S.end()); - Buf.push_back('\0'); - return I; - } - size_t size() const { - return Buf.size(); - } - void writeToStream(raw_ostream &OS) { - OS.write(Buf.data(), Buf.size()); - } -}; -} // end anonymous namespace - // This class is used to build up a contiguous binary blob while keeping // track of an offset in the output (which notionally begins at // `InitialOffset`). namespace { class ContiguousBlobAccumulator { const uint64_t InitialOffset; + SmallVector Buf; raw_svector_ostream OS; + /// \returns The new offset. + uint64_t padToAlignment(unsigned Align) { + uint64_t CurrentOffset = InitialOffset + OS.tell(); + uint64_t AlignedOffset = RoundUpToAlignment(CurrentOffset, Align); + for (; CurrentOffset != AlignedOffset; ++CurrentOffset) + OS.write('\0'); + return AlignedOffset; // == CurrentOffset; + } + public: - ContiguousBlobAccumulator(uint64_t InitialOffset_, SmallVectorImpl &Buf) - : InitialOffset(InitialOffset_), OS(Buf) {} - raw_ostream &getOS() { return OS; } - uint64_t currentOffset() const { return InitialOffset + OS.tell(); } + ContiguousBlobAccumulator(uint64_t InitialOffset_) + : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} + template + raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align = 16) { + Offset = padToAlignment(Align); + return OS; + } void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } }; } // end anonymous namespace -// Used to keep track of section names, so that in the YAML file sections -// can be referenced by name instead of by index. +// Used to keep track of section and symbol names, so that in the YAML file +// sections and symbols can be referenced by name instead of by index. namespace { -class SectionNameToIdxMap { +class NameToIdxMap { StringMap Map; public: /// \returns true if name is already present in the map. - bool addName(StringRef SecName, unsigned i) { - StringMapEntry &Entry = Map.GetOrCreateValue(SecName, -1); - if (Entry.getValue() != -1) - return true; - Entry.setValue((int)i); - return false; + bool addName(StringRef Name, unsigned i) { + return !Map.insert(std::make_pair(Name, (int)i)).second; } /// \returns true if name is not present in the map - bool lookupSection(StringRef SecName, unsigned &Idx) const { - StringMap::const_iterator I = Map.find(SecName); + bool lookup(StringRef Name, unsigned &Idx) const { + StringMap::const_iterator I = Map.find(Name); if (I == Map.end()) return true; Idx = I->getValue(); @@ -106,13 +76,13 @@ public: } // end anonymous namespace template -static size_t vectorDataSize(const std::vector &Vec) { - return Vec.size() * sizeof(T); +static size_t arrayDataSize(ArrayRef A) { + return A.size() * sizeof(T); } template -static void writeVectorData(raw_ostream &OS, const std::vector &Vec) { - OS.write((const char *)Vec.data(), vectorDataSize(Vec)); +static void writeArrayData(raw_ostream &OS, ArrayRef A) { + OS.write((const char *)A.data(), arrayDataSize(A)); } template @@ -120,16 +90,67 @@ static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } +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 -static void writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { - using namespace llvm::ELF; - using namespace llvm::object; - typedef typename ELFObjectFile::Elf_Ehdr Elf_Ehdr; - typedef typename ELFObjectFile::Elf_Shdr Elf_Shdr; +class ELFState { + typedef typename object::ELFFile::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFFile::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile::Elf_Sym Elf_Sym; + typedef typename object::ELFFile::Elf_Rel Elf_Rel; + typedef typename object::ELFFile::Elf_Rela Elf_Rela; - const ELFYAML::FileHeader &Hdr = Doc.Header; + /// \brief The future ".strtab" section. + StringTableBuilder DotStrtab; - Elf_Ehdr Header; + /// \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 &Symbols); + void initELFHeader(Elf_Ehdr &Header); + bool initSectionHeaders(std::vector &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 &Symbols, + std::vector &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); + + // - 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 +void ELFState::initELFHeader(Elf_Ehdr &Header) { + using namespace llvm::ELF; zero(Header); Header.e_ident[EI_MAG0] = 0x7f; Header.e_ident[EI_MAG1] = 'E'; @@ -139,122 +160,331 @@ static void writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { bool IsLittleEndian = ELFT::TargetEndianness == support::little; Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; Header.e_ident[EI_VERSION] = EV_CURRENT; - // TODO: Implement ELF_ELFOSABI enum. - Header.e_ident[EI_OSABI] = ELFOSABI_NONE; - // TODO: Implement ELF_ABIVERSION enum. + Header.e_ident[EI_OSABI] = Doc.Header.OSABI; Header.e_ident[EI_ABIVERSION] = 0; - Header.e_type = Hdr.Type; - Header.e_machine = Hdr.Machine; + Header.e_type = Doc.Header.Type; + Header.e_machine = Doc.Header.Machine; Header.e_version = EV_CURRENT; - Header.e_entry = Hdr.Entry; + Header.e_entry = Doc.Header.Entry; + Header.e_flags = Doc.Header.Flags; Header.e_ehsize = sizeof(Elf_Ehdr); - - // TODO: Flesh out section header support. - // TODO: Program headers. - Header.e_shentsize = sizeof(Elf_Shdr); // Immediately following the ELF header. Header.e_shoff = sizeof(Header); - std::vector Sections = Doc.Sections; - if (Sections.empty() || Sections.front().Type != SHT_NULL) { - ELFYAML::Section S; - S.Type = SHT_NULL; - zero(S.Flags); - Sections.insert(Sections.begin(), S); + Header.e_shnum = getSectionCount(); + Header.e_shstrndx = getDotShStrTabSecNo(); +} + +template +bool ELFState::initSectionHeaders(std::vector &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(Sec.get())) + writeSectionContent(SHeader, *S, CBA); + else if (auto S = dyn_cast(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 + llvm_unreachable("Unknown section type"); + + SHeaders.push_back(SHeader); } - // "+ 1" for string table. - Header.e_shnum = Sections.size() + 1; - // Place section header string table last. - Header.e_shstrndx = Sections.size(); - - SectionNameToIdxMap SN2I; - for (unsigned i = 0, e = Sections.size(); i != e; ++i) { - StringRef Name = Sections[i].Name; + return true; +} + +template +void ELFState::initSymtabSectionHeader(Elf_Shdr &SHeader, + ContiguousBlobAccumulator &CBA) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.getOffset(".symtab"); + SHeader.sh_type = ELF::SHT_SYMTAB; + SHeader.sh_link = getDotStrTabSecNo(); + // One greater than symbol table index of the last local symbol. + SHeader.sh_info = Doc.Symbols.Local.size() + 1; + SHeader.sh_entsize = sizeof(Elf_Sym); + + std::vector Syms; + { + // Ensure STN_UNDEF is present + Elf_Sym Sym; + zero(Sym); + Syms.push_back(Sym); + } + + // Add symbol names to .strtab. + for (const auto &Sym : Doc.Symbols.Local) + DotStrtab.add(Sym.Name); + for (const auto &Sym : Doc.Symbols.Global) + DotStrtab.add(Sym.Name); + for (const auto &Sym : Doc.Symbols.Weak) + DotStrtab.add(Sym.Name); + DotStrtab.finalize(StringTableBuilder::ELF); + + addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL); + addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL); + addSymbols(Doc.Symbols.Weak, Syms, ELF::STB_WEAK); + + writeArrayData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), + makeArrayRef(Syms)); + SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); +} + +template +void ELFState::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, + StringTableBuilder &STB, + ContiguousBlobAccumulator &CBA) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.getOffset(Name); + SHeader.sh_type = ELF::SHT_STRTAB; + CBA.getOSAndAlignedOffset(SHeader.sh_offset) << STB.data(); + SHeader.sh_size = STB.data().size(); + SHeader.sh_addralign = 1; +} + +template +void ELFState::addSymbols(const std::vector &Symbols, + std::vector &Syms, + unsigned SymbolBinding) { + for (const auto &Sym : Symbols) { + Elf_Sym Symbol; + zero(Symbol); + if (!Sym.Name.empty()) + Symbol.st_name = DotStrtab.getOffset(Sym.Name); + Symbol.setBindingAndType(SymbolBinding, Sym.Type); + if (!Sym.Section.empty()) { + unsigned Index; + if (SN2I.lookup(Sym.Section, Index)) { + errs() << "error: Unknown section referenced: '" << Sym.Section + << "' by YAML symbol " << Sym.Name << ".\n"; + exit(1); + } + Symbol.st_shndx = Index; + } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. + Symbol.st_value = Sym.Value; + Symbol.st_other = Sym.Other; + Symbol.st_size = Sym.Size; + Syms.push_back(Symbol); + } +} + +template +void +ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RawContentSection &Section, + ContiguousBlobAccumulator &CBA) { + assert(Section.Size >= Section.Content.binary_size() && + "Section size and section content are inconsistent"); + raw_ostream &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); + Section.Content.writeAsBinary(OS); + for (auto i = Section.Content.binary_size(); i < Section.Size; ++i) + OS.write(0); + SHeader.sh_entsize = 0; + SHeader.sh_size = Section.Size; +} + +template +bool +ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RelocationSection &Section, + ContiguousBlobAccumulator &CBA) { + if (Section.Type != llvm::ELF::SHT_REL && + Section.Type != llvm::ELF::SHT_RELA) { + errs() << "error: Invalid relocation section type.\n"; + return false; + } + + bool IsRela = Section.Type == llvm::ELF::SHT_RELA; + SHeader.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + SHeader.sh_size = SHeader.sh_entsize * Section.Relocations.size(); + + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); + + for (const auto &Rel : Section.Relocations) { + unsigned SymIdx; + if (SymN2I.lookup(Rel.Symbol, SymIdx)) { + errs() << "error: Unknown symbol referenced: '" << Rel.Symbol + << "' at YAML relocation.\n"; + return false; + } + + if (IsRela) { + Elf_Rela REntry; + zero(REntry); + REntry.r_offset = Rel.Offset; + REntry.r_addend = Rel.Addend; + REntry.setSymbolAndType(SymIdx, Rel.Type); + OS.write((const char *)&REntry, sizeof(REntry)); + } else { + Elf_Rel REntry; + zero(REntry); + REntry.r_offset = Rel.Offset; + REntry.setSymbolAndType(SymIdx, Rel.Type); + OS.write((const char *)&REntry, sizeof(REntry)); + } + } + return true; +} + +template bool ELFState::buildSectionIndex() { + SN2I.addName(".symtab", getDotSymTabSecNo()); + SN2I.addName(".strtab", getDotStrTabSecNo()); + SN2I.addName(".shstrtab", getDotShStrTabSecNo()); + + for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { + StringRef Name = Doc.Sections[i]->Name; if (Name.empty()) continue; - if (SN2I.addName(Name, i)) { + // "+ 1" to take into account the SHT_NULL entry. + if (SN2I.addName(Name, i + 1)) { errs() << "error: Repeated section name: '" << Name << "' at YAML section number " << i << ".\n"; - return; + return false; } } + return true; +} + +template +bool +ELFState::buildSymbolIndex(std::size_t &StartIndex, + const std::vector &Symbols) { + for (const auto &Sym : Symbols) { + ++StartIndex; + if (Sym.Name.empty()) + continue; + if (SymN2I.addName(Sym.Name, StartIndex)) { + errs() << "error: Repeated symbol name: '" << Sym.Name << "'.\n"; + return false; + } + } + return true; +} + +template +int ELFState::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { + ELFState State(Doc); + if (!State.buildSectionIndex()) + return 1; + + std::size_t StartSymIndex = 0; + if (!State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Local) || + !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Global) || + !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Weak)) + return 1; + + Elf_Ehdr Header; + State.initELFHeader(Header); + + // TODO: Flesh out section header support. + // TODO: Program headers. - StringTableBuilder StrTab; - SmallVector Buf; // XXX: This offset is tightly coupled with the order that we write // things to `OS`. const size_t SectionContentBeginOffset = Header.e_ehsize + Header.e_shentsize * Header.e_shnum; - ContiguousBlobAccumulator CBA(SectionContentBeginOffset, Buf); + ContiguousBlobAccumulator CBA(SectionContentBeginOffset); + + // Doc might not contain .symtab, .strtab and .shstrtab sections, + // but we will emit them, so make sure to add them to ShStrTabSHeader. + State.DotShStrtab.add(".symtab"); + State.DotShStrtab.add(".strtab"); + State.DotShStrtab.add(".shstrtab"); + std::vector SHeaders; - for (unsigned i = 0, e = Sections.size(); i != e; ++i) { - const ELFYAML::Section &Sec = Sections[i]; - Elf_Shdr SHeader; - zero(SHeader); - SHeader.sh_name = StrTab.addString(Sec.Name); - SHeader.sh_type = Sec.Type; - SHeader.sh_flags = Sec.Flags; - SHeader.sh_addr = Sec.Address; + if(!State.initSectionHeaders(SHeaders, CBA)) + return 1; - SHeader.sh_offset = CBA.currentOffset(); - SHeader.sh_size = Sec.Content.binary_size(); - Sec.Content.writeAsBinary(CBA.getOS()); + // .symtab section. + Elf_Shdr SymtabSHeader; + State.initSymtabSectionHeader(SymtabSHeader, CBA); + SHeaders.push_back(SymtabSHeader); - if (!Sec.Link.empty()) { - unsigned Index; - if (SN2I.lookupSection(Sec.Link, Index)) { - errs() << "error: Unknown section referenced: '" << Sec.Link - << "' at YAML section number " << i << ".\n"; - return; - } - SHeader.sh_link = Index; - } - SHeader.sh_info = 0; - SHeader.sh_addralign = Sec.AddressAlign; - SHeader.sh_entsize = 0; - SHeaders.push_back(SHeader); - } + // .strtab string table header. + Elf_Shdr DotStrTabSHeader; + State.initStrtabSectionHeader(DotStrTabSHeader, ".strtab", State.DotStrtab, + CBA); + SHeaders.push_back(DotStrTabSHeader); - // String table header. - Elf_Shdr StrTabSHeader; - zero(StrTabSHeader); - StrTabSHeader.sh_name = 0; - StrTabSHeader.sh_type = SHT_STRTAB; - StrTabSHeader.sh_flags = 0; - StrTabSHeader.sh_addr = 0; - StrTabSHeader.sh_offset = CBA.currentOffset(); - StrTabSHeader.sh_size = StrTab.size(); - StrTab.writeToStream(CBA.getOS()); - StrTabSHeader.sh_link = 0; - StrTabSHeader.sh_info = 0; - StrTabSHeader.sh_addralign = 1; - StrTabSHeader.sh_entsize = 0; + // .shstrtab string table header. + Elf_Shdr ShStrTabSHeader; + State.initStrtabSectionHeader(ShStrTabSHeader, ".shstrtab", State.DotShStrtab, + CBA); + SHeaders.push_back(ShStrTabSHeader); OS.write((const char *)&Header, sizeof(Header)); - writeVectorData(OS, SHeaders); - OS.write((const char *)&StrTabSHeader, sizeof(StrTabSHeader)); + writeArrayData(OS, makeArrayRef(SHeaders)); CBA.writeBlobToStream(OS); + return 0; +} + +static bool is64Bit(const ELFYAML::Object &Doc) { + return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); } -int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { - yaml::Input YIn(Buf->getBuffer()); +static bool isLittleEndian(const ELFYAML::Object &Doc) { + return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); +} + +int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { ELFYAML::Object Doc; YIn >> Doc; if (YIn.error()) { errs() << "yaml2obj: Failed to parse YAML file!\n"; return 1; } - if (Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) { - if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) - writeELF >(outs(), Doc); + using object::ELFType; + typedef ELFType LE64; + typedef ELFType BE64; + typedef ELFType LE32; + typedef ELFType BE32; + if (is64Bit(Doc)) { + if (isLittleEndian(Doc)) + return ELFState::writeELF(Out, Doc); else - writeELF >(outs(), Doc); + return ELFState::writeELF(Out, Doc); } else { - if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) - writeELF >(outs(), Doc); + if (isLittleEndian(Doc)) + return ELFState::writeELF(Out, Doc); else - writeELF >(outs(), Doc); + return ELFState::writeELF(Out, Doc); } - - return 0; }