summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-objcopy/ELF/Object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF/Object.cpp')
-rw-r--r--llvm/tools/llvm-objcopy/ELF/Object.cpp190
1 files changed, 113 insertions, 77 deletions
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp
index 0ff82f951b62..ba91d08e5540 100644
--- a/llvm/tools/llvm-objcopy/ELF/Object.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -29,16 +29,14 @@
#include <utility>
#include <vector>
-namespace llvm {
-namespace objcopy {
-namespace elf {
-
-using namespace object;
-using namespace ELF;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::objcopy::elf;
+using namespace llvm::object;
template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
- uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset +
- Seg.Index * sizeof(Elf_Phdr);
+ uint8_t *B = reinterpret_cast<uint8_t *>(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;
@@ -67,7 +65,8 @@ void SectionBase::replaceSectionReferences(
void SectionBase::onRemove() {}
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
- uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset;
+ uint8_t *B =
+ reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Sec.HeaderOffset;
Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
Shdr.sh_name = Sec.NameIndex;
Shdr.sh_type = Sec.Type;
@@ -191,7 +190,7 @@ template <class T> static T checkedGetHex(StringRef S) {
// 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) {
+static Iterator toHexStr(T X, Iterator It, size_t Len) {
// Fill range with '0'
std::fill(It, It + Len, '0');
@@ -220,13 +219,13 @@ IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
assert(Line.size());
auto Iter = Line.begin();
*Iter++ = ':';
- Iter = utohexstr(Data.size(), Iter, 2);
- Iter = utohexstr(Addr, Iter, 4);
- Iter = utohexstr(Type, Iter, 2);
+ Iter = toHexStr(Data.size(), Iter, 2);
+ Iter = toHexStr(Addr, Iter, 4);
+ Iter = toHexStr(Type, Iter, 2);
for (uint8_t X : Data)
- Iter = utohexstr(X, Iter, 2);
+ Iter = toHexStr(X, Iter, 2);
StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter));
- Iter = utohexstr(getChecksum(S), Iter, 2);
+ Iter = toHexStr(getChecksum(S), Iter, 2);
*Iter++ = '\r';
*Iter++ = '\n';
assert(Iter == Line.end());
@@ -474,7 +473,7 @@ Error ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
return createStringError(errc::invalid_argument,
"'" + Sec.Name + "': " + toString(std::move(Err)));
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
return Error::success();
@@ -519,7 +518,7 @@ Error BinarySectionWriter::visit(const CompressedSection &Sec) {
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
if (Sec.CompressionType == DebugCompressionType::None) {
std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
return Error::success();
@@ -624,7 +623,8 @@ void StringTableSection::prepareForLayout() {
}
Error SectionWriter::visit(const StringTableSection &Sec) {
- Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
+ Sec.StrTabBuilder.write(reinterpret_cast<uint8_t *>(Out.getBufferStart()) +
+ Sec.Offset);
return Error::success();
}
@@ -638,7 +638,7 @@ Error StringTableSection::accept(MutableSectionVisitor &Visitor) {
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
return Error::success();
}
@@ -979,7 +979,7 @@ static void writeRel(const RelRange &Relocations, T *Buf) {
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
if (Sec.Type == SHT_REL)
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf));
else
@@ -1069,6 +1069,12 @@ Error Section::removeSectionReferences(
void GroupSection::finalize() {
this->Info = Sym ? Sym->Index : 0;
this->Link = SymTab ? SymTab->Index : 0;
+ // Linker deduplication for GRP_COMDAT is based on Sym->Name. The local/global
+ // status is not part of the equation. If Sym is localized, the intention is
+ // likely to make the group fully localized. Drop GRP_COMDAT to suppress
+ // deduplication. See https://groups.google.com/g/generic-abi/c/2X6mR-s2zoc
+ if ((FlagWord & GRP_COMDAT) && Sym && Sym->Binding == STB_LOCAL)
+ this->FlagWord &= ~GRP_COMDAT;
}
Error GroupSection::removeSectionReferences(
@@ -1160,7 +1166,8 @@ GnuDebugLinkSection::GnuDebugLinkSection(StringRef File,
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
- unsigned char *Buf = Out.getBufferStart() + Sec.Offset;
+ unsigned char *Buf =
+ reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
Elf_Word *CRC =
reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
*CRC = Sec.CRC32;
@@ -1180,7 +1187,7 @@ template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) {
ELF::Elf32_Word *Buf =
reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset);
- *Buf++ = Sec.FlagWord;
+ support::endian::write32<ELFT::TargetEndianness>(Buf++, Sec.FlagWord);
for (SectionBase *S : Sec.GroupMembers)
support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index);
return Error::success();
@@ -1202,6 +1209,10 @@ static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) {
// not the first.
uint64_t SecSize = Sec.Size ? Sec.Size : 1;
+ // Ignore just added sections.
+ if (Sec.OriginalOffset == std::numeric_limits<uint64_t>::max())
+ return false;
+
if (Sec.Type == SHT_NOBITS) {
if (!(Sec.Flags & SHF_ALLOC))
return false;
@@ -1290,8 +1301,9 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
std::string SanitizedFilename = MemBuf->getBufferIdentifier().str();
- std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename),
- [](char C) { return !isalnum(C); }, '_');
+ std::replace_if(
+ std::begin(SanitizedFilename), std::end(SanitizedFilename),
+ [](char C) { return !isAlnum(C); }, '_');
Twine Prefix = Twine("_binary_") + SanitizedFilename;
SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection,
@@ -1505,7 +1517,8 @@ Error ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) {
reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data());
const ELF::Elf32_Word *End =
Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word);
- GroupSec->setFlagWord(*Word++);
+ GroupSec->setFlagWord(
+ support::endian::read32<ELFT::TargetEndianness>(Word++));
for (; Word != End; ++Word) {
uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word);
Expected<SectionBase *> Sec = SecTable.getSection(
@@ -1778,7 +1791,7 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSectionHeaders() {
Sec->OriginalIndex = Sec->Index;
Sec->OriginalData =
ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
- (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
+ (Shdr.sh_type == SHT_NOBITS) ? (size_t)0 : Shdr.sh_size);
}
return Error::success();
@@ -1971,7 +1984,7 @@ Expected<std::unique_ptr<Object>> ELFReader::create(bool EnsureSymtab) const {
}
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
- Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart());
+ 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';
@@ -2036,7 +2049,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
// 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 *>(Buf.getBufferStart() + Obj.SHOff);
+ *reinterpret_cast<Elf_Shdr *>(Buf->getBufferStart() + Obj.SHOff);
Shdr.sh_name = 0;
Shdr.sh_type = SHT_NULL;
Shdr.sh_flags = 0;
@@ -2076,7 +2089,7 @@ template <class ELFT> Error ELFWriter<ELFT>::writeSectionData() {
template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
for (Segment &Seg : Obj.segments()) {
size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size());
- std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(),
+ std::memcpy(Buf->getBufferStart() + Seg.Offset, Seg.getContents().data(),
Size);
}
@@ -2087,12 +2100,12 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
continue;
uint64_t Offset =
Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset;
- std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size);
+ std::memset(Buf->getBufferStart() + Offset, 0, Sec.Size);
}
}
template <class ELFT>
-ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH,
+ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
bool OnlyKeepDebug)
: Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
OnlyKeepDebug(OnlyKeepDebug) {}
@@ -2311,18 +2324,19 @@ static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments,
uint64_t HdrEnd) {
uint64_t MaxOffset = 0;
for (Segment *Seg : Segments) {
- // An empty segment contains no section (see sectionWithinSegment). If it
- // has a parent segment, copy the parent segment's offset field. This works
- // for empty PT_TLS. We don't handle empty segments without a parent for
- // now.
- if (Seg->ParentSegment != nullptr && Seg->MemSize == 0)
- Seg->Offset = Seg->ParentSegment->Offset;
-
- const SectionBase *FirstSec = Seg->firstSection();
- if (Seg->Type == PT_PHDR || !FirstSec)
+ if (Seg->Type == PT_PHDR)
continue;
- uint64_t Offset = FirstSec->Offset;
+ // The segment offset is generally the offset of the first section.
+ //
+ // For a segment containing no section (see sectionWithinSegment), if it has
+ // a parent segment, copy the parent segment's offset field. This works for
+ // empty PT_TLS. If no parent segment, use 0: the segment is not useful for
+ // debugging anyway.
+ const SectionBase *FirstSec = Seg->firstSection();
+ uint64_t Offset =
+ FirstSec ? FirstSec->Offset
+ : (Seg->ParentSegment ? Seg->ParentSegment->Offset : 0);
uint64_t FileSize = 0;
for (const SectionBase *Sec : Seg->Sections) {
uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size;
@@ -2409,7 +2423,11 @@ template <class ELFT> Error ELFWriter<ELFT>::write() {
return E;
if (WriteSectionHeaders)
writeShdrs();
- return Buf.commit();
+
+ // TODO: Implement direct writing to the output stream (without intermediate
+ // memory buffer Buf).
+ Out.write(Buf->getBufferStart(), Buf->getBufferSize());
+ return Error::success();
}
static Error removeUnneededSections(Object &Obj) {
@@ -2450,8 +2468,10 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
bool NeedsLargeIndexes = false;
if (Obj.sections().size() >= SHN_LORESERVE) {
SectionTableRef Sections = Obj.sections();
+ // Sections doesn't include the null section header, so account for this
+ // when skipping the first N sections.
NeedsLargeIndexes =
- any_of(drop_begin(Sections, SHN_LORESERVE),
+ any_of(drop_begin(Sections, SHN_LORESERVE - 1),
[](const SectionBase &Sec) { return Sec.HasSymbol; });
// TODO: handle case where only one section needs the large index table but
// only needs it because the large index table hasn't been removed yet.
@@ -2529,9 +2549,14 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
Sec.finalize();
}
- if (Error E = Buf.allocate(totalSize()))
- return E;
- SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);
+ size_t TotalSize = totalSize();
+ Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
+ if (!Buf)
+ return createStringError(errc::not_enough_memory,
+ "failed to allocate memory buffer of " +
+ Twine::utohexstr(TotalSize) + " bytes");
+
+ SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(*Buf);
return Error::success();
}
@@ -2540,7 +2565,10 @@ Error BinaryWriter::write() {
if (Error Err = Sec.accept(*SecWriter))
return Err;
- return Buf.commit();
+ // TODO: Implement direct writing to the output stream (without intermediate
+ // memory buffer Buf).
+ Out.write(Buf->getBufferStart(), Buf->getBufferSize());
+ return Error::success();
}
Error BinaryWriter::finalize() {
@@ -2553,7 +2581,7 @@ Error BinaryWriter::finalize() {
if (Sec.ParentSegment != nullptr)
Sec.Addr =
Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr;
- if (Sec.Size > 0)
+ if (Sec.Type != SHT_NOBITS && Sec.Size > 0)
MinAddr = std::min(MinAddr, Sec.Addr);
}
@@ -2568,9 +2596,12 @@ Error BinaryWriter::finalize() {
TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size);
}
- if (Error E = Buf.allocate(TotalSize))
- return E;
- SecWriter = std::make_unique<BinarySectionWriter>(Buf);
+ Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
+ if (!Buf)
+ return createStringError(errc::not_enough_memory,
+ "failed to allocate memory buffer of " +
+ Twine::utohexstr(TotalSize) + " bytes");
+ SecWriter = std::make_unique<BinarySectionWriter>(*Buf);
return Error::success();
}
@@ -2608,7 +2639,7 @@ uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
}
Error IHexWriter::write() {
- IHexSectionWriter Writer(Buf);
+ IHexSectionWriter Writer(*Buf);
// Write sections.
for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(Writer))
@@ -2616,11 +2647,17 @@ Error IHexWriter::write() {
uint64_t Offset = Writer.getBufferOffset();
// Write entry point address.
- Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);
+ Offset += writeEntryPointRecord(
+ reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Offset);
// Write EOF.
- Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);
+ Offset += writeEndOfFileRecord(
+ reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Offset);
assert(Offset == TotalSize);
- return Buf.commit();
+
+ // TODO: Implement direct writing to the output stream (without intermediate
+ // memory buffer Buf).
+ Out.write(Buf->getBufferStart(), Buf->getBufferSize());
+ return Error::success();
}
Error IHexWriter::checkSection(const SectionBase &Sec) {
@@ -2634,37 +2671,27 @@ Error IHexWriter::checkSection(const SectionBase &Sec) {
}
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.",
+ "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 (const SectionBase &Sec : Obj.sections())
- if (ShouldWrite(Sec) && IsInPtLoad(Sec)) {
- UseSegments = true;
- break;
- }
-
for (const SectionBase &Sec : Obj.sections())
- if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) {
+ if ((Sec.Flags & ELF::SHF_ALLOC) && Sec.Type != ELF::SHT_NOBITS &&
+ Sec.Size > 0) {
if (Error E = checkSection(Sec))
return E;
Sections.insert(&Sec);
}
- IHexSectionWriterBase LengthCalc(Buf);
+ std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
+ WritableMemoryBuffer::getNewMemBuffer(0);
+ if (!EmptyBuffer)
+ return createStringError(errc::not_enough_memory,
+ "failed to allocate memory buffer of 0 bytes");
+
+ IHexSectionWriterBase LengthCalc(*EmptyBuffer);
for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(LengthCalc))
return Err;
@@ -2674,11 +2701,20 @@ Error IHexWriter::finalize() {
TotalSize = LengthCalc.getBufferOffset() +
(Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
IHexRecord::getLineLength(0);
- if (Error E = Buf.allocate(TotalSize))
- return E;
+
+ Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
+ if (!Buf)
+ return createStringError(errc::not_enough_memory,
+ "failed to allocate memory buffer of " +
+ Twine::utohexstr(TotalSize) + " bytes");
+
return Error::success();
}
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
template class ELFBuilder<ELF64LE>;
template class ELFBuilder<ELF64BE>;
template class ELFBuilder<ELF32LE>;