1 //===- ELFObjHandler.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===-----------------------------------------------------------------------===/ 8 9 #include "llvm/InterfaceStub/ELFObjHandler.h" 10 #include "llvm/InterfaceStub/ELFStub.h" 11 #include "llvm/MC/StringTableBuilder.h" 12 #include "llvm/Object/Binary.h" 13 #include "llvm/Object/ELFObjectFile.h" 14 #include "llvm/Object/ELFTypes.h" 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/Error.h" 17 #include "llvm/Support/FileOutputBuffer.h" 18 #include "llvm/Support/MathExtras.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 21 using llvm::MemoryBufferRef; 22 using llvm::object::ELFObjectFile; 23 24 using namespace llvm; 25 using namespace llvm::object; 26 using namespace llvm::ELF; 27 28 namespace llvm { 29 namespace elfabi { 30 31 // Simple struct to hold relevant .dynamic entries. 32 struct DynamicEntries { 33 uint64_t StrTabAddr = 0; 34 uint64_t StrSize = 0; 35 Optional<uint64_t> SONameOffset; 36 std::vector<uint64_t> NeededLibNames; 37 // Symbol table: 38 uint64_t DynSymAddr = 0; 39 // Hash tables: 40 Optional<uint64_t> ElfHash; 41 Optional<uint64_t> GnuHash; 42 }; 43 44 /// This initializes an ELF file header with information specific to a binary 45 /// dynamic shared object. 46 /// Offsets, indexes, links, etc. for section and program headers are just 47 /// zero-initialized as they will be updated elsewhere. 48 /// 49 /// @param ElfHeader Target ELFT::Ehdr to populate. 50 /// @param Machine Target architecture (e_machine from ELF specifications). 51 template <class ELFT> 52 static void initELFHeader(typename ELFT::Ehdr &ElfHeader, uint16_t Machine) { 53 memset(&ElfHeader, 0, sizeof(ElfHeader)); 54 // ELF identification. 55 ElfHeader.e_ident[EI_MAG0] = ElfMagic[EI_MAG0]; 56 ElfHeader.e_ident[EI_MAG1] = ElfMagic[EI_MAG1]; 57 ElfHeader.e_ident[EI_MAG2] = ElfMagic[EI_MAG2]; 58 ElfHeader.e_ident[EI_MAG3] = ElfMagic[EI_MAG3]; 59 ElfHeader.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; 60 bool IsLittleEndian = ELFT::TargetEndianness == support::little; 61 ElfHeader.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; 62 ElfHeader.e_ident[EI_VERSION] = EV_CURRENT; 63 ElfHeader.e_ident[EI_OSABI] = ELFOSABI_NONE; 64 65 // Remainder of ELF header. 66 ElfHeader.e_type = ET_DYN; 67 ElfHeader.e_machine = Machine; 68 ElfHeader.e_version = EV_CURRENT; 69 ElfHeader.e_ehsize = sizeof(typename ELFT::Ehdr); 70 ElfHeader.e_phentsize = sizeof(typename ELFT::Phdr); 71 ElfHeader.e_shentsize = sizeof(typename ELFT::Shdr); 72 } 73 74 namespace { 75 template <class ELFT> struct OutputSection { 76 using Elf_Shdr = typename ELFT::Shdr; 77 std::string Name; 78 Elf_Shdr Shdr; 79 uint64_t Addr; 80 uint64_t Offset; 81 uint64_t Size; 82 uint64_t Align; 83 uint32_t Index; 84 bool NoBits = true; 85 }; 86 87 template <class T, class ELFT> 88 struct ContentSection : public OutputSection<ELFT> { 89 T Content; 90 ContentSection() { this->NoBits = false; } 91 }; 92 93 // This class just wraps StringTableBuilder for the purpose of adding a 94 // default constructor. 95 class ELFStringTableBuilder : public StringTableBuilder { 96 public: 97 ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {} 98 }; 99 100 template <class ELFT> class ELFSymbolTableBuilder { 101 public: 102 using Elf_Sym = typename ELFT::Sym; 103 104 ELFSymbolTableBuilder() { Symbols.push_back({}); } 105 106 void add(size_t StNameOffset, uint64_t StSize, uint8_t StBind, uint8_t StType, 107 uint8_t StOther, uint16_t StShndx) { 108 Elf_Sym S{}; 109 S.st_name = StNameOffset; 110 S.st_size = StSize; 111 S.st_info = (StBind << 4) | (StType & 0xf); 112 S.st_other = StOther; 113 S.st_shndx = StShndx; 114 Symbols.push_back(S); 115 } 116 117 size_t getSize() const { return Symbols.size() * sizeof(Elf_Sym); } 118 119 void write(uint8_t *Buf) const { 120 memcpy(Buf, Symbols.data(), sizeof(Elf_Sym) * Symbols.size()); 121 } 122 123 private: 124 llvm::SmallVector<Elf_Sym, 8> Symbols; 125 }; 126 127 template <class ELFT> class ELFDynamicTableBuilder { 128 public: 129 using Elf_Dyn = typename ELFT::Dyn; 130 131 size_t addAddr(uint64_t Tag, uint64_t Addr) { 132 Elf_Dyn Entry; 133 Entry.d_tag = Tag; 134 Entry.d_un.d_ptr = Addr; 135 Entries.push_back(Entry); 136 return Entries.size() - 1; 137 } 138 139 void modifyAddr(size_t Index, uint64_t Addr) { 140 Entries[Index].d_un.d_ptr = Addr; 141 } 142 143 size_t addValue(uint64_t Tag, uint64_t Value) { 144 Elf_Dyn Entry; 145 Entry.d_tag = Tag; 146 Entry.d_un.d_val = Value; 147 Entries.push_back(Entry); 148 return Entries.size() - 1; 149 } 150 151 void modifyValue(size_t Index, uint64_t Value) { 152 Entries[Index].d_un.d_val = Value; 153 } 154 155 size_t getSize() const { 156 // Add DT_NULL entry at the end. 157 return (Entries.size() + 1) * sizeof(Elf_Dyn); 158 } 159 160 void write(uint8_t *Buf) const { 161 memcpy(Buf, Entries.data(), sizeof(Elf_Dyn) * Entries.size()); 162 // Add DT_NULL entry at the end. 163 memset(Buf + sizeof(Elf_Dyn) * Entries.size(), 0, sizeof(Elf_Dyn)); 164 } 165 166 private: 167 llvm::SmallVector<Elf_Dyn, 8> Entries; 168 }; 169 170 template <class ELFT> class ELFStubBuilder { 171 public: 172 using Elf_Ehdr = typename ELFT::Ehdr; 173 using Elf_Shdr = typename ELFT::Shdr; 174 using Elf_Phdr = typename ELFT::Phdr; 175 using Elf_Sym = typename ELFT::Sym; 176 using Elf_Addr = typename ELFT::Addr; 177 using Elf_Dyn = typename ELFT::Dyn; 178 179 ELFStubBuilder(const ELFStubBuilder &) = delete; 180 ELFStubBuilder(ELFStubBuilder &&) = default; 181 182 explicit ELFStubBuilder(const ELFStub &Stub) { 183 DynSym.Name = ".dynsym"; 184 DynSym.Align = sizeof(Elf_Addr); 185 DynStr.Name = ".dynstr"; 186 DynStr.Align = 1; 187 DynTab.Name = ".dynamic"; 188 DynTab.Align = sizeof(Elf_Addr); 189 ShStrTab.Name = ".shstrtab"; 190 ShStrTab.Align = 1; 191 192 // Populate string tables. 193 for (const ELFSymbol &Sym : Stub.Symbols) 194 DynStr.Content.add(Sym.Name); 195 for (const std::string &Lib : Stub.NeededLibs) 196 DynStr.Content.add(Lib); 197 if (Stub.SoName) 198 DynStr.Content.add(Stub.SoName.getValue()); 199 200 std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab, 201 &ShStrTab}; 202 const OutputSection<ELFT> *LastSection = Sections.back(); 203 // Now set the Index and put sections names into ".shstrtab". 204 uint64_t Index = 1; 205 for (OutputSection<ELFT> *Sec : Sections) { 206 Sec->Index = Index++; 207 ShStrTab.Content.add(Sec->Name); 208 } 209 ShStrTab.Content.finalize(); 210 ShStrTab.Size = ShStrTab.Content.getSize(); 211 DynStr.Content.finalize(); 212 DynStr.Size = DynStr.Content.getSize(); 213 214 // Populate dynamic symbol table. 215 for (const ELFSymbol &Sym : Stub.Symbols) { 216 uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL; 217 // For non-undefined symbols, value of the shndx is not relevant at link 218 // time as long as it is not SHN_UNDEF. Set shndx to 1, which 219 // points to ".dynsym". 220 uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1; 221 DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Sym.Size, Bind, 222 (uint8_t)Sym.Type, 0, Shndx); 223 } 224 DynSym.Size = DynSym.Content.getSize(); 225 226 // Poplulate dynamic table. 227 size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0); 228 size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0); 229 for (const std::string &Lib : Stub.NeededLibs) 230 DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib)); 231 if (Stub.SoName) 232 DynTab.Content.addValue(DT_SONAME, 233 DynStr.Content.getOffset(Stub.SoName.getValue())); 234 DynTab.Size = DynTab.Content.getSize(); 235 // Calculate sections' addresses and offsets. 236 uint64_t CurrentOffset = sizeof(Elf_Ehdr); 237 for (OutputSection<ELFT> *Sec : Sections) { 238 Sec->Offset = alignTo(CurrentOffset, Sec->Align); 239 Sec->Addr = Sec->Offset; 240 CurrentOffset = Sec->Offset + Sec->Size; 241 } 242 // Fill Addr back to dynamic table. 243 DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr); 244 DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr); 245 // Write section headers of string tables. 246 fillSymTabShdr(DynSym, SHT_DYNSYM); 247 fillStrTabShdr(DynStr, SHF_ALLOC); 248 fillDynTabShdr(DynTab); 249 fillStrTabShdr(ShStrTab); 250 251 // Finish initializing the ELF header. 252 initELFHeader<ELFT>(ElfHeader, Stub.Arch); 253 ElfHeader.e_shstrndx = ShStrTab.Index; 254 ElfHeader.e_shnum = LastSection->Index + 1; 255 ElfHeader.e_shoff = 256 alignTo(LastSection->Offset + LastSection->Size, sizeof(Elf_Addr)); 257 } 258 259 size_t getSize() const { 260 return ElfHeader.e_shoff + ElfHeader.e_shnum * sizeof(Elf_Shdr); 261 } 262 263 void write(uint8_t *Data) const { 264 write(Data, ElfHeader); 265 DynSym.Content.write(Data + DynSym.Shdr.sh_offset); 266 DynStr.Content.write(Data + DynStr.Shdr.sh_offset); 267 DynTab.Content.write(Data + DynTab.Shdr.sh_offset); 268 ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset); 269 writeShdr(Data, DynSym); 270 writeShdr(Data, DynStr); 271 writeShdr(Data, DynTab); 272 writeShdr(Data, ShStrTab); 273 } 274 275 private: 276 Elf_Ehdr ElfHeader; 277 ContentSection<ELFStringTableBuilder, ELFT> DynStr; 278 ContentSection<ELFStringTableBuilder, ELFT> ShStrTab; 279 ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> DynSym; 280 ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> DynTab; 281 282 template <class T> static void write(uint8_t *Data, const T &Value) { 283 *reinterpret_cast<T *>(Data) = Value; 284 } 285 286 void fillStrTabShdr(ContentSection<ELFStringTableBuilder, ELFT> &StrTab, 287 uint32_t ShFlags = 0) const { 288 StrTab.Shdr.sh_type = SHT_STRTAB; 289 StrTab.Shdr.sh_flags = ShFlags; 290 StrTab.Shdr.sh_addr = StrTab.Addr; 291 StrTab.Shdr.sh_offset = StrTab.Offset; 292 StrTab.Shdr.sh_info = 0; 293 StrTab.Shdr.sh_size = StrTab.Size; 294 StrTab.Shdr.sh_name = ShStrTab.Content.getOffset(StrTab.Name); 295 StrTab.Shdr.sh_addralign = StrTab.Align; 296 StrTab.Shdr.sh_entsize = 0; 297 StrTab.Shdr.sh_link = 0; 298 } 299 void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> &SymTab, 300 uint32_t ShType) const { 301 SymTab.Shdr.sh_type = ShType; 302 SymTab.Shdr.sh_flags = SHF_ALLOC; 303 SymTab.Shdr.sh_addr = SymTab.Addr; 304 SymTab.Shdr.sh_offset = SymTab.Offset; 305 SymTab.Shdr.sh_info = SymTab.Size / sizeof(Elf_Sym) > 1 ? 1 : 0; 306 SymTab.Shdr.sh_size = SymTab.Size; 307 SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name); 308 SymTab.Shdr.sh_addralign = SymTab.Align; 309 SymTab.Shdr.sh_entsize = sizeof(Elf_Sym); 310 SymTab.Shdr.sh_link = this->DynStr.Index; 311 } 312 void fillDynTabShdr( 313 ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> &DynTab) const { 314 DynTab.Shdr.sh_type = SHT_DYNAMIC; 315 DynTab.Shdr.sh_flags = SHF_ALLOC; 316 DynTab.Shdr.sh_addr = DynTab.Addr; 317 DynTab.Shdr.sh_offset = DynTab.Offset; 318 DynTab.Shdr.sh_info = 0; 319 DynTab.Shdr.sh_size = DynTab.Size; 320 DynTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(DynTab.Name); 321 DynTab.Shdr.sh_addralign = DynTab.Align; 322 DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn); 323 DynTab.Shdr.sh_link = this->DynStr.Index; 324 } 325 uint64_t shdrOffset(const OutputSection<ELFT> &Sec) const { 326 return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr); 327 } 328 329 void writeShdr(uint8_t *Data, const OutputSection<ELFT> &Sec) const { 330 write(Data + shdrOffset(Sec), Sec.Shdr); 331 } 332 }; 333 } // end anonymous namespace 334 335 /// This function behaves similarly to StringRef::substr(), but attempts to 336 /// terminate the returned StringRef at the first null terminator. If no null 337 /// terminator is found, an error is returned. 338 /// 339 /// @param Str Source string to create a substring from. 340 /// @param Offset The start index of the desired substring. 341 static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) { 342 size_t StrEnd = Str.find('\0', Offset); 343 if (StrEnd == StringLiteral::npos) { 344 return createError( 345 "String overran bounds of string table (no null terminator)"); 346 } 347 348 size_t StrLen = StrEnd - Offset; 349 return Str.substr(Offset, StrLen); 350 } 351 352 /// This function takes an error, and appends a string of text to the end of 353 /// that error. Since "appending" to an Error isn't supported behavior of an 354 /// Error, this function technically creates a new error with the combined 355 /// message and consumes the old error. 356 /// 357 /// @param Err Source error. 358 /// @param After Text to append at the end of Err's error message. 359 Error appendToError(Error Err, StringRef After) { 360 std::string Message; 361 raw_string_ostream Stream(Message); 362 Stream << Err; 363 Stream << " " << After; 364 consumeError(std::move(Err)); 365 return createError(Stream.str().c_str()); 366 } 367 368 /// This function populates a DynamicEntries struct using an ELFT::DynRange. 369 /// After populating the struct, the members are validated with 370 /// some basic sanity checks. 371 /// 372 /// @param Dyn Target DynamicEntries struct to populate. 373 /// @param DynTable Source dynamic table. 374 template <class ELFT> 375 static Error populateDynamic(DynamicEntries &Dyn, 376 typename ELFT::DynRange DynTable) { 377 if (DynTable.empty()) 378 return createError("No .dynamic section found"); 379 380 // Search .dynamic for relevant entries. 381 bool FoundDynStr = false; 382 bool FoundDynStrSz = false; 383 bool FoundDynSym = false; 384 for (auto &Entry : DynTable) { 385 switch (Entry.d_tag) { 386 case DT_SONAME: 387 Dyn.SONameOffset = Entry.d_un.d_val; 388 break; 389 case DT_STRTAB: 390 Dyn.StrTabAddr = Entry.d_un.d_ptr; 391 FoundDynStr = true; 392 break; 393 case DT_STRSZ: 394 Dyn.StrSize = Entry.d_un.d_val; 395 FoundDynStrSz = true; 396 break; 397 case DT_NEEDED: 398 Dyn.NeededLibNames.push_back(Entry.d_un.d_val); 399 break; 400 case DT_SYMTAB: 401 Dyn.DynSymAddr = Entry.d_un.d_ptr; 402 FoundDynSym = true; 403 break; 404 case DT_HASH: 405 Dyn.ElfHash = Entry.d_un.d_ptr; 406 break; 407 case DT_GNU_HASH: 408 Dyn.GnuHash = Entry.d_un.d_ptr; 409 } 410 } 411 412 if (!FoundDynStr) { 413 return createError( 414 "Couldn't locate dynamic string table (no DT_STRTAB entry)"); 415 } 416 if (!FoundDynStrSz) { 417 return createError( 418 "Couldn't determine dynamic string table size (no DT_STRSZ entry)"); 419 } 420 if (!FoundDynSym) { 421 return createError( 422 "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)"); 423 } 424 if (Dyn.SONameOffset.hasValue() && *Dyn.SONameOffset >= Dyn.StrSize) { 425 return createStringError(object_error::parse_failed, 426 "DT_SONAME string offset (0x%016" PRIx64 427 ") outside of dynamic string table", 428 *Dyn.SONameOffset); 429 } 430 for (uint64_t Offset : Dyn.NeededLibNames) { 431 if (Offset >= Dyn.StrSize) { 432 return createStringError(object_error::parse_failed, 433 "DT_NEEDED string offset (0x%016" PRIx64 434 ") outside of dynamic string table", 435 Offset); 436 } 437 } 438 439 return Error::success(); 440 } 441 442 /// This function finds the number of dynamic symbols using a GNU hash table. 443 /// 444 /// @param Table The GNU hash table for .dynsym. 445 template <class ELFT> 446 static uint64_t getDynSymtabSize(const typename ELFT::GnuHash &Table) { 447 using Elf_Word = typename ELFT::Word; 448 if (Table.nbuckets == 0) 449 return Table.symndx + 1; 450 uint64_t LastSymIdx = 0; 451 uint64_t BucketVal = 0; 452 // Find the index of the first symbol in the last chain. 453 for (Elf_Word Val : Table.buckets()) { 454 BucketVal = std::max(BucketVal, (uint64_t)Val); 455 } 456 LastSymIdx += BucketVal; 457 const Elf_Word *It = 458 reinterpret_cast<const Elf_Word *>(Table.values(BucketVal).end()); 459 // Locate the end of the chain to find the last symbol index. 460 while ((*It & 1) == 0) { 461 LastSymIdx++; 462 It++; 463 } 464 return LastSymIdx + 1; 465 } 466 467 /// This function determines the number of dynamic symbols. 468 /// Without access to section headers, the number of symbols must be determined 469 /// by parsing dynamic hash tables. 470 /// 471 /// @param Dyn Entries with the locations of hash tables. 472 /// @param ElfFile The ElfFile that the section contents reside in. 473 template <class ELFT> 474 static Expected<uint64_t> getNumSyms(DynamicEntries &Dyn, 475 const ELFFile<ELFT> &ElfFile) { 476 using Elf_Hash = typename ELFT::Hash; 477 using Elf_GnuHash = typename ELFT::GnuHash; 478 // Search GNU hash table to try to find the upper bound of dynsym. 479 if (Dyn.GnuHash.hasValue()) { 480 Expected<const uint8_t *> TablePtr = ElfFile.toMappedAddr(*Dyn.GnuHash); 481 if (!TablePtr) 482 return TablePtr.takeError(); 483 const Elf_GnuHash *Table = 484 reinterpret_cast<const Elf_GnuHash *>(TablePtr.get()); 485 return getDynSymtabSize<ELFT>(*Table); 486 } 487 // Search SYSV hash table to try to find the upper bound of dynsym. 488 if (Dyn.ElfHash.hasValue()) { 489 Expected<const uint8_t *> TablePtr = ElfFile.toMappedAddr(*Dyn.ElfHash); 490 if (!TablePtr) 491 return TablePtr.takeError(); 492 const Elf_Hash *Table = reinterpret_cast<const Elf_Hash *>(TablePtr.get()); 493 return Table->nchain; 494 } 495 return 0; 496 } 497 498 /// This function extracts symbol type from a symbol's st_info member and 499 /// maps it to an ELFSymbolType enum. 500 /// Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are supported. 501 /// Other symbol types are mapped to ELFSymbolType::Unknown. 502 /// 503 /// @param Info Binary symbol st_info to extract symbol type from. 504 static ELFSymbolType convertInfoToType(uint8_t Info) { 505 Info = Info & 0xf; 506 switch (Info) { 507 case ELF::STT_NOTYPE: 508 return ELFSymbolType::NoType; 509 case ELF::STT_OBJECT: 510 return ELFSymbolType::Object; 511 case ELF::STT_FUNC: 512 return ELFSymbolType::Func; 513 case ELF::STT_TLS: 514 return ELFSymbolType::TLS; 515 default: 516 return ELFSymbolType::Unknown; 517 } 518 } 519 520 /// This function creates an ELFSymbol and populates all members using 521 /// information from a binary ELFT::Sym. 522 /// 523 /// @param SymName The desired name of the ELFSymbol. 524 /// @param RawSym ELFT::Sym to extract symbol information from. 525 template <class ELFT> 526 static ELFSymbol createELFSym(StringRef SymName, 527 const typename ELFT::Sym &RawSym) { 528 ELFSymbol TargetSym{std::string(SymName)}; 529 uint8_t Binding = RawSym.getBinding(); 530 if (Binding == STB_WEAK) 531 TargetSym.Weak = true; 532 else 533 TargetSym.Weak = false; 534 535 TargetSym.Undefined = RawSym.isUndefined(); 536 TargetSym.Type = convertInfoToType(RawSym.st_info); 537 538 if (TargetSym.Type == ELFSymbolType::Func) { 539 TargetSym.Size = 0; 540 } else { 541 TargetSym.Size = RawSym.st_size; 542 } 543 return TargetSym; 544 } 545 546 /// This function populates an ELFStub with symbols using information read 547 /// from an ELF binary. 548 /// 549 /// @param TargetStub ELFStub to add symbols to. 550 /// @param DynSym Range of dynamic symbols to add to TargetStub. 551 /// @param DynStr StringRef to the dynamic string table. 552 template <class ELFT> 553 static Error populateSymbols(ELFStub &TargetStub, 554 const typename ELFT::SymRange DynSym, 555 StringRef DynStr) { 556 // Skips the first symbol since it's the NULL symbol. 557 for (auto RawSym : DynSym.drop_front(1)) { 558 // If a symbol does not have global or weak binding, ignore it. 559 uint8_t Binding = RawSym.getBinding(); 560 if (!(Binding == STB_GLOBAL || Binding == STB_WEAK)) 561 continue; 562 // If a symbol doesn't have default or protected visibility, ignore it. 563 uint8_t Visibility = RawSym.getVisibility(); 564 if (!(Visibility == STV_DEFAULT || Visibility == STV_PROTECTED)) 565 continue; 566 // Create an ELFSymbol and populate it with information from the symbol 567 // table entry. 568 Expected<StringRef> SymName = terminatedSubstr(DynStr, RawSym.st_name); 569 if (!SymName) 570 return SymName.takeError(); 571 ELFSymbol Sym = createELFSym<ELFT>(*SymName, RawSym); 572 TargetStub.Symbols.insert(std::move(Sym)); 573 // TODO: Populate symbol warning. 574 } 575 return Error::success(); 576 } 577 578 /// Returns a new ELFStub with all members populated from an ELFObjectFile. 579 /// @param ElfObj Source ELFObjectFile. 580 template <class ELFT> 581 static Expected<std::unique_ptr<ELFStub>> 582 buildStub(const ELFObjectFile<ELFT> &ElfObj) { 583 using Elf_Dyn_Range = typename ELFT::DynRange; 584 using Elf_Phdr_Range = typename ELFT::PhdrRange; 585 using Elf_Sym_Range = typename ELFT::SymRange; 586 using Elf_Sym = typename ELFT::Sym; 587 std::unique_ptr<ELFStub> DestStub = std::make_unique<ELFStub>(); 588 const ELFFile<ELFT> &ElfFile = ElfObj.getELFFile(); 589 // Fetch .dynamic table. 590 Expected<Elf_Dyn_Range> DynTable = ElfFile.dynamicEntries(); 591 if (!DynTable) { 592 return DynTable.takeError(); 593 } 594 595 // Fetch program headers. 596 Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers(); 597 if (!PHdrs) { 598 return PHdrs.takeError(); 599 } 600 601 // Collect relevant .dynamic entries. 602 DynamicEntries DynEnt; 603 if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable)) 604 return std::move(Err); 605 606 // Get pointer to in-memory location of .dynstr section. 607 Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr); 608 if (!DynStrPtr) 609 return appendToError(DynStrPtr.takeError(), 610 "when locating .dynstr section contents"); 611 612 StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()), 613 DynEnt.StrSize); 614 615 // Populate Arch from ELF header. 616 DestStub->Arch = ElfFile.getHeader().e_machine; 617 618 // Populate SoName from .dynamic entries and dynamic string table. 619 if (DynEnt.SONameOffset.hasValue()) { 620 Expected<StringRef> NameOrErr = 621 terminatedSubstr(DynStr, *DynEnt.SONameOffset); 622 if (!NameOrErr) { 623 return appendToError(NameOrErr.takeError(), "when reading DT_SONAME"); 624 } 625 DestStub->SoName = std::string(*NameOrErr); 626 } 627 628 // Populate NeededLibs from .dynamic entries and dynamic string table. 629 for (uint64_t NeededStrOffset : DynEnt.NeededLibNames) { 630 Expected<StringRef> LibNameOrErr = 631 terminatedSubstr(DynStr, NeededStrOffset); 632 if (!LibNameOrErr) { 633 return appendToError(LibNameOrErr.takeError(), "when reading DT_NEEDED"); 634 } 635 DestStub->NeededLibs.push_back(std::string(*LibNameOrErr)); 636 } 637 638 // Populate Symbols from .dynsym table and dynamic string table. 639 Expected<uint64_t> SymCount = getNumSyms(DynEnt, ElfFile); 640 if (!SymCount) 641 return SymCount.takeError(); 642 if (*SymCount > 0) { 643 // Get pointer to in-memory location of .dynsym section. 644 Expected<const uint8_t *> DynSymPtr = 645 ElfFile.toMappedAddr(DynEnt.DynSymAddr); 646 if (!DynSymPtr) 647 return appendToError(DynSymPtr.takeError(), 648 "when locating .dynsym section contents"); 649 Elf_Sym_Range DynSyms = ArrayRef<Elf_Sym>( 650 reinterpret_cast<const Elf_Sym *>(*DynSymPtr), *SymCount); 651 Error SymReadError = populateSymbols<ELFT>(*DestStub, DynSyms, DynStr); 652 if (SymReadError) 653 return appendToError(std::move(SymReadError), 654 "when reading dynamic symbols"); 655 } 656 657 return std::move(DestStub); 658 } 659 660 /// This function opens a file for writing and then writes a binary ELF stub to 661 /// the file. 662 /// 663 /// @param FilePath File path for writing the ELF binary. 664 /// @param Stub Source ELFStub to generate a binary ELF stub from. 665 template <class ELFT> 666 static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub) { 667 ELFStubBuilder<ELFT> Builder{Stub}; 668 Expected<std::unique_ptr<FileOutputBuffer>> BufOrError = 669 FileOutputBuffer::create(FilePath, Builder.getSize()); 670 if (!BufOrError) 671 return createStringError(errc::invalid_argument, 672 toString(BufOrError.takeError()) + 673 " when trying to open `" + FilePath + 674 "` for writing"); 675 676 // Write binary to file. 677 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufOrError); 678 Builder.write(Buf->getBufferStart()); 679 680 if (Error E = Buf->commit()) 681 return E; 682 683 return Error::success(); 684 } 685 686 Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) { 687 Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf); 688 if (!BinOrErr) { 689 return BinOrErr.takeError(); 690 } 691 692 Binary *Bin = BinOrErr->get(); 693 if (auto Obj = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { 694 return buildStub(*Obj); 695 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { 696 return buildStub(*Obj); 697 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { 698 return buildStub(*Obj); 699 } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { 700 return buildStub(*Obj); 701 } 702 return createStringError(errc::not_supported, "unsupported binary format"); 703 } 704 705 // This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub() 706 // can be called without having to use ELFType templates directly. 707 Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub, 708 ELFTarget OutputFormat) { 709 if (OutputFormat == ELFTarget::ELF32LE) 710 return writeELFBinaryToFile<ELF32LE>(FilePath, Stub); 711 if (OutputFormat == ELFTarget::ELF32BE) 712 return writeELFBinaryToFile<ELF32BE>(FilePath, Stub); 713 if (OutputFormat == ELFTarget::ELF64LE) 714 return writeELFBinaryToFile<ELF64LE>(FilePath, Stub); 715 if (OutputFormat == ELFTarget::ELF64BE) 716 return writeELFBinaryToFile<ELF64BE>(FilePath, Stub); 717 llvm_unreachable("invalid binary output target"); 718 } 719 720 } // end namespace elfabi 721 } // end namespace llvm 722