//===- yaml2elf - Convert YAML to a ELF object file -----------------------===////// The LLVM Compiler Infrastructure//// This file is distributed under the University of Illinois Open Source// License. See LICENSE.TXT for details.////===----------------------------------------------------------------------===//////// \file/// \brief The ELF component of yaml2obj./////===----------------------------------------------------------------------===//#include"yaml2obj.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"#include"llvm/Support/YAMLTraits.h"#include"llvm/Support/raw_ostream.h"usingnamespacellvm;// 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{classContiguousBlobAccumulator{constuint64_tInitialOffset;SmallVector<char,128>Buf;raw_svector_ostreamOS;/// \returns The new offset.uint64_tpadToAlignment(unsignedAlign){uint64_tCurrentOffset=InitialOffset+OS.tell();uint64_tAlignedOffset=RoundUpToAlignment(CurrentOffset,Align);for(;CurrentOffset!=AlignedOffset;++CurrentOffset)OS.write('\0');returnAlignedOffset;// == CurrentOffset;}public:ContiguousBlobAccumulator(uint64_tInitialOffset_):InitialOffset(InitialOffset_),Buf(),OS(Buf){}template<classInteger>raw_ostream&getOSAndAlignedOffset(Integer&Offset,unsignedAlign=16){Offset=padToAlignment(Align);returnOS;}voidwriteBlobToStream(raw_ostream&Out){Out<<OS.str();}};}// end anonymous namespace// 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{classNameToIdxMap{StringMap<int>Map;public:/// \returns true if name is already present in the map.booladdName(StringRefName,unsignedi){return!Map.insert(std::make_pair(Name,(int)i)).second;}/// \returns true if name is not present in the mapboollookup(StringRefName,unsigned&Idx)const{StringMap<int>::const_iteratorI=Map.find(Name);if(I==Map.end())returntrue;Idx=I->getValue();returnfalse;}};}// end anonymous namespacetemplate<classT>staticsize_tarrayDataSize(ArrayRef<T>A){returnA.size()*sizeof(T);}template<classT>staticvoidwriteArrayData(raw_ostream&OS,ArrayRef<T>A){OS.write((constchar*)A.data(),arrayDataSize(A));}template<classT>staticvoidzero(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<classELFT>classELFState{typedeftypenameobject::ELFFile<ELFT>::Elf_EhdrElf_Ehdr;typedeftypenameobject::ELFFile<ELFT>::Elf_ShdrElf_Shdr;typedeftypenameobject::ELFFile<ELFT>::Elf_SymElf_Sym;typedeftypenameobject::ELFFile<ELFT>::Elf_RelElf_Rel;typedeftypenameobject::ELFFile<ELFT>::Elf_RelaElf_Rela;/// \brief The future ".strtab" section.StringTableBuilderDotStrtab;/// \brief The future ".shstrtab" section.StringTableBuilderDotShStrtab;NameToIdxMapSN2I;NameToIdxMapSymN2I;constELFYAML::Object&Doc;boolbuildSectionIndex();boolbuildSymbolIndex(std::size_t&StartIndex,conststd::vector<ELFYAML::Symbol>&Symbols);voidinitELFHeader(Elf_Ehdr&Header);boolinitSectionHeaders(std::vector<Elf_Shdr>&SHeaders,ContiguousBlobAccumulator&CBA);voidinitSymtabSectionHeader(Elf_Shdr&SHeader,ContiguousBlobAccumulator&CBA);voidinitStrtabSectionHeader(Elf_Shdr&SHeader,StringRefName,StringTableBuilder&STB,ContiguousBlobAccumulator&CBA);voidaddSymbols(conststd::vector<ELFYAML::Symbol>&Symbols,std::vector<Elf_Sym>&Syms,unsignedSymbolBinding);voidwriteSectionContent(Elf_Shdr&SHeader,constELFYAML::RawContentSection&Section,ContiguousBlobAccumulator&CBA);boolwriteSectionContent(Elf_Shdr&SHeader,constELFYAML::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)unsignedgetDotSymTabSecNo()const{returnDoc.Sections.size()+1;}unsignedgetDotStrTabSecNo()const{returnDoc.Sections.size()+2;}unsignedgetDotShStrTabSecNo()const{returnDoc.Sections.size()+3;}unsignedgetSectionCount()const{returnDoc.Sections.size()+4;}ELFState(constELFYAML::Object&D):Doc(D){}public:staticintwriteELF(raw_ostream&OS,constELFYAML::Object&Doc);};}// end anonymous namespacetemplate<classELFT>voidELFState<ELFT>::initELFHeader(Elf_Ehdr&Header){usingnamespacellvm::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;boolIsLittleEndian=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<classELFT>boolELFState<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_ShdrSHeader;zero(SHeader);SHeaders.push_back(SHeader);for(constauto&Sec:Doc.Sections)DotShStrtab.add(Sec->Name);DotShStrtab.finalize(StringTableBuilder::ELF);for(constauto&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()){unsignedIndex;if(SN2I.lookup(Sec->Link,Index)){errs()<<"error: Unknown section referenced: '"<<Sec->Link<<"' at YAML section '"<<Sec->Name<<"'.\n";returnfalse;}SHeader.sh_link=Index;}if(autoS=dyn_cast<ELFYAML::RawContentSection>(Sec.get()))writeSectionContent(SHeader,*S,CBA);elseif(autoS=dyn_cast<ELFYAML::RelocationSection>(Sec.get())){if(S->Link.empty())// For relocation section set link to .symtab by default.SHeader.sh_link=getDotSymTabSecNo();unsignedIndex;if(SN2I.lookup(S->Info,Index)){errs()<<"error: Unknown section referenced: '"<<S->Info<<"' at YAML section '"<<S->Name<<"'.\n";returnfalse;}SHeader.sh_info=Index;if(!writeSectionContent(SHeader,*S,CBA))returnfalse;}elsellvm_unreachable("Unknown section type");SHeaders.push_back(SHeader);}returntrue;}template<classELFT>voidELFState<ELFT>::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<Elf_Sym>Syms;{// Ensure STN_UNDEF is presentElf_SymSym;zero(Sym);Syms.push_back(Sym);}// Add symbol names to .strtab.for(constauto&Sym:Doc.Symbols.Local)DotStrtab.add(Sym.Name);for(constauto&Sym:Doc.Symbols.Global)DotStrtab.add(Sym.Name);for(constauto&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<classELFT>voidELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr&SHeader,StringRefName,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<classELFT>voidELFState<ELFT>::addSymbols(conststd::vector<ELFYAML::Symbol>&Symbols,std::vector<Elf_Sym>&Syms,unsignedSymbolBinding){for(constauto&Sym:Symbols){Elf_SymSymbol;zero(Symbol);if(!Sym.Name.empty())Symbol.st_name=DotStrtab.getOffset(Sym.Name);Symbol.setBindingAndType(SymbolBinding,Sym.Type);if(!Sym.Section.empty()){unsignedIndex;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<classELFT>voidELFState<ELFT>::writeSectionContent(Elf_Shdr&SHeader,constELFYAML::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(autoi=Section.Content.binary_size();i<Section.Size;++i)OS.write(0);SHeader.sh_entsize=0;SHeader.sh_size=Section.Size;}template<classELFT>boolELFState<ELFT>::writeSectionContent(Elf_Shdr&SHeader,constELFYAML::RelocationSection&Section,ContiguousBlobAccumulator&CBA){if(Section.Type!=llvm::ELF::SHT_REL&&Section.Type!=llvm::ELF::SHT_RELA){errs()<<"error: Invalid relocation section type.\n";returnfalse;}boolIsRela=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(constauto&Rel:Section.Relocations){unsignedSymIdx;if(SymN2I.lookup(Rel.Symbol,SymIdx)){errs()<<"error: Unknown symbol referenced: '"<<Rel.Symbol<<"' at YAML relocation.\n";returnfalse;}if(IsRela){Elf_RelaREntry;zero(REntry);REntry.r_offset=Rel.Offset;REntry.r_addend=Rel.Addend;REntry.setSymbolAndType(SymIdx,Rel.Type);OS.write((constchar*)&REntry,sizeof(REntry));}else{Elf_RelREntry;zero(REntry);REntry.r_offset=Rel.Offset;REntry.setSymbolAndType(SymIdx,Rel.Type);OS.write((constchar*)&REntry,sizeof(REntry));}}returntrue;}template<classELFT>boolELFState<ELFT>::buildSectionIndex(){SN2I.addName(".symtab",getDotSymTabSecNo());SN2I.addName(".strtab",getDotStrTabSecNo());SN2I.addName(".shstrtab",getDotShStrTabSecNo());for(unsignedi=0,e=Doc.Sections.size();i!=e;++i){StringRefName=Doc.Sections[i]->Name;if(Name.empty())continue;// "+ 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";returnfalse;}}returntrue;}template<classELFT>boolELFState<ELFT>::buildSymbolIndex(std::size_t&StartIndex,conststd::vector<ELFYAML::Symbol>&Symbols){for(constauto&Sym:Symbols){++StartIndex;if(Sym.Name.empty())continue;if(SymN2I.addName(Sym.Name,StartIndex)){errs()<<"error: Repeated symbol name: '"<<Sym.Name<<"'.\n";returnfalse;}}returntrue;}template<classELFT>intELFState<ELFT>::writeELF(raw_ostream&OS,constELFYAML::Object&Doc){ELFState<ELFT>State(Doc);if(!State.buildSectionIndex())return1;std::size_tStartSymIndex=0;if(!State.buildSymbolIndex(StartSymIndex,Doc.Symbols.Local)||!State.buildSymbolIndex(StartSymIndex,Doc.Symbols.Global)||!State.buildSymbolIndex(StartSymIndex,Doc.Symbols.Weak))return1;Elf_EhdrHeader;State.initELFHeader(Header);// TODO: Flesh out section header support.// TODO: Program headers.// XXX: This offset is tightly coupled with the order that we write// things to `OS`.constsize_tSectionContentBeginOffset=Header.e_ehsize+Header.e_shentsize*Header.e_shnum;ContiguousBlobAccumulatorCBA(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<Elf_Shdr>SHeaders;if(!State.initSectionHeaders(SHeaders,CBA))return1;// .symtab section.Elf_ShdrSymtabSHeader;State.initSymtabSectionHeader(SymtabSHeader,CBA);SHeaders.push_back(SymtabSHeader);// .strtab string table header.Elf_ShdrDotStrTabSHeader;State.initStrtabSectionHeader(DotStrTabSHeader,".strtab",State.DotStrtab,CBA);SHeaders.push_back(DotStrTabSHeader);// .shstrtab string table header.Elf_ShdrShStrTabSHeader;State.initStrtabSectionHeader(ShStrTabSHeader,".shstrtab",State.DotShStrtab,CBA);SHeaders.push_back(ShStrTabSHeader);OS.write((constchar*)&Header,sizeof(Header));writeArrayData(OS,makeArrayRef(SHeaders));CBA.writeBlobToStream(OS);return0;}staticboolis64Bit(constELFYAML::Object&Doc){returnDoc.Header.Class==ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64);}staticboolisLittleEndian(constELFYAML::Object&Doc){returnDoc.Header.Data==ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB);}intyaml2elf(yaml::Input&YIn,raw_ostream&Out){ELFYAML::ObjectDoc;YIn>>Doc;if(YIn.error()){errs()<<"yaml2obj: Failed to parse YAML file!\n";return1;}usingobject::ELFType;typedefELFType<support::little,8,true>LE64;typedefELFType<support::big,8,true>BE64;typedefELFType<support::little,4,false>LE32;typedefELFType<support::big,4,false>BE32;if(is64Bit(Doc)){if(isLittleEndian(Doc))returnELFState<LE64>::writeELF(Out,Doc);elsereturnELFState<BE64>::writeELF(Out,Doc);}else{if(isLittleEndian(Doc))returnELFState<LE32>::writeELF(Out,Doc);elsereturnELFState<BE32>::writeELF(Out,Doc);}}