diff options
Diffstat (limited to 'tools/llvm-objcopy/ELF/Object.h')
-rw-r--r-- | tools/llvm-objcopy/ELF/Object.h | 314 |
1 files changed, 274 insertions, 40 deletions
diff --git a/tools/llvm-objcopy/ELF/Object.h b/tools/llvm-objcopy/ELF/Object.h index e5730cd543ee..f3df93b9662f 100644 --- a/tools/llvm-objcopy/ELF/Object.h +++ b/tools/llvm-objcopy/ELF/Object.h @@ -1,9 +1,8 @@ //===- Object.h -------------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -18,8 +17,8 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/JamCRC.h" #include <cstddef> #include <cstdint> #include <functional> @@ -60,6 +59,7 @@ public: iterator begin() { return iterator(Sections.data()); } iterator end() { return iterator(Sections.data() + Sections.size()); } + size_t size() const { return Sections.size(); } SectionBase *getSection(uint32_t Index, Twine ErrMsg); @@ -108,7 +108,7 @@ protected: Buffer &Out; public: - virtual ~SectionWriter(){}; + virtual ~SectionWriter() = default; void visit(const Section &Sec) override; void visit(const OwnedDataSection &Sec) override; @@ -169,6 +169,8 @@ public: #define MAKE_SEC_WRITER_FRIEND \ friend class SectionWriter; \ + friend class IHexSectionWriterBase; \ + friend class IHexSectionWriter; \ template <class ELFT> friend class ELFSectionWriter; \ template <class ELFT> friend class ELFSectionSizer; @@ -187,6 +189,118 @@ public: explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {} }; +using IHexLineData = SmallVector<char, 64>; + +struct IHexRecord { + // Memory address of the record. + uint16_t Addr; + // Record type (see below). + uint16_t Type; + // Record data in hexadecimal form. + StringRef HexData; + + // Helper method to get file length of the record + // including newline character + static size_t getLength(size_t DataSize) { + // :LLAAAATT[DD...DD]CC' + return DataSize * 2 + 11; + } + + // Gets length of line in a file (getLength + CRLF). + static size_t getLineLength(size_t DataSize) { + return getLength(DataSize) + 2; + } + + // Given type, address and data returns line which can + // be written to output file. + static IHexLineData getLine(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data); + + // Parses the line and returns record if possible. + // Line should be trimmed from whitespace characters. + static Expected<IHexRecord> parse(StringRef Line); + + // Calculates checksum of stringified record representation + // S must NOT contain leading ':' and trailing whitespace + // characters + static uint8_t getChecksum(StringRef S); + + enum Type { + // Contains data and a 16-bit starting address for the data. + // The byte count specifies number of data bytes in the record. + Data = 0, + // Must occur exactly once per file in the last line of the file. + // The data field is empty (thus byte count is 00) and the address + // field is typically 0000. + EndOfFile = 1, + // The data field contains a 16-bit segment base address (thus byte + // count is always 02) compatible with 80x86 real mode addressing. + // The address field (typically 0000) is ignored. The segment address + // from the most recent 02 record is multiplied by 16 and added to each + // subsequent data record address to form the physical starting address + // for the data. This allows addressing up to one megabyte of address + // space. + SegmentAddr = 2, + // or 80x86 processors, specifies the initial content of the CS:IP + // registers. The address field is 0000, the byte count is always 04, + // the first two data bytes are the CS value, the latter two are the + // IP value. + StartAddr80x86 = 3, + // Allows for 32 bit addressing (up to 4GiB). The record's address field + // is ignored (typically 0000) and its byte count is always 02. The two + // data bytes (big endian) specify the upper 16 bits of the 32 bit + // absolute address for all subsequent type 00 records + ExtendedAddr = 4, + // The address field is 0000 (not used) and the byte count is always 04. + // The four data bytes represent a 32-bit address value. In the case of + // 80386 and higher CPUs, this address is loaded into the EIP register. + StartAddr = 5, + // We have no other valid types + InvalidType = 6 + }; +}; + +// Base class for IHexSectionWriter. This class implements writing algorithm, +// but doesn't actually write records. It is used for output buffer size +// calculation in IHexWriter::finalize. +class IHexSectionWriterBase : public BinarySectionWriter { + // 20-bit segment address + uint32_t SegmentAddr = 0; + // Extended linear address + uint32_t BaseAddr = 0; + + // Write segment address corresponding to 'Addr' + uint64_t writeSegmentAddr(uint64_t Addr); + // Write extended linear (base) address corresponding to 'Addr' + uint64_t writeBaseAddr(uint64_t Addr); + +protected: + // Offset in the output buffer + uint64_t Offset = 0; + + void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data); + virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data); + +public: + explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {} + + uint64_t getBufferOffset() const { return Offset; } + void visit(const Section &Sec) final; + void visit(const OwnedDataSection &Sec) final; + void visit(const StringTableSection &Sec) override; + void visit(const DynamicRelocationSection &Sec) final; + using BinarySectionWriter::visit; +}; + +// Real IHEX section writer +class IHexSectionWriter : public IHexSectionWriterBase { +public: + IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {} + + void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override; + void visit(const StringTableSection &Sec) override; +}; + class Writer { protected: Object &Obj; @@ -194,8 +308,8 @@ protected: public: virtual ~Writer(); - virtual void finalize() = 0; - virtual void write() = 0; + virtual Error finalize() = 0; + virtual Error write() = 0; Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {} }; @@ -216,6 +330,7 @@ private: void writePhdrs(); void writeShdrs(); void writeSectionData(); + void writeSegmentData(); void assignOffsets(); @@ -225,12 +340,11 @@ private: public: virtual ~ELFWriter() {} - bool WriteSectionHeaders = true; + bool WriteSectionHeaders; - void finalize() override; - void write() override; - ELFWriter(Object &Obj, Buffer &Buf, bool WSH) - : Writer(Obj, Buf), WriteSectionHeaders(WSH) {} + Error finalize() override; + Error write() override; + ELFWriter(Object &Obj, Buffer &Buf, bool WSH); }; class BinaryWriter : public Writer { @@ -241,11 +355,30 @@ private: public: ~BinaryWriter() {} - void finalize() override; - void write() override; + Error finalize() override; + Error write() override; BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} }; +class IHexWriter : public Writer { + struct SectionCompare { + bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const; + }; + + std::set<const SectionBase *, SectionCompare> Sections; + size_t TotalSize; + + Error checkSection(const SectionBase &Sec); + uint64_t writeEntryPointRecord(uint8_t *Buf); + uint64_t writeEndOfFileRecord(uint8_t *Buf); + +public: + ~IHexWriter() {} + Error finalize() override; + Error write() override; + IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} +}; + class SectionBase { public: std::string Name; @@ -274,11 +407,16 @@ public: virtual void initialize(SectionTableRef SecTable); virtual void finalize(); - virtual void removeSectionReferences(const SectionBase *Sec); - virtual void removeSymbols(function_ref<bool(const Symbol &)> ToRemove); + // Remove references to these sections. The list of sections must be sorted. + virtual Error + removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove); + virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); virtual void accept(SectionVisitor &Visitor) const = 0; virtual void accept(MutableSectionVisitor &Visitor) = 0; virtual void markSymbols(); + virtual void + replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); }; class Segment { @@ -322,6 +460,8 @@ public: void removeSection(const SectionBase *Sec) { Sections.erase(Sec); } void addSection(const SectionBase *Sec) { Sections.insert(Sec); } + + ArrayRef<uint8_t> getContents() const { return Contents; } }; class Section : public SectionBase { @@ -335,7 +475,8 @@ public: void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; - void removeSectionReferences(const SectionBase *Sec) override; + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; void initialize(SectionTableRef SecTable) override; void finalize() override; }; @@ -354,6 +495,16 @@ public: OriginalOffset = std::numeric_limits<uint64_t>::max(); } + OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags, + uint64_t SecOff) { + Name = SecName.str(); + Type = ELF::SHT_PROGBITS; + Addr = SecAddr; + Flags = SecFlags; + OriginalOffset = SecOff; + } + + void appendHexData(StringRef HexData); void accept(SectionVisitor &Sec) const override; void accept(MutableSectionVisitor &Visitor) override; }; @@ -421,7 +572,7 @@ public: void addString(StringRef Name); uint32_t findIndex(StringRef Name) const; - void finalize() override; + void prepareForLayout(); void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; @@ -440,10 +591,15 @@ enum SymbolShndxType { SYMBOL_SIMPLE_INDEX = 0, SYMBOL_ABS = ELF::SHN_ABS, SYMBOL_COMMON = ELF::SHN_COMMON, + SYMBOL_LOPROC = ELF::SHN_LOPROC, + SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS, SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON, SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2, SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4, SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8, + SYMBOL_HIPROC = ELF::SHN_HIPROC, + SYMBOL_LOOS = ELF::SHN_LOOS, + SYMBOL_HIOS = ELF::SHN_HIOS, SYMBOL_XINDEX = ELF::SHN_XINDEX, }; @@ -474,9 +630,14 @@ private: public: virtual ~SectionIndexSection() {} void addIndex(uint32_t Index) { - Indexes.push_back(Index); - Size += 4; + assert(Size > 0); + Indexes.push_back(Index); } + + void reserve(size_t NumSymbols) { + Indexes.reserve(NumSymbols); + Size = NumSymbols * 4; + } void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; } void initialize(SectionTableRef SecTable) override; void finalize() override; @@ -509,7 +670,7 @@ public: void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, - uint64_t Size); + uint64_t SymbolSize); void prepareForLayout(); // An 'empty' symbol table still contains a null symbol. bool empty() const { return Symbols.size() == 1; } @@ -517,17 +678,21 @@ public: SectionIndexTable = ShndxTable; } const SectionIndexSection *getShndxTable() const { return SectionIndexTable; } + void fillShndxTable(); const SectionBase *getStrTab() const { return SymbolNames; } const Symbol *getSymbolByIndex(uint32_t Index) const; Symbol *getSymbolByIndex(uint32_t Index); void updateSymbols(function_ref<void(Symbol &)> Callable); - void removeSectionReferences(const SectionBase *Sec) override; + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; void initialize(SectionTableRef SecTable) override; void finalize() override; void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; - void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_SYMTAB; @@ -567,14 +732,14 @@ public: // that code between the two symbol table types. template <class SymTabType> class RelocSectionWithSymtabBase : public RelocationSectionBase { - SymTabType *Symbols = nullptr; void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } protected: RelocSectionWithSymtabBase() = default; + SymTabType *Symbols = nullptr; + public: - void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; void finalize() override; }; @@ -589,8 +754,12 @@ public: void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; - void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { if (S->Flags & ELF::SHF_ALLOC) @@ -624,8 +793,10 @@ public: void accept(SectionVisitor &) const override; void accept(MutableSectionVisitor &Visitor) override; void finalize() override; - void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_GROUP; @@ -662,6 +833,9 @@ public: void accept(SectionVisitor &) const override; void accept(MutableSectionVisitor &Visitor) override; + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; static bool classof(const SectionBase *S) { if (!(S->Flags & ELF::SHF_ALLOC)) @@ -677,11 +851,11 @@ private: StringRef FileName; uint32_t CRC32; - void init(StringRef File, StringRef Data); + void init(StringRef File); public: // If we add this section from an external source we can use this ctor. - explicit GnuDebugLinkSection(StringRef File); + explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC); void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; }; @@ -697,21 +871,41 @@ using object::ELFFile; using object::ELFObjectFile; using object::OwningBinary; -class BinaryELFBuilder { +class BasicELFBuilder { +protected: uint16_t EMachine; - MemoryBuffer *MemBuf; std::unique_ptr<Object> Obj; void initFileHeader(); void initHeaderSegment(); StringTableSection *addStrTab(); SymbolTableSection *addSymTab(StringTableSection *StrTab); - void addData(SymbolTableSection *SymTab); void initSections(); public: + BasicELFBuilder(uint16_t EM) + : EMachine(EM), Obj(llvm::make_unique<Object>()) {} +}; + +class BinaryELFBuilder : public BasicELFBuilder { + MemoryBuffer *MemBuf; + void addData(SymbolTableSection *SymTab); + +public: BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) - : EMachine(EM), MemBuf(MB), Obj(llvm::make_unique<Object>()) {} + : BasicELFBuilder(EM), MemBuf(MB) {} + + std::unique_ptr<Object> build(); +}; + +class IHexELFBuilder : public BasicELFBuilder { + const std::vector<IHexRecord> &Records; + + void addDataSections(); + +public: + IHexELFBuilder(const std::vector<IHexRecord> &Records) + : BasicELFBuilder(ELF::EM_386), Records(Records) {} std::unique_ptr<Object> build(); }; @@ -724,17 +918,23 @@ private: const ELFFile<ELFT> &ElfFile; Object &Obj; + size_t EhdrOffset = 0; + Optional<StringRef> ExtractPartition; void setParentSegment(Segment &Child); - void readProgramHeaders(); + void readProgramHeaders(const ELFFile<ELFT> &HeadersFile); void initGroupSection(GroupSection *GroupSec); void initSymbolTable(SymbolTableSection *SymTab); void readSectionHeaders(); + void readSections(); + void findEhdrOffset(); SectionBase &makeSection(const Elf_Shdr &Shdr); public: - ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj) - : ElfFile(*ElfObj.getELFFile()), Obj(Obj) {} + ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj, + Optional<StringRef> ExtractPartition) + : ElfFile(*ElfObj.getELFFile()), Obj(Obj), + ExtractPartition(ExtractPartition) {} void build(); }; @@ -749,12 +949,36 @@ public: std::unique_ptr<Object> create() const override; }; +class IHexReader : public Reader { + MemoryBuffer *MemBuf; + + Expected<std::vector<IHexRecord>> parse() const; + Error parseError(size_t LineNo, Error E) const { + return LineNo == -1U + ? createFileError(MemBuf->getBufferIdentifier(), std::move(E)) + : createFileError(MemBuf->getBufferIdentifier(), LineNo, + std::move(E)); + } + template <typename... Ts> + Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const { + Error E = createStringError(errc::invalid_argument, Fmt, Vals...); + return parseError(LineNo, std::move(E)); + } + +public: + IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} + + std::unique_ptr<Object> create() const override; +}; + class ELFReader : public Reader { Binary *Bin; + Optional<StringRef> ExtractPartition; public: std::unique_ptr<Object> create() const override; - explicit ELFReader(Binary *B) : Bin(B) {} + explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition) + : Bin(B), ExtractPartition(ExtractPartition) {} }; class Object { @@ -764,6 +988,7 @@ private: std::vector<SecPtr> Sections; std::vector<SegPtr> Segments; + std::vector<SecPtr> RemovedSections; public: template <class T> @@ -792,6 +1017,7 @@ public: uint32_t Version; uint32_t Flags; + bool HadShdrs = true; StringTableSection *SectionNames = nullptr; SymbolTableSection *SymbolTable = nullptr; SectionIndexSection *SectionIndexTable = nullptr; @@ -801,11 +1027,19 @@ public: ConstRange<SectionBase> sections() const { return make_pointee_range(Sections); } + SectionBase *findSection(StringRef Name) { + auto SecIt = + find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; }); + return SecIt == Sections.end() ? nullptr : SecIt->get(); + } + SectionTableRef removedSections() { return SectionTableRef(RemovedSections); } + Range<Segment> segments() { return make_pointee_range(Segments); } ConstRange<Segment> segments() const { return make_pointee_range(Segments); } - void removeSections(std::function<bool(const SectionBase &)> ToRemove); - void removeSymbols(function_ref<bool(const Symbol &)> ToRemove); + Error removeSections(bool AllowBrokenLinks, + std::function<bool(const SectionBase &)> ToRemove); + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); template <class T, class... Ts> T &addSection(Ts &&... Args) { auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...); auto Ptr = Sec.get(); |