Index: test/tools/llvm-objcopy/binary-input-aarch64.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-aarch64.test @@ -0,0 +1,34 @@ +# RUN: printf abcd > %t.x-txt +# RUN: llvm-objcopy -I binary -B aarch64 %t.x-txt %t.o +# RUN: llvm-readobj -file-headers -sections -symbols %t.o | FileCheck %s + +# CHECK: Format: ELF64-aarch64-little +# CHECK-NEXT: Arch: aarch64 +# CHECK-NEXT: AddressSize: 64bit +# CHECK-NEXT: LoadName: + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 64-bit (0x2) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable (0x1) +# CHECK-NEXT: Machine: EM_AARCH64 (0xB7) +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: +# CHECK-NEXT: SectionHeaderOffset: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 64 +# CHECK-NEXT: ProgramHeaderEntrySize: 56 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 64 +# CHECK-NEXT: SectionHeaderCount: 4 +# CHECK-NEXT: StringTableSectionIndex: +# CHECK-NEXT: } Index: test/tools/llvm-objcopy/binary-input-arm.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-arm.test @@ -0,0 +1,34 @@ +# RUN: printf abcd > %t.x-txt +# RUN: llvm-objcopy -I binary -B arm %t.x-txt %t.o +# RUN: llvm-readobj -file-headers -sections -symbols %t.o | FileCheck %s + +# CHECK: Format: ELF32-arm-little +# CHECK-NEXT: Arch: arm +# CHECK-NEXT: AddressSize: 32bit +# CHECK-NEXT: LoadName: + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 32-bit (0x1) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable (0x1) +# CHECK-NEXT: Machine: EM_ARM (0x28) +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: +# CHECK-NEXT: SectionHeaderOffset: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 52 +# CHECK-NEXT: ProgramHeaderEntrySize: 32 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 40 +# CHECK-NEXT: SectionHeaderCount: 4 +# CHECK-NEXT: StringTableSectionIndex: +# CHECK-NEXT: } Index: test/tools/llvm-objcopy/binary-input-error.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-error.test @@ -0,0 +1,10 @@ +# RUN: printf abcd > %t.txt + +# RUN: not llvm-objcopy -I binary %t.txt %t.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=MISSING-BINARY-ARCH + +# RUN: not llvm-objcopy -I binary -B xyz %t.txt %t.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=BAD-BINARY-ARCH + +# MISSING-BINARY-ARCH: Specified binary input without specifiying an architecture. +# BAD-BINARY-ARCH: Invalid architecture: 'xyz'. Index: test/tools/llvm-objcopy/binary-input-i386.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-i386.test @@ -0,0 +1,34 @@ +# RUN: printf abcd > %t.x-txt +# RUN: llvm-objcopy -I binary -B i386 %t.x-txt %t.o +# RUN: llvm-readobj -file-headers -sections -symbols %t.o | FileCheck %s + +# CHECK: Format: ELF32-i386 +# CHECK-NEXT: Arch: i386 +# CHECK-NEXT: AddressSize: 32bit +# CHECK-NEXT: LoadName: + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 32-bit (0x1) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable (0x1) +# CHECK-NEXT: Machine: EM_386 (0x3) +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: +# CHECK-NEXT: SectionHeaderOffset: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 52 +# CHECK-NEXT: ProgramHeaderEntrySize: 32 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 40 +# CHECK-NEXT: SectionHeaderCount: 4 +# CHECK-NEXT: StringTableSectionIndex: +# CHECK-NEXT: } Index: test/tools/llvm-objcopy/binary-input-reconstitute.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-reconstitute.test @@ -0,0 +1,10 @@ +# RUN: printf abcd > %t.txt + +# RUN: llvm-objcopy -I binary -B i386:x86-64 -O binary %t.txt %t.2.txt +# RUN: FileCheck --match-full-lines %s < %t.2.txt + +# RUN: llvm-objcopy -I binary -B i386:x86-64 %t.txt %t.o +# RUN: llvm-objcopy -O binary %t.o %t.3.txt +# RUN: FileCheck --match-full-lines %s < %t.3.txt + +# CHECK: abcd Index: test/tools/llvm-objcopy/binary-input-x86-64.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input-x86-64.test @@ -0,0 +1,34 @@ +# RUN: printf abcd > %t.x-txt +# RUN: llvm-objcopy -I binary -B x86-64 %t.x-txt %t.o +# RUN: llvm-readobj -file-headers -sections -symbols %t.o | FileCheck %s + +# CHECK: Format: ELF64-x86-64 +# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: AddressSize: 64bit +# CHECK-NEXT: LoadName: + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 64-bit (0x2) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable (0x1) +# CHECK-NEXT: Machine: EM_X86_64 (0x3E) +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: +# CHECK-NEXT: SectionHeaderOffset: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 64 +# CHECK-NEXT: ProgramHeaderEntrySize: 56 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 64 +# CHECK-NEXT: SectionHeaderCount: 4 +# CHECK-NEXT: StringTableSectionIndex: +# CHECK-NEXT: } Index: test/tools/llvm-objcopy/binary-input.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-input.test @@ -0,0 +1,140 @@ +# RUN: printf abcd > %t.x-txt +# RUN: llvm-objcopy -I binary -B i386:x86-64 %t.x-txt %t.o +# RUN: llvm-readobj -file-headers -sections -symbols %t.o | FileCheck %s + +# CHECK: Format: ELF64-x86-64 +# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: AddressSize: 64bit +# CHECK-NEXT: LoadName: + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 64-bit (0x2) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable (0x1) +# CHECK-NEXT: Machine: EM_X86_64 (0x3E) +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: +# CHECK-NEXT: SectionHeaderOffset: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 64 +# CHECK-NEXT: ProgramHeaderEntrySize: 56 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 64 +# CHECK-NEXT: SectionHeaderCount: 4 +# CHECK-NEXT: StringTableSectionIndex: +# CHECK-NEXT: } + +# CHECK: Sections [ +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: (0) +# CHECK-NEXT: Type: SHT_NULL (0x0) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .strtab +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .symtab +# CHECK-NEXT: Type: SHT_SYMTAB (0x2) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 1 +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 24 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS (0x1) +# CHECK-NEXT: Flags [ (0x3) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: SHF_WRITE (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# Note: the symbol names are derived from the full path (with non-alnum values +# replaced with "_"), e.g. "/tmp/a-b.c" should yield +# _binary__tmp_a_b_c_{start,end,size}. +# Just check for _binary_{{[_a-zA-Z0-9]*}}_x_txt_{start,end,size} to avoid +# making assumptions about how this test is run. + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: Section (0x3) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .data +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _binary_{{[_a-zA-Z0-9]*}}_x_txt_start +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .data +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _binary_{{[_a-zA-Z0-9]*}}_x_txt_end +# CHECK-NEXT: Value: 0x4 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .data +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _binary_{{[_a-zA-Z0-9]*}}_x_txt_size +# CHECK-NEXT: Value: 0x4 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: ] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -386,7 +386,7 @@ SectionBase *DefinedIn = nullptr; SymbolShndxType ShndxType; uint32_t Index; - StringRef Name; + std::string Name; uint32_t NameIndex; uint64_t Size; uint8_t Type; @@ -437,9 +437,11 @@ using SymPtr = std::unique_ptr; public: - void addSymbol(StringRef Name, uint8_t Bind, uint8_t Type, - SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, - uint16_t Shndx, uint64_t Sz); + SymbolTableSection() { Type = ELF::SHT_SYMTAB; } + + void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, + uint64_t Value, uint8_t Visibility, uint16_t Shndx, + uint64_t Sz); void prepareForLayout(); // An 'empty' symbol table still contains a null symbol. bool empty() const { return Symbols.size() == 1; } @@ -616,6 +618,7 @@ public: virtual ~Reader(); virtual std::unique_ptr create() const = 0; + virtual ElfType getElfType() const = 0; }; using object::Binary; @@ -623,6 +626,28 @@ using object::ELFObjectFile; using object::OwningBinary; +template class BinaryELFBuilder { + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Sym = typename ELFT::Sym; + + uint16_t EMachine; + MemoryBuffer *MemBuf; + std::unique_ptr Obj; + + void initFileHeader(); + void initHeaderSegment(); + void addStrTab(); + void addSymTab(); + void addData(); + void initSections(); + +public: + BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) + : EMachine(EM), MemBuf(MB), Obj(llvm::make_unique()) {} + + std::unique_ptr build(); +}; + template class ELFBuilder { private: using Elf_Addr = typename ELFT::Addr; @@ -647,13 +672,26 @@ void build(); }; +template class BinaryReader : public Reader { + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Sym = typename ELFT::Sym; + + uint16_t EMachine; + MemoryBuffer *MemBuf; + +public: + BinaryReader(uint16_t EM, MemoryBuffer *MB) : EMachine(EM), MemBuf(MB) {} + ElfType getElfType() const override; + std::unique_ptr create() const override; +}; + class ELFReader : public Reader { Binary *Bin; public: - ElfType getElfType() const; + ElfType getElfType() const override; std::unique_ptr create() const override; - explicit ELFReader(Binary *B) : Bin(B){}; + explicit ELFReader(Binary *B) : Bin(B) {} }; class Object { Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -232,12 +232,12 @@ Sym->Index = Index++; } -void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type, +void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, uint64_t Sz) { Symbol Sym; - Sym.Name = Name; + Sym.Name = Name.str(); Sym.Binding = Bind; Sym.Type = Type; Sym.DefinedIn = DefinedIn; @@ -589,6 +589,107 @@ return A->Index < B->Index; } +template ElfType BinaryReader::getElfType() const { + if (ELFT::Is64Bits) + return ELFT::TargetEndianness == support::big ? ELFT_ELF64BE : ELFT_ELF64LE; + else + return ELFT::TargetEndianness == support::big ? ELFT_ELF32BE : ELFT_ELF32LE; +} + +template void BinaryELFBuilder::initFileHeader() { + std::fill(Obj->Ident, Obj->Ident + 16, 0); + Obj->Ident[EI_MAG0] = 0x7f; + Obj->Ident[EI_MAG1] = 'E'; + Obj->Ident[EI_MAG2] = 'L'; + Obj->Ident[EI_MAG3] = 'F'; + Obj->Ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; + Obj->Ident[EI_DATA] = + ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB; + Obj->Ident[EI_VERSION] = EV_CURRENT; + Obj->Ident[EI_OSABI] = ELFOSABI_NONE; + Obj->Ident[EI_ABIVERSION] = 0; + + Obj->Flags = 0x0; + Obj->Type = ET_REL; + Obj->Entry = 0x0; + Obj->Machine = EMachine; + Obj->Version = 1; +} + +template void BinaryELFBuilder::initHeaderSegment() { + auto &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); + ElfHdr.Align = 0; + ElfHdr.Index = 0; +} + +template void BinaryELFBuilder::addStrTab() { + auto &StrTab = Obj->addSection(); + StrTab.Name = ".strtab"; + + Obj->SectionNames = &StrTab; +} + +template void BinaryELFBuilder::addSymTab() { + auto &SymTab = Obj->addSection(); + + SymTab.Name = ".symtab"; + SymTab.Link = size(Obj->sections()) - 1; + SymTab.EntrySize = sizeof(Elf_Sym); + + Obj->SymbolTable = &SymTab; +} + +template void BinaryELFBuilder::addData() { + auto AR = ArrayRef( + reinterpret_cast(MemBuf->getBufferStart()), + MemBuf->getBufferSize()); + auto &DS = Obj->addSection
(AR); + DS.Name = ".data"; + DS.Type = ELF::SHT_PROGBITS; + DS.Size = AR.size(); + DS.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); }, '_'); + Twine S = Twine("_binary_") + SanitizedFilename; + + SymbolTableSection *SymTab = Obj->SymbolTable; + if (!SymTab) + error("Create the Symbol Table before adding the Data section"); + + SymTab->addSymbol("", STB_LOCAL, STT_SECTION, &DS, 0, STV_DEFAULT, 0, 0); + SymTab->addSymbol(S + "_start", STB_GLOBAL, STT_NOTYPE, &DS, 0, STV_DEFAULT, + 0, 0); + SymTab->addSymbol(S + "_end", STB_GLOBAL, STT_NOTYPE, &DS, DS.Size, + STV_DEFAULT, 0, 0); + SymTab->addSymbol(S + "_size", STB_GLOBAL, STT_NOTYPE, nullptr, DS.Size, + STV_DEFAULT, SHN_ABS, 0); +} + +template void BinaryELFBuilder::initSections() { + for (auto &Section : Obj->sections()) { + Section.initialize(Obj->sections()); + } +} + +template std::unique_ptr BinaryELFBuilder::build() { + initFileHeader(); + initHeaderSegment(); + addStrTab(); + addSymTab(); + initSections(); + addData(); + + return std::move(Obj); +} + template void ELFBuilder::setParentSegment(Segment &Child) { for (auto &Parent : Obj.segments()) { // Every segment will overlap with itself but we don't want a segment to @@ -925,6 +1026,13 @@ Reader::~Reader() {} +template +std::unique_ptr BinaryReader::create() const { + BinaryELFBuilder Builder(EMachine, MemBuf); + + return Builder.build(); +} + ElfType ELFReader::getElfType() const { if (isa>(Bin)) return ELFT_ELF32LE; @@ -1389,6 +1497,16 @@ namespace llvm { namespace objcopy { +template class BinaryELFBuilder; +template class BinaryELFBuilder; +template class BinaryELFBuilder; +template class BinaryELFBuilder; + +template class BinaryReader; +template class BinaryReader; +template class BinaryReader; +template class BinaryReader; + template class ELFBuilder; template class ELFBuilder; template class ELFBuilder; Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include @@ -118,6 +119,15 @@ StripOptTable() : OptTable(StripInfoTable, true) {} }; +// This type keeps track of the machine info for various architectures. This +// lets us map architecture names to ELF types and the e_machine value of the +// ELF file. +struct MachineInfo { + uint16_t EMachine; + bool Is64Bit; + bool IsLittleEndian; +}; + struct SectionRename { StringRef OriginalName; StringRef NewName; @@ -129,7 +139,7 @@ StringRef InputFilename; StringRef OutputFormat; StringRef InputFormat; - StringRef BinaryArch; + MachineInfo BinaryArch; StringRef SplitDWO; StringRef AddGnuDebugLink; @@ -288,6 +298,24 @@ return !IsDWOSection(Sec); } +static const MachineInfo MI_X86_64{EM_X86_64, true, true}; +static const MachineInfo MI_386{EM_386, false, true}; +static const MachineInfo MI_AARCH64{EM_AARCH64, true, true}; +static const MachineInfo MI_ARM{EM_ARM, false, true}; + +static const StringMap ArchMap{{"i386", MI_386}, + {"i386:x86-64", MI_X86_64}, + {"x86-64", MI_X86_64}, + {"arm", MI_ARM}, + {"aarch64", MI_AARCH64}}; + +static MachineInfo GetMachineInfo(StringRef Arch) { + auto Iter = ArchMap.find(Arch); + if (Iter == std::end(ArchMap)) + error("Invalid architecture: '" + Arch + "'"); + return Iter->getValue(); +} + static std::unique_ptr CreateWriter(const CopyConfig &Config, Object &Obj, Buffer &Buf, ElfType OutputElfType) { @@ -559,9 +587,8 @@ Obj.addSection(Config.AddGnuDebugLink); } -static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary, +static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader, Buffer &Out) { - ELFReader Reader(&Binary); std::unique_ptr Obj = Reader.create(); HandleArgs(Config, *Obj, Reader, Reader.getElfType()); @@ -614,7 +641,8 @@ reportError(Ar.getFileName(), ChildNameOrErr.takeError()); MemBuffer MB(ChildNameOrErr.get()); - ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB); + ELFReader Reader(ChildOrErr->get()); + ExecuteElfObjcopyOnBinary(Config, Reader, MB); Expected Member = NewArchiveMember::getOldMember(Child, true); @@ -633,17 +661,44 @@ reportError(Config.OutputFilename, std::move(E)); } -static void ExecuteElfObjcopy(const CopyConfig &Config) { - Expected> BinaryOrErr = - createBinary(Config.InputFilename); - if (!BinaryOrErr) - reportError(Config.InputFilename, BinaryOrErr.takeError()); - - if (Archive *Ar = dyn_cast(BinaryOrErr.get().getBinary())) - return ExecuteElfObjcopyOnArchive(Config, *Ar); +static std::unique_ptr CreateBinaryReader(const MachineInfo &MI, + MemoryBuffer *MB) { + if (MI.Is64Bit) { + if (MI.IsLittleEndian) + return llvm::make_unique>(MI.EMachine, MB); + else + return llvm::make_unique>(MI.EMachine, MB); + } else { + if (MI.IsLittleEndian) + return llvm::make_unique>(MI.EMachine, MB); + else + return llvm::make_unique>(MI.EMachine, MB); + } +} - FileBuffer FB(Config.OutputFilename); - ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); +static void ExecuteElfObjcopy(const CopyConfig &Config) { + if (Config.InputFormat == "binary") { + auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); + if (!BufOrErr) + reportError(Config.InputFilename, BufOrErr.getError()); + + FileBuffer FB(Config.OutputFilename); + std::unique_ptr Reader = + CreateBinaryReader(Config.BinaryArch, BufOrErr->get()); + ExecuteElfObjcopyOnBinary(Config, *Reader, FB); + } else { + Expected> BinaryOrErr = + createBinary(Config.InputFilename); + if (!BinaryOrErr) + reportError(Config.InputFilename, BinaryOrErr.takeError()); + + if (Archive *Ar = dyn_cast(BinaryOrErr.get().getBinary())) + return ExecuteElfObjcopyOnArchive(Config, *Ar); + + FileBuffer FB(Config.OutputFilename); + ELFReader Reader(BinaryOrErr.get().getBinary()); + ExecuteElfObjcopyOnBinary(Config, Reader, FB); + } } // ParseObjcopyOptions returns the config and sets the input arguments. If a @@ -684,7 +739,12 @@ Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); - Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); + if (Config.InputFormat == "binary") { + auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); + if (BinaryArch.empty()) + error("Specified binary input without specifiying an architecture"); + Config.BinaryArch = GetMachineInfo(BinaryArch); + } Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);