diff options
Diffstat (limited to 'llvm/lib/InterfaceStub/ELFObjHandler.cpp')
-rw-r--r-- | llvm/lib/InterfaceStub/ELFObjHandler.cpp | 139 |
1 files changed, 99 insertions, 40 deletions
diff --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp index cb72f57f7bde..13801cd2cbc0 100644 --- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp +++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp @@ -17,7 +17,6 @@ #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Process.h" using llvm::object::ELFObjectFile; @@ -195,7 +194,7 @@ public: for (const std::string &Lib : Stub.NeededLibs) DynStr.Content.add(Lib); if (Stub.SoName) - DynStr.Content.add(Stub.SoName.getValue()); + DynStr.Content.add(*Stub.SoName); std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab, &ShStrTab}; @@ -218,7 +217,8 @@ public: // time as long as it is not SHN_UNDEF. Set shndx to 1, which // points to ".dynsym". uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1; - DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Sym.Size, Bind, + uint64_t Size = Sym.Size.value_or(0); + DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Size, Bind, convertIFSSymbolTypeToELF(Sym.Type), 0, Shndx); } DynSym.Size = DynSym.Content.getSize(); @@ -226,11 +226,12 @@ public: // Poplulate dynamic table. size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0); size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0); + DynTab.Content.addValue(DT_STRSZ, DynSym.Size); for (const std::string &Lib : Stub.NeededLibs) DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib)); if (Stub.SoName) DynTab.Content.addValue(DT_SONAME, - DynStr.Content.getOffset(Stub.SoName.getValue())); + DynStr.Content.getOffset(*Stub.SoName)); DynTab.Size = DynTab.Content.getSize(); // Calculate sections' addresses and offsets. uint64_t CurrentOffset = sizeof(Elf_Ehdr); @@ -249,8 +250,7 @@ public: fillStrTabShdr(ShStrTab); // Finish initializing the ELF header. - initELFHeader<ELFT>(ElfHeader, - static_cast<uint16_t>(Stub.Target.Arch.getValue())); + initELFHeader<ELFT>(ElfHeader, static_cast<uint16_t>(*Stub.Target.Arch)); ElfHeader.e_shstrndx = ShStrTab.Index; ElfHeader.e_shnum = LastSection->Index + 1; ElfHeader.e_shoff = @@ -334,6 +334,89 @@ private: write(Data + shdrOffset(Sec), Sec.Shdr); } }; + +/// This function takes an error, and appends a string of text to the end of +/// that error. Since "appending" to an Error isn't supported behavior of an +/// Error, this function technically creates a new error with the combined +/// message and consumes the old error. +/// +/// @param Err Source error. +/// @param After Text to append at the end of Err's error message. +Error appendToError(Error Err, StringRef After) { + std::string Message; + raw_string_ostream Stream(Message); + Stream << Err; + Stream << " " << After; + consumeError(std::move(Err)); + return createError(Stream.str()); +} + +template <class ELFT> class DynSym { + using Elf_Shdr_Range = typename ELFT::ShdrRange; + using Elf_Shdr = typename ELFT::Shdr; + +public: + static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile, + const DynamicEntries &DynEnt) { + Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections(); + if (!Shdrs) + return Shdrs.takeError(); + return DynSym(ElfFile, DynEnt, *Shdrs); + } + + Expected<const uint8_t *> getDynSym() { + if (DynSymHdr) + return ElfFile.base() + DynSymHdr->sh_offset; + return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table"); + } + + Expected<StringRef> getDynStr() { + if (DynSymHdr) + return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs); + Expected<const uint8_t *> DataOrErr = getDynamicData( + DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize); + if (!DataOrErr) + return DataOrErr.takeError(); + return StringRef(reinterpret_cast<const char *>(*DataOrErr), + DynEnt.StrSize); + } + +private: + DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt, + Elf_Shdr_Range Shdrs) + : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs), + DynSymHdr(findDynSymHdr()) {} + + const Elf_Shdr *findDynSymHdr() { + for (const Elf_Shdr &Sec : Shdrs) + if (Sec.sh_type == SHT_DYNSYM) { + // If multiple .dynsym are present, use the first one. + // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() + return &Sec; + } + return nullptr; + } + + Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name, + uint64_t Size = 0) { + Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr); + if (!SecPtr) + return appendToError( + SecPtr.takeError(), + ("when locating " + Name + " section contents").str()); + Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size); + if (!SecEndPtr) + return appendToError( + SecEndPtr.takeError(), + ("when locating " + Name + " section contents").str()); + return *SecPtr; + } + + const ELFFile<ELFT> &ElfFile; + const DynamicEntries &DynEnt; + Elf_Shdr_Range Shdrs; + const Elf_Shdr *DynSymHdr; +}; } // end anonymous namespace /// This function behaves similarly to StringRef::substr(), but attempts to @@ -353,22 +436,6 @@ static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) { return Str.substr(Offset, StrLen); } -/// This function takes an error, and appends a string of text to the end of -/// that error. Since "appending" to an Error isn't supported behavior of an -/// Error, this function technically creates a new error with the combined -/// message and consumes the old error. -/// -/// @param Err Source error. -/// @param After Text to append at the end of Err's error message. -Error appendToError(Error Err, StringRef After) { - std::string Message; - raw_string_ostream Stream(Message); - Stream << Err; - Stream << " " << After; - consumeError(std::move(Err)); - return createError(Stream.str()); -} - /// This function populates a DynamicEntries struct using an ELFT::DynRange. /// After populating the struct, the members are validated with /// some basic correctness checks. @@ -425,7 +492,7 @@ static Error populateDynamic(DynamicEntries &Dyn, return createError( "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)"); } - if (Dyn.SONameOffset.hasValue() && *Dyn.SONameOffset >= Dyn.StrSize) { + if (Dyn.SONameOffset && *Dyn.SONameOffset >= Dyn.StrSize) { return createStringError(object_error::parse_failed, "DT_SONAME string offset (0x%016" PRIx64 ") outside of dynamic string table", @@ -507,7 +574,6 @@ template <class ELFT> static Expected<std::unique_ptr<IFSStub>> buildStub(const ELFObjectFile<ELFT> &ElfObj) { using Elf_Dyn_Range = typename ELFT::DynRange; - using Elf_Phdr_Range = typename ELFT::PhdrRange; using Elf_Sym_Range = typename ELFT::SymRange; using Elf_Sym = typename ELFT::Sym; std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>(); @@ -518,25 +584,19 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) { return DynTable.takeError(); } - // Fetch program headers. - Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers(); - if (!PHdrs) { - return PHdrs.takeError(); - } - // Collect relevant .dynamic entries. DynamicEntries DynEnt; if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable)) return std::move(Err); + Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt); + if (!EDynSym) + return EDynSym.takeError(); - // Get pointer to in-memory location of .dynstr section. - Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr); - if (!DynStrPtr) - return appendToError(DynStrPtr.takeError(), - "when locating .dynstr section contents"); + Expected<StringRef> EDynStr = EDynSym->getDynStr(); + if (!EDynStr) + return EDynStr.takeError(); - StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()), - DynEnt.StrSize); + StringRef DynStr = *EDynStr; // Populate Arch from ELF header. DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine); @@ -547,7 +607,7 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) { DestStub->Target.ObjectFormat = "ELF"; // Populate SoName from .dynamic entries and dynamic string table. - if (DynEnt.SONameOffset.hasValue()) { + if (DynEnt.SONameOffset) { Expected<StringRef> NameOrErr = terminatedSubstr(DynStr, *DynEnt.SONameOffset); if (!NameOrErr) { @@ -572,8 +632,7 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) { return SymCount.takeError(); if (*SymCount > 0) { // Get pointer to in-memory location of .dynsym section. - Expected<const uint8_t *> DynSymPtr = - ElfFile.toMappedAddr(DynEnt.DynSymAddr); + Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym(); if (!DynSymPtr) return appendToError(DynSymPtr.takeError(), "when locating .dynsym section contents"); |