mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-02 08:26:29 +00:00
[llvm-objcopy] Add support for static libraries
This diff adds support for handling static libraries to llvm-objcopy and llvm-strip. Test plan: make check-all Differential revision: https://reviews.llvm.org/D48413 llvm-svn: 336455
This commit is contained in:
parent
ac69f6b93e
commit
9383a6b0f8
99
test/tools/llvm-objcopy/basic-archive-copy.test
Normal file
99
test/tools/llvm-objcopy/basic-archive-copy.test
Normal file
@ -0,0 +1,99 @@
|
||||
# RUN: yaml2obj %s > %t
|
||||
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar crs %t.a %t
|
||||
# RUN: cp %t.a %t.copy.a
|
||||
# RUN: llvm-objcopy %t.a %t2.a
|
||||
# RUN: llvm-objcopy %t %t2
|
||||
# RUN: llvm-ar p %t2.a > %t3
|
||||
# RUN: cmp %t2 %t3
|
||||
|
||||
# RUN: llvm-readobj -sections %t2 | FileCheck %s
|
||||
# RUN: llvm-nm -print-armap %t.a | FileCheck --check-prefix=INDEX-TABLE %s
|
||||
# RUN: llvm-nm -print-armap %t2.a | FileCheck --check-prefix=INDEX-TABLE %s
|
||||
# Verify that llvm-objcopy has not modifed the input.
|
||||
# RUN: cmp %t.copy.a %t.a
|
||||
|
||||
# INDEX-TABLE: Archive map
|
||||
# INDEX-TABLE-NEXT: foo in
|
||||
|
||||
# RUN: rm -f %t.no.index.a
|
||||
# RUN: llvm-ar crS %t.no.index.a %t
|
||||
# RUN: llvm-objcopy %t.no.index.a %t2.no.index.a
|
||||
# RUN: llvm-ar p %t2.no.index.a > %t4
|
||||
|
||||
# RUN: llvm-nm -print-armap %t.no.index.a | FileCheck --check-prefix=NO-INDEX-TABLE %s
|
||||
# RUN: llvm-nm -print-armap %t2.no.index.a | FileCheck --check-prefix=NO-INDEX-TABLE %s
|
||||
# RUN: cmp %t2 %t4
|
||||
|
||||
# NO-INDEX-TABLE-NOT: Archive map
|
||||
# NO-INDEX-TABLE-NOT: foo in
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000010
|
||||
Size: 64
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: "00000000"
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x1004
|
||||
|
||||
# CHECK: Type: SHT_NULL
|
||||
|
||||
# CHECK: Name: .bss
|
||||
# CHECK-NEXT: Type: SHT_NOBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 64
|
||||
|
||||
# CHECK: Name: .text
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_EXECINSTR
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 4
|
||||
|
||||
# CHECK: Name: .symtab
|
||||
# CHECK-NEXT: Type: SHT_SYMTAB
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 48
|
||||
|
||||
# CHECK: Name: .strtab
|
||||
# CHECK-NEXT: Type: SHT_STRTAB
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 6
|
||||
|
||||
# CHECK: Name: .shstrtab
|
||||
# CHECK-NEXT: Type: SHT_STRTAB
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 38
|
@ -1,6 +1,6 @@
|
||||
# RUN: yaml2obj %s > %t
|
||||
# RUN: not llvm-objcopy %t no/such/dir 2>&1 | FileCheck %s
|
||||
# CHECK: failed to open no/such/dir
|
||||
# CHECK: failed to open no/such/dir:
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
|
@ -21,6 +21,12 @@
|
||||
# RUN: cmp %t2 %t-should-be-stripped
|
||||
# RUN: cmp %t %t-should-remain-the-same
|
||||
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar crs %t.a %t
|
||||
# RUN: llvm-objcopy --strip-all %t.a %t.a
|
||||
# RUN: llvm-ar p %t.a > %t6
|
||||
# RUN: cmp %t2 %t6
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
|
@ -21,6 +21,69 @@
|
||||
# RUN: llvm-strip -S %t6
|
||||
# RUN: cmp %t2 %t6
|
||||
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar crs %t.a %t
|
||||
# RUN: llvm-objcopy --strip-debug %t.a %t.a
|
||||
# RUN: llvm-ar p %t.a > %t7
|
||||
# RUN: cmp %t2 %t7
|
||||
|
||||
# Verify that an archive with multiple object files is handled correctly.
|
||||
# RUN: cp %t %t.duplicate
|
||||
# RUN: cp %t2 %t.duplicate.stripped
|
||||
# RUN: rm -f %t.multiple-stripped-obj.a
|
||||
# RUN: llvm-ar crs %t.multiple-stripped-obj.a %t2 %t.duplicate.stripped
|
||||
# RUN: rm -f %t.multiple-obj.a
|
||||
# RUN: llvm-ar crs %t.multiple-obj.a %t %t.duplicate
|
||||
# RUN: llvm-objcopy --strip-debug %t.multiple-obj.a %t.multiple-obj.stripped.a
|
||||
# RUN: llvm-ar p %t.multiple-stripped-obj.a > %t.multiple-stripped-obj.a.dump
|
||||
# RUN: llvm-ar p %t.multiple-obj.stripped.a > %t.multiple-obj.stripped.a.dump
|
||||
# RUN: cmp %t.multiple-stripped-obj.a.dump %t.multiple-obj.stripped.a.dump
|
||||
|
||||
# We can not use %t inside the patterns passed to FileCheck,
|
||||
# thus we have to use "recognizable" file names.
|
||||
# RUN: cp %t %t1.o
|
||||
# RUN: cp %s %t2.txt
|
||||
# RUN: cp %t %t3.o
|
||||
# RUN: rm -f %t.non-object.a
|
||||
# RUN: llvm-ar cr %t.non-object.a %t1.o %t2.txt %t3.o
|
||||
# RUN: llvm-ar t %t.non-object.a | FileCheck %s --check-prefix=NON-OBJECT-ARCHIVE-MEMBERS
|
||||
|
||||
# NON-OBJECT-ARCHIVE-MEMBERS: 1.o
|
||||
# NON-OBJECT-ARCHIVE-MEMBERS-NEXT: 2.txt
|
||||
# NON-OBJECT-ARCHIVE-MEMBERS-NEXT: 3.o
|
||||
|
||||
# RUN: cp %t.non-object.a %t.non-object.copy.a
|
||||
# RUN: not llvm-objcopy --strip-debug %t.non-object.a %t2.non-object.a 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
|
||||
|
||||
# BAD-FORMAT: The file was not recognized as a valid object file
|
||||
|
||||
# Verify that %t.non-object.a has not been modified.
|
||||
# RUN: cmp %t.non-object.a %t.non-object.copy.a
|
||||
|
||||
# RUN: rm -f %t.thin.a
|
||||
# Copy %t to %t.thin.archive.member to avoid changing %t directly.
|
||||
# RUN: cp %t %t.thin.archive.member
|
||||
# RUN: llvm-ar crsT %t.thin.a %t.thin.archive.member
|
||||
# RUN: llvm-objcopy --strip-debug %t.thin.a %t2.thin.a
|
||||
# RUN: cat %t.thin.a | FileCheck %s --check-prefix=VERIFY-THIN-ARCHIVE
|
||||
# RUN: cat %t2.thin.a | FileCheck %s --check-prefix=VERIFY-THIN-ARCHIVE
|
||||
|
||||
# VERIFY-THIN-ARCHIVE: !<thin>
|
||||
|
||||
# Verify that the member of a thin archive was properly modified.
|
||||
# RUN: cmp %t2 %t.thin.archive.member
|
||||
|
||||
# RUN: rm -f %t.non-object.thin.a
|
||||
# RUN: llvm-ar crsT %t.non-object.thin.a %t1.o %t2.txt %t3.o
|
||||
# RUN: cp %t.non-object.thin.a %t.non-object.thin.copy.a
|
||||
# RUN: not llvm-objcopy --strip-debug %t.non-object.thin.a %t.non-object.thin.a 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
|
||||
|
||||
# Verify that in the case of error thin archive and its memebers are not getting modified.
|
||||
# RUN: cmp %t.non-object.thin.a %t.non-object.thin.copy.a
|
||||
# RUN: cmp %t %t1.o
|
||||
# RUN: cmp %s %t2.txt
|
||||
# RUN: cmp %t %t3.o
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
|
@ -30,12 +30,43 @@ using namespace llvm;
|
||||
using namespace object;
|
||||
using namespace ELF;
|
||||
|
||||
Buffer::~Buffer() {}
|
||||
|
||||
void FileBuffer::allocate(size_t Size) {
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||
FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
|
||||
handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) {
|
||||
error("failed to open " + getName() + ": " + E.message());
|
||||
});
|
||||
Buf = std::move(*BufferOrErr);
|
||||
}
|
||||
|
||||
Error FileBuffer::commit() { return Buf->commit(); }
|
||||
|
||||
uint8_t *FileBuffer::getBufferStart() {
|
||||
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
}
|
||||
|
||||
void MemBuffer::allocate(size_t Size) {
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
|
||||
}
|
||||
|
||||
Error MemBuffer::commit() { return Error::success(); }
|
||||
|
||||
uint8_t *MemBuffer::getBufferStart() {
|
||||
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
|
||||
return std::move(Buf);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
|
||||
using Elf_Phdr = typename ELFT::Phdr;
|
||||
|
||||
uint8_t *Buf = BufPtr->getBufferStart();
|
||||
Buf += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr);
|
||||
Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(Buf);
|
||||
uint8_t *B = Buf.getBufferStart();
|
||||
B += 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;
|
||||
Phdr.p_offset = Seg.Offset;
|
||||
@ -53,9 +84,9 @@ void SectionBase::finalize() {}
|
||||
void SectionBase::markSymbols() {}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
|
||||
uint8_t *Buf = BufPtr->getBufferStart();
|
||||
Buf += Sec.HeaderOffset;
|
||||
typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(Buf);
|
||||
uint8_t *B = Buf.getBufferStart();
|
||||
B += Sec.HeaderOffset;
|
||||
typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(B);
|
||||
Shdr.sh_name = Sec.NameIndex;
|
||||
Shdr.sh_type = Sec.Type;
|
||||
Shdr.sh_flags = Sec.Flags;
|
||||
@ -410,9 +441,7 @@ void Section::initialize(SectionTableRef SecTable) {
|
||||
}
|
||||
}
|
||||
|
||||
void Section::finalize() {
|
||||
this->Link = LinkSection ? LinkSection->Index : 0;
|
||||
}
|
||||
void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; }
|
||||
|
||||
void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
|
||||
FileName = sys::path::filename(File);
|
||||
@ -814,41 +843,33 @@ Writer::~Writer() {}
|
||||
|
||||
Reader::~Reader() {}
|
||||
|
||||
ELFReader::ELFReader(StringRef File) {
|
||||
auto BinaryOrErr = createBinary(File);
|
||||
if (!BinaryOrErr)
|
||||
reportError(File, BinaryOrErr.takeError());
|
||||
auto OwnedBin = std::move(BinaryOrErr.get());
|
||||
std::tie(Bin, Data) = OwnedBin.takeBinary();
|
||||
}
|
||||
|
||||
ElfType ELFReader::getElfType() const {
|
||||
if (isa<ELFObjectFile<ELF32LE>>(Bin.get()))
|
||||
if (isa<ELFObjectFile<ELF32LE>>(Bin))
|
||||
return ELFT_ELF32LE;
|
||||
if (isa<ELFObjectFile<ELF64LE>>(Bin.get()))
|
||||
if (isa<ELFObjectFile<ELF64LE>>(Bin))
|
||||
return ELFT_ELF64LE;
|
||||
if (isa<ELFObjectFile<ELF32BE>>(Bin.get()))
|
||||
if (isa<ELFObjectFile<ELF32BE>>(Bin))
|
||||
return ELFT_ELF32BE;
|
||||
if (isa<ELFObjectFile<ELF64BE>>(Bin.get()))
|
||||
if (isa<ELFObjectFile<ELF64BE>>(Bin))
|
||||
return ELFT_ELF64BE;
|
||||
llvm_unreachable("Invalid ELFType");
|
||||
}
|
||||
|
||||
std::unique_ptr<Object> ELFReader::create() const {
|
||||
auto Obj = llvm::make_unique<Object>();
|
||||
if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Bin.get())) {
|
||||
if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
|
||||
ELFBuilder<ELF32LE> Builder(*o, *Obj);
|
||||
Builder.build();
|
||||
return Obj;
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(Bin.get())) {
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
|
||||
ELFBuilder<ELF64LE> Builder(*o, *Obj);
|
||||
Builder.build();
|
||||
return Obj;
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(Bin.get())) {
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
|
||||
ELFBuilder<ELF32BE> Builder(*o, *Obj);
|
||||
Builder.build();
|
||||
return Obj;
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Bin.get())) {
|
||||
} else if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
|
||||
ELFBuilder<ELF64BE> Builder(*o, *Obj);
|
||||
Builder.build();
|
||||
return Obj;
|
||||
@ -857,8 +878,8 @@ std::unique_ptr<Object> ELFReader::create() const {
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
|
||||
uint8_t *Buf = BufPtr->getBufferStart();
|
||||
Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
|
||||
uint8_t *B = Buf.getBufferStart();
|
||||
Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(B);
|
||||
std::copy(Obj.Ident, Obj.Ident + 16, Ehdr.e_ident);
|
||||
Ehdr.e_type = Obj.Type;
|
||||
Ehdr.e_machine = Obj.Machine;
|
||||
@ -887,10 +908,10 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
|
||||
uint8_t *Buf = BufPtr->getBufferStart() + Obj.SHOffset;
|
||||
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 *>(Buf);
|
||||
Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
|
||||
Shdr.sh_name = 0;
|
||||
Shdr.sh_type = SHT_NULL;
|
||||
Shdr.sh_flags = 0;
|
||||
@ -1076,17 +1097,8 @@ template <class ELFT> void ELFWriter<ELFT>::write() {
|
||||
writeSectionData();
|
||||
if (WriteSectionHeaders)
|
||||
writeShdrs();
|
||||
if (auto E = BufPtr->commit())
|
||||
reportError(File, errorToErrorCode(std::move(E)));
|
||||
}
|
||||
|
||||
void Writer::createBuffer(uint64_t Size) {
|
||||
auto BufferOrErr =
|
||||
FileOutputBuffer::create(File, Size, FileOutputBuffer::F_executable);
|
||||
handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &) {
|
||||
error("failed to open " + File);
|
||||
});
|
||||
BufPtr = std::move(*BufferOrErr);
|
||||
if (auto E = Buf.commit())
|
||||
reportError(Buf.getName(), errorToErrorCode(std::move(E)));
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::finalize() {
|
||||
@ -1123,8 +1135,8 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
|
||||
Section.finalize();
|
||||
}
|
||||
|
||||
createBuffer(totalSize());
|
||||
SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(*BufPtr);
|
||||
Buf.allocate(totalSize());
|
||||
SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf);
|
||||
}
|
||||
|
||||
void BinaryWriter::write() {
|
||||
@ -1133,8 +1145,8 @@ void BinaryWriter::write() {
|
||||
continue;
|
||||
Section.accept(*SecWriter);
|
||||
}
|
||||
if (auto E = BufPtr->commit())
|
||||
reportError(File, errorToErrorCode(std::move(E)));
|
||||
if (auto E = Buf.commit())
|
||||
reportError(Buf.getName(), errorToErrorCode(std::move(E)));
|
||||
}
|
||||
|
||||
void BinaryWriter::finalize() {
|
||||
@ -1216,8 +1228,8 @@ void BinaryWriter::finalize() {
|
||||
TotalSize = std::max(TotalSize, Section->Offset + Section->Size);
|
||||
}
|
||||
|
||||
createBuffer(TotalSize);
|
||||
SecWriter = llvm::make_unique<BinarySectionWriter>(*BufPtr);
|
||||
Buf.allocate(TotalSize);
|
||||
SecWriter = llvm::make_unique<BinarySectionWriter>(Buf);
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Buffer;
|
||||
class SectionBase;
|
||||
class Section;
|
||||
class OwnedDataSection;
|
||||
@ -77,7 +78,7 @@ public:
|
||||
|
||||
class SectionWriter : public SectionVisitor {
|
||||
protected:
|
||||
FileOutputBuffer &Out;
|
||||
Buffer &Out;
|
||||
|
||||
public:
|
||||
virtual ~SectionWriter(){};
|
||||
@ -91,7 +92,7 @@ public:
|
||||
virtual void visit(const GnuDebugLinkSection &Sec) override = 0;
|
||||
virtual void visit(const GroupSection &Sec) override = 0;
|
||||
|
||||
SectionWriter(FileOutputBuffer &Buf) : Out(Buf) {}
|
||||
explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
|
||||
};
|
||||
|
||||
template <class ELFT> class ELFSectionWriter : public SectionWriter {
|
||||
@ -107,7 +108,7 @@ public:
|
||||
void visit(const GnuDebugLinkSection &Sec) override;
|
||||
void visit(const GroupSection &Sec) override;
|
||||
|
||||
ELFSectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
|
||||
explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
|
||||
};
|
||||
|
||||
#define MAKE_SEC_WRITER_FRIEND \
|
||||
@ -123,24 +124,62 @@ public:
|
||||
void visit(const GnuDebugLinkSection &Sec) override;
|
||||
void visit(const GroupSection &Sec) override;
|
||||
|
||||
BinarySectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
|
||||
explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
|
||||
};
|
||||
|
||||
// The class Buffer abstracts out the common interface of FileOutputBuffer and
|
||||
// WritableMemoryBuffer so that the hierarchy of Writers depends on this
|
||||
// abstract interface and doesn't depend on a particular implementation.
|
||||
// TODO: refactor the buffer classes in LLVM to enable us to use them here
|
||||
// directly.
|
||||
class Buffer {
|
||||
StringRef Name;
|
||||
|
||||
public:
|
||||
virtual ~Buffer();
|
||||
virtual void allocate(size_t Size) = 0;
|
||||
virtual uint8_t *getBufferStart() = 0;
|
||||
virtual Error commit() = 0;
|
||||
|
||||
explicit Buffer(StringRef Name) : Name(Name) {}
|
||||
StringRef getName() const { return Name; }
|
||||
};
|
||||
|
||||
class FileBuffer : public Buffer {
|
||||
std::unique_ptr<FileOutputBuffer> Buf;
|
||||
|
||||
public:
|
||||
void allocate(size_t Size) override;
|
||||
uint8_t *getBufferStart() override;
|
||||
Error commit() override;
|
||||
|
||||
explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
|
||||
};
|
||||
|
||||
class MemBuffer : public Buffer {
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
|
||||
public:
|
||||
void allocate(size_t Size) override;
|
||||
uint8_t *getBufferStart() override;
|
||||
Error commit() override;
|
||||
|
||||
explicit MemBuffer(StringRef Name) : Buffer(Name) {}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> releaseMemoryBuffer();
|
||||
};
|
||||
|
||||
class Writer {
|
||||
protected:
|
||||
StringRef File;
|
||||
Object &Obj;
|
||||
std::unique_ptr<FileOutputBuffer> BufPtr;
|
||||
|
||||
void createBuffer(uint64_t Size);
|
||||
Buffer &Buf;
|
||||
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual void finalize() = 0;
|
||||
virtual void write() = 0;
|
||||
|
||||
Writer(StringRef File, Object &Obj) : File(File), Obj(Obj) {}
|
||||
Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
|
||||
};
|
||||
|
||||
template <class ELFT> class ELFWriter : public Writer {
|
||||
@ -169,8 +208,8 @@ public:
|
||||
|
||||
void finalize() override;
|
||||
void write() override;
|
||||
ELFWriter(StringRef File, Object &Obj, bool WSH)
|
||||
: Writer(File, Obj), WriteSectionHeaders(WSH) {}
|
||||
ELFWriter(Object &Obj, Buffer &Buf, bool WSH)
|
||||
: Writer(Obj, Buf), WriteSectionHeaders(WSH) {}
|
||||
};
|
||||
|
||||
class BinaryWriter : public Writer {
|
||||
@ -183,7 +222,7 @@ public:
|
||||
~BinaryWriter() {}
|
||||
void finalize() override;
|
||||
void write() override;
|
||||
BinaryWriter(StringRef File, Object &Obj) : Writer(File, Obj) {}
|
||||
BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
|
||||
};
|
||||
|
||||
class SectionBase {
|
||||
@ -569,14 +608,12 @@ public:
|
||||
};
|
||||
|
||||
class ELFReader : public Reader {
|
||||
private:
|
||||
std::unique_ptr<Binary> Bin;
|
||||
std::shared_ptr<MemoryBuffer> Data;
|
||||
Binary *Bin;
|
||||
|
||||
public:
|
||||
ElfType getElfType() const;
|
||||
std::unique_ptr<Object> create() const override;
|
||||
ELFReader(StringRef File);
|
||||
explicit ELFReader(Binary *B) : Bin(B){};
|
||||
};
|
||||
|
||||
class Object {
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ArchiveWriter.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
#include "llvm/Object/ELFTypes.h"
|
||||
@ -191,23 +193,23 @@ bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config, Object &Obj,
|
||||
StringRef File, ElfType OutputElfType) {
|
||||
Buffer &Buf, ElfType OutputElfType) {
|
||||
if (Config.OutputFormat == "binary") {
|
||||
return llvm::make_unique<BinaryWriter>(File, Obj);
|
||||
return llvm::make_unique<BinaryWriter>(Obj, Buf);
|
||||
}
|
||||
// Depending on the initial ELFT and OutputFormat we need a different Writer.
|
||||
switch (OutputElfType) {
|
||||
case ELFT_ELF32LE:
|
||||
return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj,
|
||||
return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
|
||||
!Config.StripSections);
|
||||
case ELFT_ELF64LE:
|
||||
return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj,
|
||||
return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
|
||||
!Config.StripSections);
|
||||
case ELFT_ELF32BE:
|
||||
return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj,
|
||||
return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
|
||||
!Config.StripSections);
|
||||
case ELFT_ELF64BE:
|
||||
return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj,
|
||||
return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
|
||||
!Config.StripSections);
|
||||
}
|
||||
llvm_unreachable("Invalid output format");
|
||||
@ -218,7 +220,8 @@ void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader,
|
||||
auto DWOFile = Reader.create();
|
||||
DWOFile->removeSections(
|
||||
[&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
|
||||
auto Writer = CreateWriter(Config, *DWOFile, File, OutputElfType);
|
||||
FileBuffer FB(File);
|
||||
auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType);
|
||||
Writer->finalize();
|
||||
Writer->write();
|
||||
}
|
||||
@ -441,24 +444,89 @@ void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader,
|
||||
Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
|
||||
}
|
||||
|
||||
std::unique_ptr<Reader> CreateReader(StringRef InputFilename,
|
||||
ElfType &OutputElfType) {
|
||||
// Right now we can only read ELF files so there's only one reader;
|
||||
auto Out = llvm::make_unique<ELFReader>(InputFilename);
|
||||
// We need to set the default ElfType for output.
|
||||
OutputElfType = Out->getElfType();
|
||||
return std::move(Out);
|
||||
void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary,
|
||||
Buffer &Out) {
|
||||
ELFReader Reader(&Binary);
|
||||
std::unique_ptr<Object> Obj = Reader.create();
|
||||
|
||||
HandleArgs(Config, *Obj, Reader, Reader.getElfType());
|
||||
|
||||
std::unique_ptr<Writer> Writer =
|
||||
CreateWriter(Config, *Obj, Out, Reader.getElfType());
|
||||
Writer->finalize();
|
||||
Writer->write();
|
||||
}
|
||||
|
||||
// For regular archives this function simply calls llvm::writeArchive,
|
||||
// For thin archives it writes the archive file itself as well as its members.
|
||||
Error deepWriteArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
|
||||
bool WriteSymtab, object::Archive::Kind Kind,
|
||||
bool Deterministic, bool Thin) {
|
||||
Error E =
|
||||
writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
|
||||
if (!Thin || E)
|
||||
return E;
|
||||
for (const NewArchiveMember &Member : NewMembers) {
|
||||
// Internally, FileBuffer will use the buffer created by
|
||||
// FileOutputBuffer::create, for regular files (that is the case for
|
||||
// deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
|
||||
// OnDiskBuffer uses a temporary file and then renames it. So in reality
|
||||
// there is no inefficiency / duplicated in-memory buffers in this case. For
|
||||
// now in-memory buffers can not be completely avoided since
|
||||
// NewArchiveMember still requires them even though writeArchive does not
|
||||
// write them on disk.
|
||||
FileBuffer FB(Member.MemberName);
|
||||
FB.allocate(Member.Buf->getBufferSize());
|
||||
std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
|
||||
FB.getBufferStart());
|
||||
if (auto E = FB.commit())
|
||||
return E;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void ExecuteElfObjcopyOnArchive(const CopyConfig &Config, const Archive &Ar) {
|
||||
std::vector<NewArchiveMember> NewArchiveMembers;
|
||||
Error Err = Error::success();
|
||||
for (const Archive::Child &Child : Ar.children(Err)) {
|
||||
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
|
||||
if (!ChildOrErr)
|
||||
reportError(Ar.getFileName(), ChildOrErr.takeError());
|
||||
Expected<StringRef> ChildNameOrErr = Child.getName();
|
||||
if (!ChildNameOrErr)
|
||||
reportError(Ar.getFileName(), ChildNameOrErr.takeError());
|
||||
|
||||
MemBuffer MB(ChildNameOrErr.get());
|
||||
ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB);
|
||||
|
||||
Expected<NewArchiveMember> Member =
|
||||
NewArchiveMember::getOldMember(Child, true);
|
||||
if (!Member)
|
||||
reportError(Ar.getFileName(), Member.takeError());
|
||||
Member->Buf = MB.releaseMemoryBuffer();
|
||||
Member->MemberName = Member->Buf->getBufferIdentifier();
|
||||
NewArchiveMembers.push_back(std::move(*Member));
|
||||
}
|
||||
|
||||
if (Err)
|
||||
reportError(Config.InputFilename, std::move(Err));
|
||||
if (Error E =
|
||||
deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
|
||||
Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
|
||||
reportError(Config.OutputFilename, std::move(E));
|
||||
}
|
||||
|
||||
void ExecuteElfObjcopy(const CopyConfig &Config) {
|
||||
ElfType OutputElfType;
|
||||
auto Reader = CreateReader(Config.InputFilename, OutputElfType);
|
||||
auto Obj = Reader->create();
|
||||
auto Writer =
|
||||
CreateWriter(Config, *Obj, Config.OutputFilename, OutputElfType);
|
||||
HandleArgs(Config, *Obj, *Reader, OutputElfType);
|
||||
Writer->finalize();
|
||||
Writer->write();
|
||||
Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
|
||||
createBinary(Config.InputFilename);
|
||||
if (!BinaryOrErr)
|
||||
reportError(Config.InputFilename, BinaryOrErr.takeError());
|
||||
|
||||
if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary()))
|
||||
return ExecuteElfObjcopyOnArchive(Config, *Ar);
|
||||
|
||||
FileBuffer FB(Config.OutputFilename);
|
||||
ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
|
||||
}
|
||||
|
||||
// ParseObjcopyOptions returns the config and sets the input arguments. If a
|
||||
@ -584,7 +652,7 @@ CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) {
|
||||
InputArgs.getLastArgValue(STRIP_output, Positional[0]);
|
||||
|
||||
Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
|
||||
|
||||
|
||||
Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
|
||||
Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user