aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-objcopy/ELF/Object.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-objcopy/ELF/Object.h')
-rw-r--r--tools/llvm-objcopy/ELF/Object.h314
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();