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/ADT/ArrayRef.h" 17#include "llvm/MC/StringTableBuilder.h" 18#include "llvm/Object/ELFObjectFile.h" 19#include "llvm/Object/ELFYAML.h" 20#include "llvm/Support/ELF.h" 21#include "llvm/Support/MemoryBuffer.h" 22#include "llvm/Support/YAMLTraits.h" 23#include "llvm/Support/raw_ostream.h" 24 25using namespace llvm; 26 27// This class is used to build up a contiguous binary blob while keeping 28// track of an offset in the output (which notionally begins at 29// `InitialOffset`). 30namespace { 31class ContiguousBlobAccumulator { 32 const uint64_t InitialOffset; 33 SmallVector<char, 128> Buf; 34 raw_svector_ostream OS; 35 36 /// \returns The new offset. 37 uint64_t padToAlignment(unsigned Align) { 38 uint64_t CurrentOffset = InitialOffset + OS.tell(); 39 uint64_t AlignedOffset = RoundUpToAlignment(CurrentOffset, Align); 40 for (; CurrentOffset != AlignedOffset; ++CurrentOffset) 41 OS.write('\0'); 42 return AlignedOffset; // == CurrentOffset; 43 } 44 45public: 46 ContiguousBlobAccumulator(uint64_t InitialOffset_) 47 : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} 48 template <class Integer> 49 raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align = 16) { 50 Offset = padToAlignment(Align); 51 return OS; 52 } 53 void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } 54}; 55} // end anonymous namespace 56 57// Used to keep track of section and symbol names, so that in the YAML file 58// sections and symbols can be referenced by name instead of by index. 59namespace { 60class NameToIdxMap { 61 StringMap<int> Map; 62public: 63 /// \returns true if name is already present in the map. 64 bool addName(StringRef Name, unsigned i) { 65 return !Map.insert(std::make_pair(Name, (int)i)).second; 66 } 67 /// \returns true if name is not present in the map 68 bool lookup(StringRef Name, unsigned &Idx) const { 69 StringMap<int>::const_iterator I = Map.find(Name); 70 if (I == Map.end()) 71 return true; 72 Idx = I->getValue(); 73 return false; 74 } 75}; 76} // end anonymous namespace 77 78template <class T> 79static size_t arrayDataSize(ArrayRef<T> A) { 80 return A.size() * sizeof(T); 81} 82 83template <class T> 84static void writeArrayData(raw_ostream &OS, ArrayRef<T> A) { 85 OS.write((const char *)A.data(), arrayDataSize(A)); 86} 87 88template <class T> 89static void zero(T &Obj) { 90 memset(&Obj, 0, sizeof(Obj)); 91} 92 93namespace { 94/// \brief "Single point of truth" for the ELF file construction. 95/// TODO: This class still has a ways to go before it is truly a "single 96/// point of truth". 97template <class ELFT> 98class ELFState { 99 typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; 100 typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; 101 typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; 102 typedef typename object::ELFFile<ELFT>::Elf_Rel Elf_Rel; 103 typedef typename object::ELFFile<ELFT>::Elf_Rela Elf_Rela; 104 105 /// \brief The future ".strtab" section. 106 StringTableBuilder DotStrtab; 107 108 /// \brief The future ".shstrtab" section. 109 StringTableBuilder DotShStrtab; 110 111 NameToIdxMap SN2I; 112 NameToIdxMap SymN2I; 113 const ELFYAML::Object &Doc; 114 115 bool buildSectionIndex(); 116 bool buildSymbolIndex(std::size_t &StartIndex, 117 const std::vector<ELFYAML::Symbol> &Symbols); 118 void initELFHeader(Elf_Ehdr &Header); 119 bool initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, 120 ContiguousBlobAccumulator &CBA); 121 void initSymtabSectionHeader(Elf_Shdr &SHeader, 122 ContiguousBlobAccumulator &CBA); 123 void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, 124 StringTableBuilder &STB, 125 ContiguousBlobAccumulator &CBA); 126 void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, 127 std::vector<Elf_Sym> &Syms, unsigned SymbolBinding); 128 void writeSectionContent(Elf_Shdr &SHeader, 129 const ELFYAML::RawContentSection &Section, 130 ContiguousBlobAccumulator &CBA); 131 bool writeSectionContent(Elf_Shdr &SHeader, 132 const ELFYAML::RelocationSection &Section, 133 ContiguousBlobAccumulator &CBA); 134 bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, 135 ContiguousBlobAccumulator &CBA); 136 137 // - SHT_NULL entry (placed first, i.e. 0'th entry) 138 // - symbol table (.symtab) (placed third to last) 139 // - string table (.strtab) (placed second to last) 140 // - section header string table (.shstrtab) (placed last) 141 unsigned getDotSymTabSecNo() const { return Doc.Sections.size() + 1; } 142 unsigned getDotStrTabSecNo() const { return Doc.Sections.size() + 2; } 143 unsigned getDotShStrTabSecNo() const { return Doc.Sections.size() + 3; } 144 unsigned getSectionCount() const { return Doc.Sections.size() + 4; } 145 146 ELFState(const ELFYAML::Object &D) : Doc(D) {} 147 148public: 149 static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc); 150}; 151} // end anonymous namespace 152 153template <class ELFT> 154void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) { 155 using namespace llvm::ELF; 156 zero(Header); 157 Header.e_ident[EI_MAG0] = 0x7f; 158 Header.e_ident[EI_MAG1] = 'E'; 159 Header.e_ident[EI_MAG2] = 'L'; 160 Header.e_ident[EI_MAG3] = 'F'; 161 Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; 162 bool IsLittleEndian = ELFT::TargetEndianness == support::little; 163 Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; 164 Header.e_ident[EI_VERSION] = EV_CURRENT; 165 Header.e_ident[EI_OSABI] = Doc.Header.OSABI; 166 Header.e_ident[EI_ABIVERSION] = 0; 167 Header.e_type = Doc.Header.Type; 168 Header.e_machine = Doc.Header.Machine; 169 Header.e_version = EV_CURRENT; 170 Header.e_entry = Doc.Header.Entry; 171 Header.e_flags = Doc.Header.Flags; 172 Header.e_ehsize = sizeof(Elf_Ehdr); 173 Header.e_shentsize = sizeof(Elf_Shdr); 174 // Immediately following the ELF header. 175 Header.e_shoff = sizeof(Header); 176 Header.e_shnum = getSectionCount(); 177 Header.e_shstrndx = getDotShStrTabSecNo(); 178} 179 180template <class ELFT> 181bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, 182 ContiguousBlobAccumulator &CBA) { 183 // Ensure SHN_UNDEF entry is present. An all-zero section header is a 184 // valid SHN_UNDEF entry since SHT_NULL == 0. 185 Elf_Shdr SHeader; 186 zero(SHeader); 187 SHeaders.push_back(SHeader); 188 189 for (const auto &Sec : Doc.Sections) 190 DotShStrtab.add(Sec->Name); 191 DotShStrtab.finalize(StringTableBuilder::ELF); 192 193 for (const auto &Sec : Doc.Sections) { 194 zero(SHeader); 195 SHeader.sh_name = DotShStrtab.getOffset(Sec->Name); 196 SHeader.sh_type = Sec->Type; 197 SHeader.sh_flags = Sec->Flags; 198 SHeader.sh_addr = Sec->Address; 199 SHeader.sh_addralign = Sec->AddressAlign; 200 201 if (!Sec->Link.empty()) { 202 unsigned Index; 203 if (SN2I.lookup(Sec->Link, Index)) { 204 errs() << "error: Unknown section referenced: '" << Sec->Link 205 << "' at YAML section '" << Sec->Name << "'.\n"; 206 return false; 207 } 208 SHeader.sh_link = Index; 209 } 210 211 if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec.get())) 212 writeSectionContent(SHeader, *S, CBA); 213 else if (auto S = dyn_cast<ELFYAML::RelocationSection>(Sec.get())) { 214 if (S->Link.empty()) 215 // For relocation section set link to .symtab by default. 216 SHeader.sh_link = getDotSymTabSecNo(); 217 218 unsigned Index; 219 if (SN2I.lookup(S->Info, Index)) { 220 errs() << "error: Unknown section referenced: '" << S->Info 221 << "' at YAML section '" << S->Name << "'.\n"; 222 return false; 223 } 224 SHeader.sh_info = Index; 225 226 if (!writeSectionContent(SHeader, *S, CBA)) 227 return false; 228 } else if (auto S = dyn_cast<ELFYAML::Group>(Sec.get())) { 229 unsigned SymIdx; 230 if (SymN2I.lookup(S->Info, SymIdx)) { 231 errs() << "error: Unknown symbol referenced: '" << S->Info 232 << "' at YAML section '" << S->Name << "'.\n"; 233 return false; 234 } 235 SHeader.sh_info = SymIdx; 236 if (!writeSectionContent(SHeader, *S, CBA)) 237 return false; 238 } else 239 llvm_unreachable("Unknown section type"); 240 241 SHeaders.push_back(SHeader); 242 } 243 return true; 244} 245 246template <class ELFT> 247void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader, 248 ContiguousBlobAccumulator &CBA) { 249 zero(SHeader); 250 SHeader.sh_name = DotShStrtab.getOffset(".symtab"); 251 SHeader.sh_type = ELF::SHT_SYMTAB; 252 SHeader.sh_link = getDotStrTabSecNo(); 253 // One greater than symbol table index of the last local symbol. 254 SHeader.sh_info = Doc.Symbols.Local.size() + 1; 255 SHeader.sh_entsize = sizeof(Elf_Sym); 256 257 std::vector<Elf_Sym> Syms; 258 { 259 // Ensure STN_UNDEF is present 260 Elf_Sym Sym; 261 zero(Sym); 262 Syms.push_back(Sym); 263 } 264 265 // Add symbol names to .strtab. 266 for (const auto &Sym : Doc.Symbols.Local) 267 DotStrtab.add(Sym.Name); 268 for (const auto &Sym : Doc.Symbols.Global) 269 DotStrtab.add(Sym.Name); 270 for (const auto &Sym : Doc.Symbols.Weak) 271 DotStrtab.add(Sym.Name); 272 DotStrtab.finalize(StringTableBuilder::ELF); 273 274 addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL); 275 addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL); 276 addSymbols(Doc.Symbols.Weak, Syms, ELF::STB_WEAK); 277 278 writeArrayData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), 279 makeArrayRef(Syms)); 280 SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); 281} 282 283template <class ELFT> 284void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, 285 StringTableBuilder &STB, 286 ContiguousBlobAccumulator &CBA) { 287 zero(SHeader); 288 SHeader.sh_name = DotShStrtab.getOffset(Name); 289 SHeader.sh_type = ELF::SHT_STRTAB; 290 CBA.getOSAndAlignedOffset(SHeader.sh_offset) << STB.data(); 291 SHeader.sh_size = STB.data().size(); 292 SHeader.sh_addralign = 1; 293} 294 295template <class ELFT> 296void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, 297 std::vector<Elf_Sym> &Syms, 298 unsigned SymbolBinding) { 299 for (const auto &Sym : Symbols) { 300 Elf_Sym Symbol; 301 zero(Symbol); 302 if (!Sym.Name.empty()) 303 Symbol.st_name = DotStrtab.getOffset(Sym.Name); 304 Symbol.setBindingAndType(SymbolBinding, Sym.Type); 305 if (!Sym.Section.empty()) { 306 unsigned Index; 307 if (SN2I.lookup(Sym.Section, Index)) { 308 errs() << "error: Unknown section referenced: '" << Sym.Section 309 << "' by YAML symbol " << Sym.Name << ".\n"; 310 exit(1); 311 } 312 Symbol.st_shndx = Index; 313 } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. 314 Symbol.st_value = Sym.Value; 315 Symbol.st_other = Sym.Other; 316 Symbol.st_size = Sym.Size; 317 Syms.push_back(Symbol); 318 } 319} 320 321template <class ELFT> 322void 323ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader, 324 const ELFYAML::RawContentSection &Section, 325 ContiguousBlobAccumulator &CBA) { 326 assert(Section.Size >= Section.Content.binary_size() && 327 "Section size and section content are inconsistent"); 328 raw_ostream &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); 329 Section.Content.writeAsBinary(OS); 330 for (auto i = Section.Content.binary_size(); i < Section.Size; ++i) 331 OS.write(0); 332 SHeader.sh_entsize = 0; 333 SHeader.sh_size = Section.Size; 334} 335 336static bool isMips64EL(const ELFYAML::Object &Doc) { 337 return Doc.Header.Machine == ELFYAML::ELF_EM(llvm::ELF::EM_MIPS) && 338 Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64) && 339 Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); 340} 341 342template <class ELFT> 343bool 344ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader, 345 const ELFYAML::RelocationSection &Section, 346 ContiguousBlobAccumulator &CBA) { 347 if (Section.Type != llvm::ELF::SHT_REL && 348 Section.Type != llvm::ELF::SHT_RELA) { 349 errs() << "error: Invalid relocation section type.\n"; 350 return false; 351 } 352 353 bool IsRela = Section.Type == llvm::ELF::SHT_RELA; 354 SHeader.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); 355 SHeader.sh_size = SHeader.sh_entsize * Section.Relocations.size(); 356 357 auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); 358 359 for (const auto &Rel : Section.Relocations) { 360 unsigned SymIdx; 361 if (SymN2I.lookup(Rel.Symbol, SymIdx)) { 362 errs() << "error: Unknown symbol referenced: '" << Rel.Symbol 363 << "' at YAML relocation.\n"; 364 return false; 365 } 366 367 if (IsRela) { 368 Elf_Rela REntry; 369 zero(REntry); 370 REntry.r_offset = Rel.Offset; 371 REntry.r_addend = Rel.Addend; 372 REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); 373 OS.write((const char *)&REntry, sizeof(REntry)); 374 } else { 375 Elf_Rel REntry; 376 zero(REntry); 377 REntry.r_offset = Rel.Offset; 378 REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); 379 OS.write((const char *)&REntry, sizeof(REntry)); 380 } 381 } 382 return true; 383} 384 385template <class ELFT> 386bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader, 387 const ELFYAML::Group &Section, 388 ContiguousBlobAccumulator &CBA) { 389 typedef typename object::ELFFile<ELFT>::Elf_Word Elf_Word; 390 if (Section.Type != llvm::ELF::SHT_GROUP) { 391 errs() << "error: Invalid section type.\n"; 392 return false; 393 } 394 395 SHeader.sh_entsize = sizeof(Elf_Word); 396 SHeader.sh_size = SHeader.sh_entsize * Section.Members.size(); 397 398 auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); 399 400 for (auto member : Section.Members) { 401 Elf_Word SIdx; 402 unsigned int sectionIndex = 0; 403 if (member.sectionNameOrType == "GRP_COMDAT") 404 sectionIndex = llvm::ELF::GRP_COMDAT; 405 else if (SN2I.lookup(member.sectionNameOrType, sectionIndex)) { 406 errs() << "error: Unknown section referenced: '" 407 << member.sectionNameOrType << "' at YAML section' " 408 << Section.Name << "\n"; 409 return false; 410 } 411 SIdx = sectionIndex; 412 OS.write((const char *)&SIdx, sizeof(SIdx)); 413 } 414 return true; 415} 416 417template <class ELFT> bool ELFState<ELFT>::buildSectionIndex() { 418 SN2I.addName(".symtab", getDotSymTabSecNo()); 419 SN2I.addName(".strtab", getDotStrTabSecNo()); 420 SN2I.addName(".shstrtab", getDotShStrTabSecNo()); 421 422 for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { 423 StringRef Name = Doc.Sections[i]->Name; 424 if (Name.empty()) 425 continue; 426 // "+ 1" to take into account the SHT_NULL entry. 427 if (SN2I.addName(Name, i + 1)) { 428 errs() << "error: Repeated section name: '" << Name 429 << "' at YAML section number " << i << ".\n"; 430 return false; 431 } 432 } 433 return true; 434} 435 436template <class ELFT> 437bool 438ELFState<ELFT>::buildSymbolIndex(std::size_t &StartIndex, 439 const std::vector<ELFYAML::Symbol> &Symbols) { 440 for (const auto &Sym : Symbols) { 441 ++StartIndex; 442 if (Sym.Name.empty()) 443 continue; 444 if (SymN2I.addName(Sym.Name, StartIndex)) { 445 errs() << "error: Repeated symbol name: '" << Sym.Name << "'.\n"; 446 return false; 447 } 448 } 449 return true; 450} 451 452template <class ELFT> 453int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { 454 ELFState<ELFT> State(Doc); 455 if (!State.buildSectionIndex()) 456 return 1; 457 458 std::size_t StartSymIndex = 0; 459 if (!State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Local) || 460 !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Global) || 461 !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Weak)) 462 return 1; 463 464 Elf_Ehdr Header; 465 State.initELFHeader(Header); 466 467 // TODO: Flesh out section header support. 468 // TODO: Program headers. 469 470 // XXX: This offset is tightly coupled with the order that we write 471 // things to `OS`. 472 const size_t SectionContentBeginOffset = 473 Header.e_ehsize + Header.e_shentsize * Header.e_shnum; 474 ContiguousBlobAccumulator CBA(SectionContentBeginOffset); 475 476 // Doc might not contain .symtab, .strtab and .shstrtab sections, 477 // but we will emit them, so make sure to add them to ShStrTabSHeader. 478 State.DotShStrtab.add(".symtab"); 479 State.DotShStrtab.add(".strtab"); 480 State.DotShStrtab.add(".shstrtab"); 481 482 std::vector<Elf_Shdr> SHeaders; 483 if(!State.initSectionHeaders(SHeaders, CBA)) 484 return 1; 485 486 // .symtab section. 487 Elf_Shdr SymtabSHeader; 488 State.initSymtabSectionHeader(SymtabSHeader, CBA); 489 SHeaders.push_back(SymtabSHeader); 490 491 // .strtab string table header. 492 Elf_Shdr DotStrTabSHeader; 493 State.initStrtabSectionHeader(DotStrTabSHeader, ".strtab", State.DotStrtab, 494 CBA); 495 SHeaders.push_back(DotStrTabSHeader); 496 497 // .shstrtab string table header. 498 Elf_Shdr ShStrTabSHeader; 499 State.initStrtabSectionHeader(ShStrTabSHeader, ".shstrtab", State.DotShStrtab, 500 CBA); 501 SHeaders.push_back(ShStrTabSHeader); 502 503 OS.write((const char *)&Header, sizeof(Header)); 504 writeArrayData(OS, makeArrayRef(SHeaders)); 505 CBA.writeBlobToStream(OS); 506 return 0; 507} 508 509static bool is64Bit(const ELFYAML::Object &Doc) { 510 return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); 511} 512 513static bool isLittleEndian(const ELFYAML::Object &Doc) { 514 return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); 515} 516 517int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { 518 ELFYAML::Object Doc; 519 YIn >> Doc; 520 if (YIn.error()) { 521 errs() << "yaml2obj: Failed to parse YAML file!\n"; 522 return 1; 523 } 524 using object::ELFType; 525 typedef ELFType<support::little, 8, true> LE64; 526 typedef ELFType<support::big, 8, true> BE64; 527 typedef ELFType<support::little, 4, false> LE32; 528 typedef ELFType<support::big, 4, false> BE32; 529 if (is64Bit(Doc)) { 530 if (isLittleEndian(Doc)) 531 return ELFState<LE64>::writeELF(Out, Doc); 532 else 533 return ELFState<BE64>::writeELF(Out, Doc); 534 } else { 535 if (isLittleEndian(Doc)) 536 return ELFState<LE32>::writeELF(Out, Doc); 537 else 538 return ELFState<BE32>::writeELF(Out, Doc); 539 } 540} 541