yaml2elf.cpp revision 552d7cd31a0f6eb0e1434981196f477ae741a184
1//===- yaml2elf - Convert YAML to a ELF object file -----------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief The ELF component of yaml2obj. 12/// 13//===----------------------------------------------------------------------===// 14 15#include "yaml2obj.h" 16#include "llvm/Object/ELF.h" 17#include "llvm/Object/ELFYAML.h" 18#include "llvm/Support/ELF.h" 19#include "llvm/Support/MemoryBuffer.h" 20#include "llvm/Support/YAMLTraits.h" 21#include "llvm/Support/raw_ostream.h" 22 23using namespace llvm; 24 25// There is similar code in yaml2coff, but with some slight COFF-specific 26// variations like different initial state. Might be able to deduplicate 27// some day, but also want to make sure that the Mach-O use case is served. 28// 29// This class has a deliberately small interface, since a lot of 30// implementation variation is possible. 31// 32// TODO: Use an ordered container with a suffix-based comparison in order 33// to deduplicate suffixes. std::map<> with a custom comparator is likely 34// to be the simplest implementation, but a suffix trie could be more 35// suitable for the job. 36namespace { 37class StringTableBuilder { 38 /// \brief Indices of strings currently present in `Buf`. 39 StringMap<unsigned> StringIndices; 40 /// \brief The contents of the string table as we build it. 41 std::string Buf; 42public: 43 StringTableBuilder() { 44 Buf.push_back('\0'); 45 } 46 /// \returns Index of string in string table. 47 unsigned addString(StringRef S) { 48 StringMapEntry<unsigned> &Entry = StringIndices.GetOrCreateValue(S); 49 unsigned &I = Entry.getValue(); 50 if (I != 0) 51 return I; 52 I = Buf.size(); 53 Buf.append(S.begin(), S.end()); 54 Buf.push_back('\0'); 55 return I; 56 } 57 size_t size() const { 58 return Buf.size(); 59 } 60 void writeToStream(raw_ostream &OS) { 61 OS.write(Buf.data(), Buf.size()); 62 } 63}; 64} // end anonymous namespace 65 66// This class is used to build up a contiguous binary blob while keeping 67// track of an offset in the output (which notionally begins at 68// `InitialOffset`). 69namespace { 70class ContiguousBlobAccumulator { 71 const uint64_t InitialOffset; 72 SmallVector<char, 128> Buf; 73 raw_svector_ostream OS; 74 75public: 76 ContiguousBlobAccumulator(uint64_t InitialOffset_) 77 : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} 78 raw_ostream &getOS() { return OS; } 79 uint64_t currentOffset() const { return InitialOffset + OS.tell(); } 80 void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } 81}; 82} // end anonymous namespace 83 84// Used to keep track of section names, so that in the YAML file sections 85// can be referenced by name instead of by index. 86namespace { 87class SectionNameToIdxMap { 88 StringMap<int> Map; 89public: 90 /// \returns true if name is already present in the map. 91 bool addName(StringRef SecName, unsigned i) { 92 StringMapEntry<int> &Entry = Map.GetOrCreateValue(SecName, -1); 93 if (Entry.getValue() != -1) 94 return true; 95 Entry.setValue((int)i); 96 return false; 97 } 98 /// \returns true if name is not present in the map 99 bool lookupSection(StringRef SecName, unsigned &Idx) const { 100 StringMap<int>::const_iterator I = Map.find(SecName); 101 if (I == Map.end()) 102 return true; 103 Idx = I->getValue(); 104 return false; 105 } 106}; 107} // end anonymous namespace 108 109template <class T> 110static size_t vectorDataSize(const std::vector<T> &Vec) { 111 return Vec.size() * sizeof(T); 112} 113 114template <class T> 115static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) { 116 OS.write((const char *)Vec.data(), vectorDataSize(Vec)); 117} 118 119template <class T> 120static void zero(T &Obj) { 121 memset(&Obj, 0, sizeof(Obj)); 122} 123 124/// \brief Create a string table in `SHeader`, which we assume is already 125/// zero'd. 126template <class Elf_Shdr> 127static void createStringTableSectionHeader(Elf_Shdr &SHeader, 128 StringTableBuilder &STB, 129 ContiguousBlobAccumulator &CBA) { 130 SHeader.sh_type = ELF::SHT_STRTAB; 131 SHeader.sh_offset = CBA.currentOffset(); 132 SHeader.sh_size = STB.size(); 133 STB.writeToStream(CBA.getOS()); 134 SHeader.sh_addralign = 1; 135} 136 137namespace { 138/// \brief "Single point of truth" for the ELF file construction. 139/// TODO: This class still has a ways to go before it is truly a "single 140/// point of truth". 141template <class ELFT> 142class ELFState { 143 /// \brief The future ".strtab" section. 144 StringTableBuilder DotStrtab; 145 /// \brief The section number of the ".strtab" section. 146 unsigned DotStrtabSecNo; 147 /// \brief The accumulated contents of all sections so far. 148 ContiguousBlobAccumulator &SectionContentAccum; 149 typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; 150 /// \brief The ELF file header. 151 Elf_Ehdr &Header; 152 153 SectionNameToIdxMap &SN2I; 154 155public: 156 157 ELFState(Elf_Ehdr &Header_, ContiguousBlobAccumulator &Accum, 158 unsigned DotStrtabSecNo_, SectionNameToIdxMap &SN2I_) 159 : DotStrtab(), DotStrtabSecNo(DotStrtabSecNo_), 160 SectionContentAccum(Accum), Header(Header_), SN2I(SN2I_) {} 161 162 unsigned getDotStrTabSecNo() const { return DotStrtabSecNo; } 163 StringTableBuilder &getStringTable() { return DotStrtab; } 164 ContiguousBlobAccumulator &getSectionContentAccum() { 165 return SectionContentAccum; 166 } 167 SectionNameToIdxMap &getSN2I() { return SN2I; } 168}; 169} // end anonymous namespace 170 171// FIXME: At this point it is fairly clear that we need to refactor these 172// static functions into methods of a class sharing some typedefs. These 173// ELF type names are insane. 174template <class ELFT> 175static void 176addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State, 177 std::vector<typename object::ELFObjectFile<ELFT>::Elf_Sym> &Syms, 178 unsigned SymbolBinding) { 179 typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; 180 for (unsigned i = 0, e = Symbols.size(); i != e; ++i) { 181 const ELFYAML::Symbol &Sym = Symbols[i]; 182 Elf_Sym Symbol; 183 zero(Symbol); 184 if (!Sym.Name.empty()) 185 Symbol.st_name = State.getStringTable().addString(Sym.Name); 186 Symbol.setBindingAndType(SymbolBinding, Sym.Type); 187 unsigned Index; 188 if (State.getSN2I().lookupSection(Sym.Section, Index)) { 189 errs() << "error: Unknown section referenced: '" << Sym.Section 190 << "' by YAML symbol " << Sym.Name << ".\n"; 191 exit(1); 192 } 193 Symbol.st_shndx = Index; 194 Symbol.st_value = Sym.Value; 195 Symbol.st_size = Sym.Size; 196 Syms.push_back(Symbol); 197 } 198} 199 200template <class ELFT> 201static void handleSymtabSectionHeader( 202 const ELFYAML::Section &Sec, ELFState<ELFT> &State, 203 typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) { 204 205 typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; 206 // TODO: Ensure that a manually specified `Link` field is diagnosed as an 207 // error for SHT_SYMTAB. 208 SHeader.sh_link = State.getDotStrTabSecNo(); 209 // One greater than symbol table index of the last local symbol. 210 SHeader.sh_info = Sec.Symbols.Local.size() + 1; 211 SHeader.sh_entsize = sizeof(Elf_Sym); 212 213 std::vector<Elf_Sym> Syms; 214 { 215 // Ensure STN_UNDEF is present 216 Elf_Sym Sym; 217 zero(Sym); 218 Syms.push_back(Sym); 219 } 220 addSymbols(Sec.Symbols.Local, State, Syms, ELF::STB_LOCAL); 221 addSymbols(Sec.Symbols.Global, State, Syms, ELF::STB_GLOBAL); 222 addSymbols(Sec.Symbols.Weak, State, Syms, ELF::STB_WEAK); 223 224 ContiguousBlobAccumulator &CBA = State.getSectionContentAccum(); 225 SHeader.sh_offset = CBA.currentOffset(); 226 SHeader.sh_size = vectorDataSize(Syms); 227 writeVectorData(CBA.getOS(), Syms); 228} 229 230template <class ELFT> 231static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { 232 using namespace llvm::ELF; 233 typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; 234 typedef typename object::ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; 235 236 const ELFYAML::FileHeader &Hdr = Doc.Header; 237 238 Elf_Ehdr Header; 239 zero(Header); 240 Header.e_ident[EI_MAG0] = 0x7f; 241 Header.e_ident[EI_MAG1] = 'E'; 242 Header.e_ident[EI_MAG2] = 'L'; 243 Header.e_ident[EI_MAG3] = 'F'; 244 Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; 245 bool IsLittleEndian = ELFT::TargetEndianness == support::little; 246 Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; 247 Header.e_ident[EI_VERSION] = EV_CURRENT; 248 Header.e_ident[EI_OSABI] = Hdr.OSABI; 249 Header.e_ident[EI_ABIVERSION] = 0; 250 Header.e_type = Hdr.Type; 251 Header.e_machine = Hdr.Machine; 252 Header.e_version = EV_CURRENT; 253 Header.e_entry = Hdr.Entry; 254 Header.e_ehsize = sizeof(Elf_Ehdr); 255 256 // TODO: Flesh out section header support. 257 // TODO: Program headers. 258 259 Header.e_shentsize = sizeof(Elf_Shdr); 260 // Immediately following the ELF header. 261 Header.e_shoff = sizeof(Header); 262 const std::vector<ELFYAML::Section> &Sections = Doc.Sections; 263 // "+ 3" for 264 // - SHT_NULL entry (placed first, i.e. 0'th entry) 265 // - string table (.strtab) (placed second to last) 266 // - section header string table. (placed last) 267 Header.e_shnum = Sections.size() + 3; 268 // Place section header string table last. 269 Header.e_shstrndx = Header.e_shnum - 1; 270 const unsigned DotStrtabSecNo = Header.e_shnum - 2; 271 272 // XXX: This offset is tightly coupled with the order that we write 273 // things to `OS`. 274 const size_t SectionContentBeginOffset = 275 Header.e_ehsize + Header.e_shentsize * Header.e_shnum; 276 ContiguousBlobAccumulator CBA(SectionContentBeginOffset); 277 SectionNameToIdxMap SN2I; 278 for (unsigned i = 0, e = Sections.size(); i != e; ++i) { 279 StringRef Name = Sections[i].Name; 280 if (Name.empty()) 281 continue; 282 // "+ 1" to take into account the SHT_NULL entry. 283 if (SN2I.addName(Name, i + 1)) { 284 errs() << "error: Repeated section name: '" << Name 285 << "' at YAML section number " << i << ".\n"; 286 return 1; 287 } 288 } 289 290 ELFState<ELFT> State(Header, CBA, DotStrtabSecNo, SN2I); 291 292 StringTableBuilder SHStrTab; 293 std::vector<Elf_Shdr> SHeaders; 294 { 295 // Ensure SHN_UNDEF entry is present. An all-zero section header is a 296 // valid SHN_UNDEF entry since SHT_NULL == 0. 297 Elf_Shdr SHdr; 298 zero(SHdr); 299 SHeaders.push_back(SHdr); 300 } 301 for (unsigned i = 0, e = Sections.size(); i != e; ++i) { 302 const ELFYAML::Section &Sec = Sections[i]; 303 Elf_Shdr SHeader; 304 zero(SHeader); 305 SHeader.sh_name = SHStrTab.addString(Sec.Name); 306 SHeader.sh_type = Sec.Type; 307 SHeader.sh_flags = Sec.Flags; 308 SHeader.sh_addr = Sec.Address; 309 310 SHeader.sh_offset = CBA.currentOffset(); 311 SHeader.sh_size = Sec.Content.binary_size(); 312 Sec.Content.writeAsBinary(CBA.getOS()); 313 314 if (!Sec.Link.empty()) { 315 unsigned Index; 316 if (SN2I.lookupSection(Sec.Link, Index)) { 317 errs() << "error: Unknown section referenced: '" << Sec.Link 318 << "' at YAML section number " << i << ".\n"; 319 return 1; 320 } 321 SHeader.sh_link = Index; 322 } 323 SHeader.sh_info = 0; 324 SHeader.sh_addralign = Sec.AddressAlign; 325 SHeader.sh_entsize = 0; 326 // XXX: Really ugly right now. Should not be writing to `CBA` above 327 // (and setting sh_offset and sh_size) when going through this branch 328 // here. 329 if (Sec.Type == ELFYAML::ELF_SHT(SHT_SYMTAB)) 330 handleSymtabSectionHeader<ELFT>(Sec, State, SHeader); 331 SHeaders.push_back(SHeader); 332 } 333 334 // .strtab string table header. 335 Elf_Shdr DotStrTabSHeader; 336 zero(DotStrTabSHeader); 337 DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab")); 338 createStringTableSectionHeader(DotStrTabSHeader, State.getStringTable(), CBA); 339 340 // Section header string table header. 341 Elf_Shdr SHStrTabSHeader; 342 zero(SHStrTabSHeader); 343 createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA); 344 345 OS.write((const char *)&Header, sizeof(Header)); 346 writeVectorData(OS, SHeaders); 347 OS.write((const char *)&DotStrTabSHeader, sizeof(DotStrTabSHeader)); 348 OS.write((const char *)&SHStrTabSHeader, sizeof(SHStrTabSHeader)); 349 CBA.writeBlobToStream(OS); 350 return 0; 351} 352 353int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { 354 yaml::Input YIn(Buf->getBuffer()); 355 ELFYAML::Object Doc; 356 YIn >> Doc; 357 if (YIn.error()) { 358 errs() << "yaml2obj: Failed to parse YAML file!\n"; 359 return 1; 360 } 361 if (Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) { 362 if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) 363 return writeELF<object::ELFType<support::little, 8, true> >(outs(), Doc); 364 else 365 return writeELF<object::ELFType<support::big, 8, true> >(outs(), Doc); 366 } else { 367 if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) 368 return writeELF<object::ELFType<support::little, 4, false> >(outs(), Doc); 369 else 370 return writeELF<object::ELFType<support::big, 4, false> >(outs(), Doc); 371 } 372} 373