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