diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /tools/llvm-objcopy/ELF/Object.cpp | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Diffstat (limited to 'tools/llvm-objcopy/ELF/Object.cpp')
-rw-r--r-- | tools/llvm-objcopy/ELF/Object.cpp | 1198 |
1 files changed, 902 insertions, 296 deletions
diff --git a/tools/llvm-objcopy/ELF/Object.cpp b/tools/llvm-objcopy/ELF/Object.cpp index 3d3e029c09eb..fa696380e17c 100644 --- a/tools/llvm-objcopy/ELF/Object.cpp +++ b/tools/llvm-objcopy/ELF/Object.cpp @@ -1,9 +1,8 @@ //===- Object.cpp ---------------------------------------------------------===// // -// 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,6 +17,7 @@ #include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" @@ -25,6 +25,7 @@ #include <cstddef> #include <cstdint> #include <iterator> +#include <unordered_set> #include <utility> #include <vector> @@ -36,8 +37,8 @@ using namespace object; using namespace ELF; template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) { - uint8_t *B = Buf.getBufferStart(); - B += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr); + uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset + + Seg.Index * sizeof(Elf_Phdr); Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B); Phdr.p_type = Seg.Type; Phdr.p_flags = Seg.Flags; @@ -49,15 +50,24 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) { Phdr.p_align = Seg.Align; } -void SectionBase::removeSectionReferences(const SectionBase *Sec) {} -void SectionBase::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {} +Error SectionBase::removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) { + return Error::success(); +} + +Error SectionBase::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { + return Error::success(); +} + void SectionBase::initialize(SectionTableRef SecTable) {} void SectionBase::finalize() {} void SectionBase::markSymbols() {} +void SectionBase::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &) {} template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) { - uint8_t *B = Buf.getBufferStart(); - B += Sec.HeaderOffset; + uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset; Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B); Shdr.sh_name = Sec.NameIndex; Shdr.sh_type = Sec.Type; @@ -113,30 +123,270 @@ template <class ELFT> void ELFSectionSizer<ELFT>::visit(DecompressedSection &Sec) {} void BinarySectionWriter::visit(const SectionIndexSection &Sec) { - error("Cannot write symbol section index table '" + Sec.Name + "' "); + error("cannot write symbol section index table '" + Sec.Name + "' "); } void BinarySectionWriter::visit(const SymbolTableSection &Sec) { - error("Cannot write symbol table '" + Sec.Name + "' out to binary"); + error("cannot write symbol table '" + Sec.Name + "' out to binary"); } void BinarySectionWriter::visit(const RelocationSection &Sec) { - error("Cannot write relocation section '" + Sec.Name + "' out to binary"); + error("cannot write relocation section '" + Sec.Name + "' out to binary"); } void BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) { - error("Cannot write '" + Sec.Name + "' out to binary"); + error("cannot write '" + Sec.Name + "' out to binary"); } void BinarySectionWriter::visit(const GroupSection &Sec) { - error("Cannot write '" + Sec.Name + "' out to binary"); + error("cannot write '" + Sec.Name + "' out to binary"); } void SectionWriter::visit(const Section &Sec) { - if (Sec.Type == SHT_NOBITS) - return; - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - llvm::copy(Sec.Contents, Buf); + if (Sec.Type != SHT_NOBITS) + llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); +} + +static bool addressOverflows32bit(uint64_t Addr) { + // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok + return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX; +} + +template <class T> static T checkedGetHex(StringRef S) { + T Value; + bool Fail = S.getAsInteger(16, Value); + assert(!Fail); + (void)Fail; + return Value; +} + +// Fills exactly Len bytes of buffer with hexadecimal characters +// representing value 'X' +template <class T, class Iterator> +static Iterator utohexstr(T X, Iterator It, size_t Len) { + // Fill range with '0' + std::fill(It, It + Len, '0'); + + for (long I = Len - 1; I >= 0; --I) { + unsigned char Mod = static_cast<unsigned char>(X) & 15; + *(It + I) = hexdigit(Mod, false); + X >>= 4; + } + assert(X == 0); + return It + Len; +} + +uint8_t IHexRecord::getChecksum(StringRef S) { + assert((S.size() & 1) == 0); + uint8_t Checksum = 0; + while (!S.empty()) { + Checksum += checkedGetHex<uint8_t>(S.take_front(2)); + S = S.drop_front(2); + } + return -Checksum; +} + +IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data) { + IHexLineData Line(getLineLength(Data.size())); + assert(Line.size()); + auto Iter = Line.begin(); + *Iter++ = ':'; + Iter = utohexstr(Data.size(), Iter, 2); + Iter = utohexstr(Addr, Iter, 4); + Iter = utohexstr(Type, Iter, 2); + for (uint8_t X : Data) + Iter = utohexstr(X, Iter, 2); + StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter)); + Iter = utohexstr(getChecksum(S), Iter, 2); + *Iter++ = '\r'; + *Iter++ = '\n'; + assert(Iter == Line.end()); + return Line; +} + +static Error checkRecord(const IHexRecord &R) { + switch (R.Type) { + case IHexRecord::Data: + if (R.HexData.size() == 0) + return createStringError( + errc::invalid_argument, + "zero data length is not allowed for data records"); + break; + case IHexRecord::EndOfFile: + break; + case IHexRecord::SegmentAddr: + // 20-bit segment address. Data length must be 2 bytes + // (4 bytes in hex) + if (R.HexData.size() != 4) + return createStringError( + errc::invalid_argument, + "segment address data should be 2 bytes in size"); + break; + case IHexRecord::StartAddr80x86: + case IHexRecord::StartAddr: + if (R.HexData.size() != 8) + return createStringError(errc::invalid_argument, + "start address data should be 4 bytes in size"); + // According to Intel HEX specification '03' record + // only specifies the code address within the 20-bit + // segmented address space of the 8086/80186. This + // means 12 high order bits should be zeroes. + if (R.Type == IHexRecord::StartAddr80x86 && + R.HexData.take_front(3) != "000") + return createStringError(errc::invalid_argument, + "start address exceeds 20 bit for 80x86"); + break; + case IHexRecord::ExtendedAddr: + // 16-31 bits of linear base address + if (R.HexData.size() != 4) + return createStringError( + errc::invalid_argument, + "extended address data should be 2 bytes in size"); + break; + default: + // Unknown record type + return createStringError(errc::invalid_argument, "unknown record type: %u", + static_cast<unsigned>(R.Type)); + } + return Error::success(); +} + +// Checks that IHEX line contains valid characters. +// This allows converting hexadecimal data to integers +// without extra verification. +static Error checkChars(StringRef Line) { + assert(!Line.empty()); + if (Line[0] != ':') + return createStringError(errc::invalid_argument, + "missing ':' in the beginning of line."); + + for (size_t Pos = 1; Pos < Line.size(); ++Pos) + if (hexDigitValue(Line[Pos]) == -1U) + return createStringError(errc::invalid_argument, + "invalid character at position %zu.", Pos + 1); + return Error::success(); +} + +Expected<IHexRecord> IHexRecord::parse(StringRef Line) { + assert(!Line.empty()); + + // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC' + if (Line.size() < 11) + return createStringError(errc::invalid_argument, + "line is too short: %zu chars.", Line.size()); + + if (Error E = checkChars(Line)) + return std::move(E); + + IHexRecord Rec; + size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2)); + if (Line.size() != getLength(DataLen)) + return createStringError(errc::invalid_argument, + "invalid line length %zu (should be %zu)", + Line.size(), getLength(DataLen)); + + Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4)); + Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2)); + Rec.HexData = Line.substr(9, DataLen * 2); + + if (getChecksum(Line.drop_front(1)) != 0) + return createStringError(errc::invalid_argument, "incorrect checksum."); + if (Error E = checkRecord(Rec)) + return std::move(E); + return Rec; +} + +static uint64_t sectionPhysicalAddr(const SectionBase *Sec) { + Segment *Seg = Sec->ParentSegment; + if (Seg && Seg->Type != ELF::PT_LOAD) + Seg = nullptr; + return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset + : Sec->Addr; +} + +void IHexSectionWriterBase::writeSection(const SectionBase *Sec, + ArrayRef<uint8_t> Data) { + assert(Data.size() == Sec->Size); + const uint32_t ChunkSize = 16; + uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU; + while (!Data.empty()) { + uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize); + if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) { + if (Addr > 0xFFFFFU) { + // Write extended address record, zeroing segment address + // if needed. + if (SegmentAddr != 0) + SegmentAddr = writeSegmentAddr(0U); + BaseAddr = writeBaseAddr(Addr); + } else { + // We can still remain 16-bit + SegmentAddr = writeSegmentAddr(Addr); + } + } + uint64_t SegOffset = Addr - BaseAddr - SegmentAddr; + assert(SegOffset <= 0xFFFFU); + DataSize = std::min(DataSize, 0x10000U - SegOffset); + writeData(0, SegOffset, Data.take_front(DataSize)); + Addr += DataSize; + Data = Data.drop_front(DataSize); + } +} + +uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) { + assert(Addr <= 0xFFFFFU); + uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0}; + writeData(2, 0, Data); + return Addr & 0xF0000U; +} + +uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) { + assert(Addr <= 0xFFFFFFFFU); + uint64_t Base = Addr & 0xFFFF0000U; + uint8_t Data[] = {static_cast<uint8_t>(Base >> 24), + static_cast<uint8_t>((Base >> 16) & 0xFF)}; + writeData(4, 0, Data); + return Base; +} + +void IHexSectionWriterBase::writeData(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data) { + Offset += IHexRecord::getLineLength(Data.size()); +} + +void IHexSectionWriterBase::visit(const Section &Sec) { + writeSection(&Sec, Sec.Contents); +} + +void IHexSectionWriterBase::visit(const OwnedDataSection &Sec) { + writeSection(&Sec, Sec.Data); +} + +void IHexSectionWriterBase::visit(const StringTableSection &Sec) { + // Check that sizer has already done its work + assert(Sec.Size == Sec.StrTabBuilder.getSize()); + // We are free to pass an invalid pointer to writeSection as long + // as we don't actually write any data. The real writer class has + // to override this method . + writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)}); +} + +void IHexSectionWriterBase::visit(const DynamicRelocationSection &Sec) { + writeSection(&Sec, Sec.Contents); +} + +void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data) { + IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data); + memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size()); + Offset += HexData.size(); +} + +void IHexSectionWriter::visit(const StringTableSection &Sec) { + assert(Sec.Size == Sec.StrTabBuilder.getSize()); + std::vector<uint8_t> Data(Sec.Size); + Sec.StrTabBuilder.write(Data.data()); + writeSection(&Sec, Data); } void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); } @@ -144,8 +394,7 @@ void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); } void Section::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } void SectionWriter::visit(const OwnedDataSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - llvm::copy(Sec.Data, Buf); + llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset); } static const std::vector<uint8_t> ZlibGnuMagic = {'Z', 'L', 'I', 'B'}; @@ -161,8 +410,7 @@ getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) { const bool IsGnuDebug = isDataGnuCompressed(Data); const uint64_t DecompressedSize = IsGnuDebug - ? support::endian::read64be(reinterpret_cast<const uint64_t *>( - Data.data() + ZlibGnuMagic.size())) + ? support::endian::read64be(Data.data() + ZlibGnuMagic.size()) : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size; const uint64_t DecompressedAlign = IsGnuDebug ? 1 @@ -174,13 +422,6 @@ getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) { template <class ELFT> void ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - - if (!zlib::isAvailable()) { - std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf); - return; - } - const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData) ? (ZlibGnuMagic.size() + sizeof(Sec.Size)) : sizeof(Elf_Chdr_Impl<ELFT>); @@ -194,11 +435,12 @@ void ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) { static_cast<size_t>(Sec.Size))) reportError(Sec.Name, std::move(E)); + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); } void BinarySectionWriter::visit(const DecompressedSection &Sec) { - error("Cannot write compressed section '" + Sec.Name + "' "); + error("cannot write compressed section '" + Sec.Name + "' "); } void DecompressedSection::accept(SectionVisitor &Visitor) const { @@ -217,15 +459,22 @@ void OwnedDataSection::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } +void OwnedDataSection::appendHexData(StringRef HexData) { + assert((HexData.size() & 1) == 0); + while (!HexData.empty()) { + Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2))); + HexData = HexData.drop_front(2); + } + Size = Data.size(); +} + void BinarySectionWriter::visit(const CompressedSection &Sec) { - error("Cannot write compressed section '" + Sec.Name + "' "); + error("cannot write compressed section '" + Sec.Name + "' "); } template <class ELFT> void ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) { - uint8_t *Buf = Out.getBufferStart(); - Buf += Sec.Offset; - + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; if (Sec.CompressionType == DebugCompressionType::None) { std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf); return; @@ -255,12 +504,6 @@ CompressedSection::CompressedSection(const SectionBase &Sec, DebugCompressionType CompressionType) : SectionBase(Sec), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { - - if (!zlib::isAvailable()) { - CompressionType = DebugCompressionType::None; - return; - } - if (Error E = zlib::compress( StringRef(reinterpret_cast<const char *>(OriginalData.data()), OriginalData.size()), @@ -299,16 +542,16 @@ void CompressedSection::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } -void StringTableSection::addString(StringRef Name) { - StrTabBuilder.add(Name); - Size = StrTabBuilder.getSize(); -} +void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); } uint32_t StringTableSection::findIndex(StringRef Name) const { return StrTabBuilder.getOffset(Name); } -void StringTableSection::finalize() { StrTabBuilder.finalize(); } +void StringTableSection::prepareForLayout() { + StrTabBuilder.finalize(); + Size = StrTabBuilder.getSize(); +} void SectionWriter::visit(const StringTableSection &Sec) { Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset); @@ -325,8 +568,7 @@ void StringTableSection::accept(MutableSectionVisitor &Visitor) { template <class ELFT> void ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) { uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - auto *IndexesBuffer = reinterpret_cast<Elf_Word *>(Buf); - llvm::copy(Sec.Indexes, IndexesBuffer); + llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf)); } void SectionIndexSection::initialize(SectionTableRef SecTable) { @@ -355,6 +597,11 @@ static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) { case SHN_COMMON: return true; } + + if (Machine == EM_AMDGPU) { + return Index == SHN_AMDGPU_LDS; + } + if (Machine == EM_HEXAGON) { switch (Index) { case SHN_HEXAGON_SCOMMON: @@ -376,21 +623,17 @@ uint16_t Symbol::getShndx() const { return SHN_XINDEX; return DefinedIn->Index; } - switch (ShndxType) { - // This means that we don't have a defined section but we do need to - // output a legitimate section index. - case SYMBOL_SIMPLE_INDEX: + + if (ShndxType == SYMBOL_SIMPLE_INDEX) { + // This means that we don't have a defined section but we do need to + // output a legitimate section index. return SHN_UNDEF; - case SYMBOL_ABS: - case SYMBOL_COMMON: - case SYMBOL_HEXAGON_SCOMMON: - case SYMBOL_HEXAGON_SCOMMON_2: - case SYMBOL_HEXAGON_SCOMMON_4: - case SYMBOL_HEXAGON_SCOMMON_8: - case SYMBOL_XINDEX: - return static_cast<uint16_t>(ShndxType); } - llvm_unreachable("Symbol with invalid ShndxType encountered"); + + assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON || + (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) || + (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS)); + return static_cast<uint16_t>(ShndxType); } bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; } @@ -404,7 +647,7 @@ void SymbolTableSection::assignIndices() { void SymbolTableSection::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) { Symbol Sym; Sym.Name = Name.str(); Sym.Binding = Bind; @@ -420,21 +663,28 @@ void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, } Sym.Value = Value; Sym.Visibility = Visibility; - Sym.Size = Size; + Sym.Size = SymbolSize; Sym.Index = Symbols.size(); Symbols.emplace_back(llvm::make_unique<Symbol>(Sym)); Size += this->EntrySize; } -void SymbolTableSection::removeSectionReferences(const SectionBase *Sec) { - if (SectionIndexTable == Sec) +Error SymbolTableSection::removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(SectionIndexTable)) SectionIndexTable = nullptr; - if (SymbolNames == Sec) { - error("String table " + SymbolNames->Name + - " cannot be removed because it is referenced by the symbol table " + - this->Name); + if (ToRemove(SymbolNames)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "string table '%s' cannot be removed because it is " + "referenced by the symbol table '%s'", + SymbolNames->Name.data(), this->Name.data()); + SymbolNames = nullptr; } - removeSymbols([Sec](const Symbol &Sym) { return Sym.DefinedIn == Sec; }); + return removeSymbols( + [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); }); } void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) { @@ -446,7 +696,7 @@ void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) { assignIndices(); } -void SymbolTableSection::removeSymbols( +Error SymbolTableSection::removeSymbols( function_ref<bool(const Symbol &)> ToRemove) { Symbols.erase( std::remove_if(std::begin(Symbols) + 1, std::end(Symbols), @@ -454,6 +704,14 @@ void SymbolTableSection::removeSymbols( std::end(Symbols)); Size = Symbols.size() * EntrySize; assignIndices(); + return Error::success(); +} + +void SymbolTableSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + for (std::unique_ptr<Symbol> &Sym : Symbols) + if (SectionBase *To = FromTo.lookup(Sym->DefinedIn)) + Sym->DefinedIn = To; } void SymbolTableSection::initialize(SectionTableRef SecTable) { @@ -467,40 +725,50 @@ void SymbolTableSection::initialize(SectionTableRef SecTable) { } void SymbolTableSection::finalize() { - // Make sure SymbolNames is finalized before getting name indexes. - SymbolNames->finalize(); - uint32_t MaxLocalIndex = 0; - for (auto &Sym : Symbols) { - Sym->NameIndex = SymbolNames->findIndex(Sym->Name); + for (std::unique_ptr<Symbol> &Sym : Symbols) { + Sym->NameIndex = + SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name); if (Sym->Binding == STB_LOCAL) MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index); } // Now we need to set the Link and Info fields. - Link = SymbolNames->Index; + Link = SymbolNames == nullptr ? 0 : SymbolNames->Index; Info = MaxLocalIndex + 1; } void SymbolTableSection::prepareForLayout() { - // Add all potential section indexes before file layout so that the section - // index section has the approprite size. - if (SectionIndexTable != nullptr) { - for (const auto &Sym : Symbols) { - if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE) - SectionIndexTable->addIndex(Sym->DefinedIn->Index); - else - SectionIndexTable->addIndex(SHN_UNDEF); - } - } + // Reserve proper amount of space in section index table, so we can + // layout sections correctly. We will fill the table with correct + // indexes later in fillShdnxTable. + if (SectionIndexTable) + SectionIndexTable->reserve(Symbols.size()); + // Add all of our strings to SymbolNames so that SymbolNames has the right // size before layout is decided. - for (auto &Sym : Symbols) - SymbolNames->addString(Sym->Name); + // If the symbol names section has been removed, don't try to add strings to + // the table. + if (SymbolNames != nullptr) + for (std::unique_ptr<Symbol> &Sym : Symbols) + SymbolNames->addString(Sym->Name); +} + +void SymbolTableSection::fillShndxTable() { + if (SectionIndexTable == nullptr) + return; + // Fill section index table with real section indexes. This function must + // be called after assignOffsets. + for (const std::unique_ptr<Symbol> &Sym : Symbols) { + if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE) + SectionIndexTable->addIndex(Sym->DefinedIn->Index); + else + SectionIndexTable->addIndex(SHN_UNDEF); + } } const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const { if (Symbols.size() <= Index) - error("Invalid symbol index: " + Twine(Index)); + error("invalid symbol index: " + Twine(Index)); return Symbols[Index].get(); } @@ -511,11 +779,9 @@ Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) { template <class ELFT> void ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) { - uint8_t *Buf = Out.getBufferStart(); - Buf += Sec.Offset; - Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Buf); + Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset); // Loop though symbols setting each entry of the symbol table. - for (auto &Symbol : Sec.Symbols) { + for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) { Sym->st_name = Symbol->NameIndex; Sym->st_value = Symbol->Value; Sym->st_size = Symbol->Size; @@ -535,16 +801,31 @@ void SymbolTableSection::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } -template <class SymTabType> -void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences( - const SectionBase *Sec) { - if (Symbols == Sec) { - error("Symbol table " + Symbols->Name + - " cannot be removed because it is " - "referenced by the relocation " - "section " + - this->Name); +Error RelocationSection::removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(Symbols)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "symbol table '%s' cannot be removed because it is " + "referenced by the relocation section '%s'", + Symbols->Name.data(), this->Name.data()); + Symbols = nullptr; } + + for (const Relocation &R : Relocations) { + if (!R.RelocSymbol->DefinedIn || !ToRemove(R.RelocSymbol->DefinedIn)) + continue; + return createStringError(llvm::errc::invalid_argument, + "section '%s' cannot be removed: (%s+0x%" PRIx64 + ") has relocation against symbol '%s'", + R.RelocSymbol->DefinedIn->Name.data(), + SecToApplyRel->Name.data(), R.Offset, + R.RelocSymbol->Name.c_str()); + } + + return Error::success(); } template <class SymTabType> @@ -609,12 +890,15 @@ void RelocationSection::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } -void RelocationSection::removeSymbols( +Error RelocationSection::removeSymbols( function_ref<bool(const Symbol &)> ToRemove) { for (const Relocation &Reloc : Relocations) if (ToRemove(*Reloc.RelocSymbol)) - error("not stripping symbol '" + Reloc.RelocSymbol->Name + - "' because it is named in a relocation"); + return createStringError( + llvm::errc::invalid_argument, + "not stripping symbol '%s' because it is named in a relocation", + Reloc.RelocSymbol->Name.data()); + return Error::success(); } void RelocationSection::markSymbols() { @@ -622,9 +906,15 @@ void RelocationSection::markSymbols() { Reloc.RelocSymbol->Referenced = true; } +void RelocationSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + // Update the target section if it was replaced. + if (SectionBase *To = FromTo.lookup(SecToApplyRel)) + SecToApplyRel = To; +} + void SectionWriter::visit(const DynamicRelocationSection &Sec) { - llvm::copy(Sec.Contents, - Out.getBufferStart() + Sec.Offset); + llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); } void DynamicRelocationSection::accept(SectionVisitor &Visitor) const { @@ -635,13 +925,38 @@ void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); } -void Section::removeSectionReferences(const SectionBase *Sec) { - if (LinkSection == Sec) { - error("Section " + LinkSection->Name + - " cannot be removed because it is " - "referenced by the section " + - this->Name); +Error DynamicRelocationSection::removeSectionReferences( + bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(Symbols)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "symbol table '%s' cannot be removed because it is " + "referenced by the relocation section '%s'", + Symbols->Name.data(), this->Name.data()); + Symbols = nullptr; + } + + // SecToApplyRel contains a section referenced by sh_info field. It keeps + // a section to which the relocation section applies. When we remove any + // sections we also remove their relocation sections. Since we do that much + // earlier, this assert should never be triggered. + assert(!SecToApplyRel || !ToRemove(SecToApplyRel)); + return Error::success(); +} + +Error Section::removeSectionReferences( + bool AllowBrokenDependency, + function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(LinkSection)) { + if (!AllowBrokenDependency) + return createStringError(llvm::errc::invalid_argument, + "section '%s' cannot be removed because it is " + "referenced by the section '%s'", + LinkSection->Name.data(), this->Name.data()); + LinkSection = nullptr; } + return Error::success(); } void GroupSection::finalize() { @@ -649,13 +964,13 @@ void GroupSection::finalize() { this->Link = SymTab->Index; } -void GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { - if (ToRemove(*Sym)) { - error("Symbol " + Sym->Name + - " cannot be removed because it is " - "referenced by the section " + - this->Name + "[" + Twine(this->Index) + "]"); - } +Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { + if (ToRemove(*Sym)) + return createStringError(llvm::errc::invalid_argument, + "symbol '%s' cannot be removed because it is " + "referenced by the section '%s[%d]'", + Sym->Name.data(), this->Name.data(), this->Index); + return Error::success(); } void GroupSection::markSymbols() { @@ -663,19 +978,26 @@ void GroupSection::markSymbols() { Sym->Referenced = true; } +void GroupSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + for (SectionBase *&Sec : GroupMembers) + if (SectionBase *To = FromTo.lookup(Sec)) + Sec = To; +} + void Section::initialize(SectionTableRef SecTable) { - if (Link != ELF::SHN_UNDEF) { - LinkSection = - SecTable.getSection(Link, "Link field value " + Twine(Link) + - " in section " + Name + " is invalid"); - if (LinkSection->Type == ELF::SHT_SYMTAB) - LinkSection = nullptr; - } + if (Link == ELF::SHN_UNDEF) + return; + LinkSection = + SecTable.getSection(Link, "Link field value " + Twine(Link) + + " in section " + Name + " is invalid"); + if (LinkSection->Type == ELF::SHT_SYMTAB) + LinkSection = nullptr; } void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; } -void GnuDebugLinkSection::init(StringRef File, StringRef Data) { +void GnuDebugLinkSection::init(StringRef File) { FileName = sys::path::filename(File); // The format for the .gnu_debuglink starts with the file name and is // followed by a null terminator and then the CRC32 of the file. The CRC32 @@ -690,31 +1012,21 @@ void GnuDebugLinkSection::init(StringRef File, StringRef Data) { // establish the order that sections should go in. By using the maximum // possible offset we cause this section to wind up at the end. OriginalOffset = std::numeric_limits<uint64_t>::max(); - JamCRC CRC; - CRC.update(ArrayRef<char>(Data.data(), Data.size())); - // The CRC32 value needs to be complemented because the JamCRC dosn't - // finalize the CRC32 value. It also dosn't negate the initial CRC32 value - // but it starts by default at 0xFFFFFFFF which is the complement of zero. - CRC32 = ~CRC.getCRC(); } -GnuDebugLinkSection::GnuDebugLinkSection(StringRef File) : FileName(File) { - // Read in the file to compute the CRC of it. - auto DebugOrErr = MemoryBuffer::getFile(File); - if (!DebugOrErr) - error("'" + File + "': " + DebugOrErr.getError().message()); - auto Debug = std::move(*DebugOrErr); - init(File, Debug->getBuffer()); +GnuDebugLinkSection::GnuDebugLinkSection(StringRef File, + uint32_t PrecomputedCRC) + : FileName(File), CRC32(PrecomputedCRC) { + init(File); } template <class ELFT> void ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) { - auto Buf = Out.getBufferStart() + Sec.Offset; - char *File = reinterpret_cast<char *>(Buf); + unsigned char *Buf = Out.getBufferStart() + Sec.Offset; Elf_Word *CRC = reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word)); *CRC = Sec.CRC32; - llvm::copy(Sec.FileName, File); + llvm::copy(Sec.FileName, Buf); } void GnuDebugLinkSection::accept(SectionVisitor &Visitor) const { @@ -730,7 +1042,7 @@ void ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) { ELF::Elf32_Word *Buf = reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset); *Buf++ = Sec.FlagWord; - for (const auto *S : Sec.GroupMembers) + for (SectionBase *S : Sec.GroupMembers) support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index); } @@ -750,6 +1062,20 @@ static bool sectionWithinSegment(const SectionBase &Section, // segments and ensures that the section "belongs" to the second segment and // not the first. uint64_t SecSize = Section.Size ? Section.Size : 1; + + if (Section.Type == SHT_NOBITS) { + if (!(Section.Flags & SHF_ALLOC)) + return false; + + bool SectionIsTLS = Section.Flags & SHF_TLS; + bool SegmentIsTLS = Segment.Type == PT_TLS; + if (SectionIsTLS != SegmentIsTLS) + return false; + + return Segment.VAddr <= Section.Addr && + Segment.VAddr + Segment.MemSize >= Section.Addr + SecSize; + } + return Segment.Offset <= Section.OriginalOffset && Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize; } @@ -781,7 +1107,7 @@ static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) { return A->Index < B->Index; } -void BinaryELFBuilder::initFileHeader() { +void BasicELFBuilder::initFileHeader() { Obj->Flags = 0x0; Obj->Type = ET_REL; Obj->OSABI = ELFOSABI_NONE; @@ -791,9 +1117,9 @@ void BinaryELFBuilder::initFileHeader() { Obj->Version = 1; } -void BinaryELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; } +void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; } -StringTableSection *BinaryELFBuilder::addStrTab() { +StringTableSection *BasicELFBuilder::addStrTab() { auto &StrTab = Obj->addSection<StringTableSection>(); StrTab.Name = ".strtab"; @@ -801,7 +1127,7 @@ StringTableSection *BinaryELFBuilder::addStrTab() { return &StrTab; } -SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) { +SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) { auto &SymTab = Obj->addSection<SymbolTableSection>(); SymTab.Name = ".symtab"; @@ -814,6 +1140,11 @@ SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) { return &SymTab; } +void BasicELFBuilder::initSections() { + for (auto &Section : Obj->sections()) + Section.initialize(Obj->sections()); +} + void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { auto Data = ArrayRef<uint8_t>( reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()), @@ -837,25 +1168,75 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0); } -void BinaryELFBuilder::initSections() { - for (auto &Section : Obj->sections()) { - Section.initialize(Obj->sections()); +std::unique_ptr<Object> BinaryELFBuilder::build() { + initFileHeader(); + initHeaderSegment(); + + SymbolTableSection *SymTab = addSymTab(addStrTab()); + initSections(); + addData(SymTab); + + return std::move(Obj); +} + +// Adds sections from IHEX data file. Data should have been +// fully validated by this time. +void IHexELFBuilder::addDataSections() { + OwnedDataSection *Section = nullptr; + uint64_t SegmentAddr = 0, BaseAddr = 0; + uint32_t SecNo = 1; + + for (const IHexRecord &R : Records) { + uint64_t RecAddr; + switch (R.Type) { + case IHexRecord::Data: + // Ignore empty data records + if (R.HexData.empty()) + continue; + RecAddr = R.Addr + SegmentAddr + BaseAddr; + if (!Section || Section->Addr + Section->Size != RecAddr) + // OriginalOffset field is only used to sort section properly, so + // instead of keeping track of real offset in IHEX file, we use + // section number. + Section = &Obj->addSection<OwnedDataSection>( + ".sec" + std::to_string(SecNo++), RecAddr, + ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo); + Section->appendHexData(R.HexData); + break; + case IHexRecord::EndOfFile: + break; + case IHexRecord::SegmentAddr: + // 20-bit segment address. + SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4; + break; + case IHexRecord::StartAddr80x86: + case IHexRecord::StartAddr: + Obj->Entry = checkedGetHex<uint32_t>(R.HexData); + assert(Obj->Entry <= 0xFFFFFU); + break; + case IHexRecord::ExtendedAddr: + // 16-31 bits of linear base address + BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16; + break; + default: + llvm_unreachable("unknown record type"); + } } } -std::unique_ptr<Object> BinaryELFBuilder::build() { +std::unique_ptr<Object> IHexELFBuilder::build() { initFileHeader(); initHeaderSegment(); StringTableSection *StrTab = addStrTab(); - SymbolTableSection *SymTab = addSymTab(StrTab); + addSymTab(StrTab); initSections(); - addData(SymTab); + addDataSections(); return std::move(Obj); } template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { - for (auto &Parent : Obj.segments()) { + for (Segment &Parent : Obj.segments()) { // Every segment will overlap with itself but we don't want a segment to // be it's own parent so we avoid that situation. if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) { @@ -870,23 +1251,43 @@ template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { } } -template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { +template <class ELFT> void ELFBuilder<ELFT>::findEhdrOffset() { + if (!ExtractPartition) + return; + + for (const SectionBase &Section : Obj.sections()) { + if (Section.Type == SHT_LLVM_PART_EHDR && + Section.Name == *ExtractPartition) { + EhdrOffset = Section.Offset; + return; + } + } + error("could not find partition named '" + *ExtractPartition + "'"); +} + +template <class ELFT> +void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) { uint32_t Index = 0; - for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { - ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset, + for (const auto &Phdr : unwrapOrError(HeadersFile.program_headers())) { + if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize()) + error("program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) + + " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) + + " goes past the end of the file"); + + ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset, (size_t)Phdr.p_filesz}; Segment &Seg = Obj.addSegment(Data); Seg.Type = Phdr.p_type; Seg.Flags = Phdr.p_flags; - Seg.OriginalOffset = Phdr.p_offset; - Seg.Offset = Phdr.p_offset; + Seg.OriginalOffset = Phdr.p_offset + EhdrOffset; + Seg.Offset = Phdr.p_offset + EhdrOffset; Seg.VAddr = Phdr.p_vaddr; Seg.PAddr = Phdr.p_paddr; Seg.FileSize = Phdr.p_filesz; Seg.MemSize = Phdr.p_memsz; Seg.Align = Phdr.p_align; Seg.Index = Index++; - for (auto &Section : Obj.sections()) { + for (SectionBase &Section : Obj.sections()) { if (sectionWithinSegment(Section, Seg)) { Seg.addSection(&Section); if (!Section.ParentSegment || @@ -899,8 +1300,9 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { auto &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Index = Index++; + ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset; - const auto &Ehdr = *ElfFile.getHeader(); + const auto &Ehdr = *HeadersFile.getHeader(); auto &PrHdr = Obj.ProgramHdrSegment; PrHdr.Type = PT_PHDR; PrHdr.Flags = 0; @@ -908,7 +1310,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { // Whereas this works automatically for ElfHdr, here OriginalOffset is // always non-zero and to ensure the equation we assign the same value to // VAddr as well. - PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = Ehdr.e_phoff; + PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff; PrHdr.PAddr = 0; PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum; // The spec requires us to naturally align all the fields. @@ -917,7 +1319,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { // Now we do an O(n^2) loop through the segments in order to match up // segments. - for (auto &Child : Obj.segments()) + for (Segment &Child : Obj.segments()) setParentSegment(Child); setParentSegment(ElfHdr); setParentSegment(PrHdr); @@ -925,22 +1327,25 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { template <class ELFT> void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) { - auto SecTable = Obj.sections(); + if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0) + error("invalid alignment " + Twine(GroupSec->Align) + " of group section '" + + GroupSec->Name + "'"); + SectionTableRef SecTable = Obj.sections(); auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( GroupSec->Link, - "Link field value " + Twine(GroupSec->Link) + " in section " + - GroupSec->Name + " is invalid", - "Link field value " + Twine(GroupSec->Link) + " in section " + - GroupSec->Name + " is not a symbol table"); - auto Sym = SymTab->getSymbolByIndex(GroupSec->Info); + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is invalid", + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is not a symbol table"); + Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info); if (!Sym) - error("Info field value " + Twine(GroupSec->Info) + " in section " + - GroupSec->Name + " is not a valid symbol index"); + error("info field value '" + Twine(GroupSec->Info) + "' in section '" + + GroupSec->Name + "' is not a valid symbol index"); GroupSec->setSymTab(SymTab); GroupSec->setSymbol(Sym); if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) || GroupSec->Contents.empty()) - error("The content of the section " + GroupSec->Name + " is malformed"); + error("the content of the section " + GroupSec->Name + " is malformed"); const ELF::Elf32_Word *Word = reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data()); const ELF::Elf32_Word *End = @@ -949,8 +1354,8 @@ void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) { for (; Word != End; ++Word) { uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word); GroupSec->addMember(SecTable.getSection( - Index, "Group member index " + Twine(Index) + " in section " + - GroupSec->Name + " is invalid")); + Index, "group member index " + Twine(Index) + " in section '" + + GroupSec->Name + "' is invalid")); } } @@ -967,31 +1372,31 @@ void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { if (Sym.st_shndx == SHN_XINDEX) { if (SymTab->getShndxTable() == nullptr) - error("Symbol '" + Name + - "' has index SHN_XINDEX but no SHT_SYMTAB_SHNDX section exists."); + error("symbol '" + Name + + "' has index SHN_XINDEX but no SHT_SYMTAB_SHNDX section exists"); if (ShndxData.data() == nullptr) { const Elf_Shdr &ShndxSec = *unwrapOrError(ElfFile.getSection(SymTab->getShndxTable()->Index)); ShndxData = unwrapOrError( ElfFile.template getSectionContentsAsArray<Elf_Word>(&ShndxSec)); if (ShndxData.size() != Symbols.size()) - error("Symbol section index table does not have the same number of " - "entries as the symbol table."); + error("symbol section index table does not have the same number of " + "entries as the symbol table"); } Elf_Word Index = ShndxData[&Sym - Symbols.begin()]; DefSection = Obj.sections().getSection( Index, - "Symbol '" + Name + "' has invalid section index " + Twine(Index)); + "symbol '" + Name + "' has invalid section index " + Twine(Index)); } else if (Sym.st_shndx >= SHN_LORESERVE) { if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) { error( - "Symbol '" + Name + + "symbol '" + Name + "' has unsupported value greater than or equal to SHN_LORESERVE: " + Twine(Sym.st_shndx)); } } else if (Sym.st_shndx != SHN_UNDEF) { DefSection = Obj.sections().getSection( - Sym.st_shndx, "Symbol '" + Name + + Sym.st_shndx, "symbol '" + Name + "' is defined has invalid section index " + Twine(Sym.st_shndx)); } @@ -1086,7 +1491,8 @@ SectionBase &ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) { default: { Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); - if (isDataGnuCompressed(Data) || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) { + StringRef Name = unwrapOrError(ElfFile.getSectionName(&Shdr)); + if (Name.startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) { uint64_t DecompressedSize, DecompressedAlign; std::tie(DecompressedSize, DecompressedAlign) = getDecompressedSizeAndAlignment<ELFT>(Data); @@ -1123,7 +1529,9 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset, (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size); } +} +template <class ELFT> void ELFBuilder<ELFT>::readSections() { // If a section index table exists we'll need to initialize it before we // initialize the symbol table because the symbol table might need to // reference it. @@ -1157,11 +1565,34 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { initGroupSection(GroupSec); } } + + uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; + if (ShstrIndex == SHN_XINDEX) + ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; + + if (ShstrIndex == SHN_UNDEF) + Obj.HadShdrs = false; + else + Obj.SectionNames = + Obj.sections().template getSectionOfType<StringTableSection>( + ShstrIndex, + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is invalid", + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is not a string table"); } template <class ELFT> void ELFBuilder<ELFT>::build() { - const auto &Ehdr = *ElfFile.getHeader(); + readSectionHeaders(); + findEhdrOffset(); + + // The ELFFile whose ELF headers and program headers are copied into the + // output file. Normally the same as ElfFile, but if we're extracting a + // loadable partition it will point to the partition's headers. + ELFFile<ELFT> HeadersFile = unwrapOrError(ELFFile<ELFT>::create(toStringRef( + {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset}))); + auto &Ehdr = *HeadersFile.getHeader(); Obj.OSABI = Ehdr.e_ident[EI_OSABI]; Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION]; Obj.Type = Ehdr.e_type; @@ -1170,25 +1601,8 @@ template <class ELFT> void ELFBuilder<ELFT>::build() { Obj.Entry = Ehdr.e_entry; Obj.Flags = Ehdr.e_flags; - readSectionHeaders(); - readProgramHeaders(); - - uint32_t ShstrIndex = Ehdr.e_shstrndx; - if (ShstrIndex == SHN_XINDEX) - ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; - - Obj.SectionNames = - Obj.sections().template getSectionOfType<StringTableSection>( - ShstrIndex, - "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + - " in elf header " + " is invalid", - "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + - " in elf header " + " is not a string table"); -} - -// A generic size function which computes sizes of any random access range. -template <class R> size_t size(R &&Range) { - return static_cast<size_t>(std::end(Range) - std::begin(Range)); + readSections(); + readProgramHeaders(HeadersFile); } Writer::~Writer() {} @@ -1199,31 +1613,61 @@ std::unique_ptr<Object> BinaryReader::create() const { return BinaryELFBuilder(MInfo.EMachine, MemBuf).build(); } +Expected<std::vector<IHexRecord>> IHexReader::parse() const { + SmallVector<StringRef, 16> Lines; + std::vector<IHexRecord> Records; + bool HasSections = false; + + MemBuf->getBuffer().split(Lines, '\n'); + Records.reserve(Lines.size()); + for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) { + StringRef Line = Lines[LineNo - 1].trim(); + if (Line.empty()) + continue; + + Expected<IHexRecord> R = IHexRecord::parse(Line); + if (!R) + return parseError(LineNo, R.takeError()); + if (R->Type == IHexRecord::EndOfFile) + break; + HasSections |= (R->Type == IHexRecord::Data); + Records.push_back(*R); + } + if (!HasSections) + return parseError(-1U, "no sections"); + + return std::move(Records); +} + +std::unique_ptr<Object> IHexReader::create() const { + std::vector<IHexRecord> Records = unwrapOrError(parse()); + return IHexELFBuilder(Records).build(); +} + std::unique_ptr<Object> ELFReader::create() const { auto Obj = llvm::make_unique<Object>(); if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { - ELFBuilder<ELF32LE> Builder(*O, *Obj); + ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { - ELFBuilder<ELF64LE> Builder(*O, *Obj); + ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { - ELFBuilder<ELF32BE> Builder(*O, *Obj); + ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { - ELFBuilder<ELF64BE> Builder(*O, *Obj); + ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } - error("Invalid file type"); + error("invalid file type"); } template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { - uint8_t *B = Buf.getBufferStart(); - Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(B); + Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart()); std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0); Ehdr.e_ident[EI_MAG0] = 0x7f; Ehdr.e_ident[EI_MAG1] = 'E'; @@ -1247,7 +1691,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0; Ehdr.e_flags = Obj.Flags; Ehdr.e_ehsize = sizeof(Elf_Ehdr); - if (WriteSectionHeaders && size(Obj.sections()) != 0) { + if (WriteSectionHeaders && Obj.sections().size() != 0) { Ehdr.e_shentsize = sizeof(Elf_Shdr); Ehdr.e_shoff = Obj.SHOffset; // """ @@ -1256,7 +1700,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { // number of section header table entries is contained in the sh_size field // of the section header at index 0. // """ - auto Shnum = size(Obj.sections()) + 1; + auto Shnum = Obj.sections().size() + 1; if (Shnum >= SHN_LORESERVE) Ehdr.e_shnum = 0; else @@ -1285,17 +1729,17 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdrs() { } template <class ELFT> void ELFWriter<ELFT>::writeShdrs() { - uint8_t *B = Buf.getBufferStart() + Obj.SHOffset; // This reference serves to write the dummy section header at the begining // of the file. It is not used for anything else - Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B); + Elf_Shdr &Shdr = + *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOffset); Shdr.sh_name = 0; Shdr.sh_type = SHT_NULL; Shdr.sh_flags = 0; Shdr.sh_addr = 0; Shdr.sh_offset = 0; // See writeEhdr for why we do this. - uint64_t Shnum = size(Obj.sections()) + 1; + uint64_t Shnum = Obj.sections().size() + 1; if (Shnum >= SHN_LORESERVE) Shdr.sh_size = Shnum; else @@ -1309,16 +1753,44 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() { Shdr.sh_addralign = 0; Shdr.sh_entsize = 0; - for (auto &Sec : Obj.sections()) + for (SectionBase &Sec : Obj.sections()) writeShdr(Sec); } template <class ELFT> void ELFWriter<ELFT>::writeSectionData() { - for (auto &Sec : Obj.sections()) - Sec.accept(*SecWriter); + for (SectionBase &Sec : Obj.sections()) + // Segments are responsible for writing their contents, so only write the + // section data if the section is not in a segment. Note that this renders + // sections in segments effectively immutable. + if (Sec.ParentSegment == nullptr) + Sec.accept(*SecWriter); +} + +template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { + for (Segment &Seg : Obj.segments()) { + uint8_t *B = Buf.getBufferStart() + Seg.Offset; + assert(Seg.FileSize == Seg.getContents().size() && + "Segment size must match contents size"); + std::memcpy(B, Seg.getContents().data(), Seg.FileSize); + } + + // Iterate over removed sections and overwrite their old data with zeroes. + for (auto &Sec : Obj.removedSections()) { + Segment *Parent = Sec.ParentSegment; + if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0) + continue; + uint64_t Offset = + Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset; + std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size); + } } -void Object::removeSections(std::function<bool(const SectionBase &)> ToRemove) { +template <class ELFT> +ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH) + : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {} + +Error Object::removeSections(bool AllowBrokenLinks, + std::function<bool(const SectionBase &)> ToRemove) { auto Iter = std::stable_partition( std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) { @@ -1339,32 +1811,55 @@ void Object::removeSections(std::function<bool(const SectionBase &)> ToRemove) { // Now make sure there are no remaining references to the sections that will // be removed. Sometimes it is impossible to remove a reference so we emit // an error here instead. + std::unordered_set<const SectionBase *> RemoveSections; + RemoveSections.reserve(std::distance(Iter, std::end(Sections))); for (auto &RemoveSec : make_range(Iter, std::end(Sections))) { for (auto &Segment : Segments) Segment->removeSection(RemoveSec.get()); - for (auto &KeepSec : make_range(std::begin(Sections), Iter)) - KeepSec->removeSectionReferences(RemoveSec.get()); + RemoveSections.insert(RemoveSec.get()); } - // Now finally get rid of them all togethor. + + // For each section that remains alive, we want to remove the dead references. + // This either might update the content of the section (e.g. remove symbols + // from symbol table that belongs to removed section) or trigger an error if + // a live section critically depends on a section being removed somehow + // (e.g. the removed section is referenced by a relocation). + for (auto &KeepSec : make_range(std::begin(Sections), Iter)) { + if (Error E = KeepSec->removeSectionReferences(AllowBrokenLinks, + [&RemoveSections](const SectionBase *Sec) { + return RemoveSections.find(Sec) != RemoveSections.end(); + })) + return E; + } + + // Transfer removed sections into the Object RemovedSections container for use + // later. + std::move(Iter, Sections.end(), std::back_inserter(RemovedSections)); + // Now finally get rid of them all together. Sections.erase(Iter, std::end(Sections)); + return Error::success(); } -void Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { - if (!SymbolTable) - return; - - for (const SecPtr &Sec : Sections) - Sec->removeSymbols(ToRemove); +Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { + if (SymbolTable) + for (const SecPtr &Sec : Sections) + if (Error E = Sec->removeSymbols(ToRemove)) + return E; + return Error::success(); } void Object::sortSections() { - // Put all sections in offset order. Maintain the ordering as closely as - // possible while meeting that demand however. - auto CompareSections = [](const SecPtr &A, const SecPtr &B) { + // Use stable_sort to maintain the original ordering as closely as possible. + llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) { + // Put SHT_GROUP sections first, since group section headers must come + // before the sections they contain. This also matches what GNU objcopy + // does. + if (A->Type != B->Type && + (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP)) + return A->Type == ELF::SHT_GROUP; + // For all other sections, sort by offset order. return A->OriginalOffset < B->OriginalOffset; - }; - std::stable_sort(std::begin(this->Sections), std::end(this->Sections), - CompareSections); + }); } static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { @@ -1382,14 +1877,13 @@ static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { // Orders segments such that if x = y->ParentSegment then y comes before x. static void orderSegments(std::vector<Segment *> &Segments) { - std::stable_sort(std::begin(Segments), std::end(Segments), - compareSegmentsByOffset); + llvm::stable_sort(Segments, compareSegmentsByOffset); } // This function finds a consistent layout for a list of segments starting from // an Offset. It assumes that Segments have been sorted by OrderSegments and // returns an Offset one past the end of the last segment. -static uint64_t LayoutSegments(std::vector<Segment *> &Segments, +static uint64_t layoutSegments(std::vector<Segment *> &Segments, uint64_t Offset) { assert(std::is_sorted(std::begin(Segments), std::end(Segments), compareSegmentsByOffset)); @@ -1398,20 +1892,20 @@ static uint64_t LayoutSegments(std::vector<Segment *> &Segments, // then it's acceptable, but not ideal, to simply move it to after the // segments. So we can simply layout segments one after the other accounting // for alignment. - for (auto &Segment : Segments) { + for (Segment *Seg : Segments) { // We assume that segments have been ordered by OriginalOffset and Index // such that a parent segment will always come before a child segment in // OrderedSegments. This means that the Offset of the ParentSegment should // already be set and we can set our offset relative to it. - if (Segment->ParentSegment != nullptr) { - auto Parent = Segment->ParentSegment; - Segment->Offset = - Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset; + if (Seg->ParentSegment != nullptr) { + Segment *Parent = Seg->ParentSegment; + Seg->Offset = + Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset; } else { - Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); - Segment->Offset = Offset; + Offset = alignToAddr(Offset, Seg->VAddr, Seg->Align); + Seg->Offset = Offset; } - Offset = std::max(Offset, Segment->Offset + Segment->FileSize); + Offset = std::max(Offset, Seg->Offset + Seg->FileSize); } return Offset; } @@ -1448,10 +1942,9 @@ static uint64_t layoutSections(Range Sections, uint64_t Offset) { } template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() { - auto &ElfHdr = Obj.ElfHdrSegment; + Segment &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Type = PT_PHDR; ElfHdr.Flags = 0; - ElfHdr.OriginalOffset = ElfHdr.Offset = 0; ElfHdr.VAddr = 0; ElfHdr.PAddr = 0; ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr); @@ -1463,7 +1956,7 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { // so that we know that anytime ->ParentSegment is set that segment has // already had its offset properly set. std::vector<Segment *> OrderedSegments; - for (auto &Segment : Obj.segments()) + for (Segment &Segment : Obj.segments()) OrderedSegments.push_back(&Segment); OrderedSegments.push_back(&Obj.ElfHdrSegment); OrderedSegments.push_back(&Obj.ProgramHdrSegment); @@ -1472,7 +1965,7 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { // Since the ELF Header (ElfHdrSegment) must be at the start of the file, // we start at offset 0. uint64_t Offset = 0; - Offset = LayoutSegments(OrderedSegments, Offset); + Offset = layoutSegments(OrderedSegments, Offset); Offset = layoutSections(Obj.sections(), Offset); // If we need to write the section header table out then we need to align the // Offset so that SHOffset is valid. @@ -1484,28 +1977,32 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const { // We already have the section header offset so we can calculate the total // size by just adding up the size of each section header. - auto NullSectionSize = WriteSectionHeaders ? sizeof(Elf_Shdr) : 0; - return Obj.SHOffset + size(Obj.sections()) * sizeof(Elf_Shdr) + - NullSectionSize; + if (!WriteSectionHeaders) + return Obj.SHOffset; + size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr. + return Obj.SHOffset + ShdrCount * sizeof(Elf_Shdr); } -template <class ELFT> void ELFWriter<ELFT>::write() { +template <class ELFT> Error ELFWriter<ELFT>::write() { + // Segment data must be written first, so that the ELF header and program + // header tables can overwrite it, if covered by a segment. + writeSegmentData(); writeEhdr(); writePhdrs(); writeSectionData(); if (WriteSectionHeaders) writeShdrs(); - if (auto E = Buf.commit()) - reportError(Buf.getName(), errorToErrorCode(std::move(E))); + return Buf.commit(); } -template <class ELFT> void ELFWriter<ELFT>::finalize() { +template <class ELFT> Error ELFWriter<ELFT>::finalize() { // It could happen that SectionNames has been removed and yet the user wants // a section header table output. We need to throw an error if a user tries // to do that. if (Obj.SectionNames == nullptr && WriteSectionHeaders) - error("Cannot write section header table because section header string " - "table was removed."); + return createStringError(llvm::errc::invalid_argument, + "cannot write section header table because " + "section header string table was removed"); Obj.sortSections(); @@ -1513,8 +2010,8 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() { // if we need large indexes or not. We can assign indexes first and check as // we go to see if we will actully need large indexes. bool NeedsLargeIndexes = false; - if (size(Obj.sections()) >= SHN_LORESERVE) { - auto Sections = Obj.sections(); + if (Obj.sections().size() >= SHN_LORESERVE) { + SectionTableRef Sections = Obj.sections(); NeedsLargeIndexes = std::any_of(Sections.begin() + SHN_LORESERVE, Sections.end(), [](const SectionBase &Sec) { return Sec.HasSymbol; }); @@ -1536,9 +2033,12 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() { // Since we don't need SectionIndexTable we should remove it and all // references to it. if (Obj.SectionIndexTable != nullptr) { - Obj.removeSections([this](const SectionBase &Sec) { - return &Sec == Obj.SectionIndexTable; - }); + // We do not support sections referring to the section index table. + if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/, + [this](const SectionBase &Sec) { + return &Sec == Obj.SectionIndexTable; + })) + return E; } } @@ -1567,15 +2067,23 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() { if (Obj.SymbolTable != nullptr) Obj.SymbolTable->prepareForLayout(); + // Now that all strings are added we want to finalize string table builders, + // because that affects section sizes which in turn affects section offsets. + for (SectionBase &Sec : Obj.sections()) + if (auto StrTab = dyn_cast<StringTableSection>(&Sec)) + StrTab->prepareForLayout(); + assignOffsets(); - // Finalize SectionNames first so that we can assign name indexes. - if (Obj.SectionNames != nullptr) - Obj.SectionNames->finalize(); + // layoutSections could have modified section indexes, so we need + // to fill the index table after assignOffsets. + if (Obj.SymbolTable != nullptr) + Obj.SymbolTable->fillShndxTable(); + // Finally now that all offsets and indexes have been set we can finalize any // remaining issues. uint64_t Offset = Obj.SHOffset + sizeof(Elf_Shdr); - for (auto &Section : Obj.sections()) { + for (SectionBase &Section : Obj.sections()) { Section.HeaderOffset = Offset; Offset += sizeof(Elf_Shdr); if (WriteSectionHeaders) @@ -1583,21 +2091,20 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() { Section.finalize(); } - Buf.allocate(totalSize()); + if (Error E = Buf.allocate(totalSize())) + return E; SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf); + return Error::success(); } -void BinaryWriter::write() { - for (auto &Section : Obj.sections()) { - if ((Section.Flags & SHF_ALLOC) == 0) - continue; - Section.accept(*SecWriter); - } - if (auto E = Buf.commit()) - reportError(Buf.getName(), errorToErrorCode(std::move(E))); +Error BinaryWriter::write() { + for (auto &Section : Obj.sections()) + if (Section.Flags & SHF_ALLOC) + Section.accept(*SecWriter); + return Buf.commit(); } -void BinaryWriter::finalize() { +Error BinaryWriter::finalize() { // TODO: Create a filter range to construct OrderedSegments from so that this // code can be deduped with assignOffsets above. This should also solve the // todo below for LayoutSections. @@ -1606,11 +2113,9 @@ void BinaryWriter::finalize() { // already had it's offset properly set. We only want to consider the segments // that will affect layout of allocated sections so we only add those. std::vector<Segment *> OrderedSegments; - for (auto &Section : Obj.sections()) { - if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) { + for (SectionBase &Section : Obj.sections()) + if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) OrderedSegments.push_back(Section.ParentSegment); - } - } // For binary output, we're going to use physical addresses instead of // virtual addresses, since a binary output is used for cases like ROM @@ -1622,8 +2127,7 @@ void BinaryWriter::finalize() { for (Segment *Seg : OrderedSegments) Seg->PAddr = Seg->VAddr; - std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments), - compareSegmentsByPAddr); + llvm::stable_sort(OrderedSegments, compareSegmentsByPAddr); // Because we add a ParentSegment for each section we might have duplicate // segments in OrderedSegments. If there were duplicates then LayoutSegments @@ -1638,8 +2142,8 @@ void BinaryWriter::finalize() { // our layout algorithm to proceed as expected while not writing out the gap // at the start. if (!OrderedSegments.empty()) { - auto Seg = OrderedSegments[0]; - auto Sec = Seg->firstSection(); + Segment *Seg = OrderedSegments[0]; + const SectionBase *Sec = Seg->firstSection(); auto Diff = Sec->OriginalOffset - Seg->OriginalOffset; Seg->OriginalOffset += Diff; // The size needs to be shrunk as well. @@ -1648,7 +2152,7 @@ void BinaryWriter::finalize() { // section. Seg->PAddr += Diff; uint64_t LowestPAddr = Seg->PAddr; - for (auto &Segment : OrderedSegments) { + for (Segment *Segment : OrderedSegments) { Segment->Offset = Segment->PAddr - LowestPAddr; Offset = std::max(Offset, Segment->Offset + Segment->FileSize); } @@ -1659,11 +2163,9 @@ void BinaryWriter::finalize() { // not hold. Then pass such a range to LayoutSections instead of constructing // AllocatedSections here. std::vector<SectionBase *> AllocatedSections; - for (auto &Section : Obj.sections()) { - if ((Section.Flags & SHF_ALLOC) == 0) - continue; - AllocatedSections.push_back(&Section); - } + for (SectionBase &Section : Obj.sections()) + if (Section.Flags & SHF_ALLOC) + AllocatedSections.push_back(&Section); layoutSections(make_pointee_range(AllocatedSections), Offset); // Now that every section has been laid out we just need to compute the total @@ -1671,13 +2173,117 @@ void BinaryWriter::finalize() { // LayoutSections, because we want to truncate the last segment to the end of // its last section, to match GNU objcopy's behaviour. TotalSize = 0; - for (const auto &Section : AllocatedSections) { + for (SectionBase *Section : AllocatedSections) if (Section->Type != SHT_NOBITS) TotalSize = std::max(TotalSize, Section->Offset + Section->Size); - } - Buf.allocate(TotalSize); + if (Error E = Buf.allocate(TotalSize)) + return E; SecWriter = llvm::make_unique<BinarySectionWriter>(Buf); + return Error::success(); +} + +bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs, + const SectionBase *Rhs) const { + return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) < + (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU); +} + +uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) { + IHexLineData HexData; + uint8_t Data[4] = {}; + // We don't write entry point record if entry is zero. + if (Obj.Entry == 0) + return 0; + + if (Obj.Entry <= 0xFFFFFU) { + Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF; + support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry), + support::big); + HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data); + } else { + support::endian::write(Data, static_cast<uint32_t>(Obj.Entry), + support::big); + HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data); + } + memcpy(Buf, HexData.data(), HexData.size()); + return HexData.size(); +} + +uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) { + IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {}); + memcpy(Buf, HexData.data(), HexData.size()); + return HexData.size(); +} + +Error IHexWriter::write() { + IHexSectionWriter Writer(Buf); + // Write sections. + for (const SectionBase *Sec : Sections) + Sec->accept(Writer); + + uint64_t Offset = Writer.getBufferOffset(); + // Write entry point address. + Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset); + // Write EOF. + Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset); + assert(Offset == TotalSize); + return Buf.commit(); +} + +Error IHexWriter::checkSection(const SectionBase &Sec) { + uint64_t Addr = sectionPhysicalAddr(&Sec); + if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1)) + return createStringError( + errc::invalid_argument, + "Section '%s' address range [0x%llx, 0x%llx] is not 32 bit", Sec.Name.c_str(), + Addr, Addr + Sec.Size - 1); + return Error::success(); +} + +Error IHexWriter::finalize() { + bool UseSegments = false; + auto ShouldWrite = [](const SectionBase &Sec) { + return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS); + }; + auto IsInPtLoad = [](const SectionBase &Sec) { + return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD; + }; + + // We can't write 64-bit addresses. + if (addressOverflows32bit(Obj.Entry)) + return createStringError(errc::invalid_argument, + "Entry point address 0x%llx overflows 32 bits.", + Obj.Entry); + + // If any section we're to write has segment then we + // switch to using physical addresses. Otherwise we + // use section virtual address. + for (auto &Section : Obj.sections()) + if (ShouldWrite(Section) && IsInPtLoad(Section)) { + UseSegments = true; + break; + } + + for (auto &Section : Obj.sections()) + if (ShouldWrite(Section) && (!UseSegments || IsInPtLoad(Section))) { + if (Error E = checkSection(Section)) + return E; + Sections.insert(&Section); + } + + IHexSectionWriterBase LengthCalc(Buf); + for (const SectionBase *Sec : Sections) + Sec->accept(LengthCalc); + + // We need space to write section records + StartAddress record + // (if start adress is not zero) + EndOfFile record. + TotalSize = LengthCalc.getBufferOffset() + + (Obj.Entry ? IHexRecord::getLineLength(4) : 0) + + IHexRecord::getLineLength(0); + if (Error E = Buf.allocate(TotalSize)) + return E; + return Error::success(); } template class ELFBuilder<ELF64LE>; |