Index: test/tools/llvm-objcopy/COFF/Inputs/remove-symbols.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/remove-symbols.yaml @@ -0,0 +1,194 @@ +# Generated from the following source with +# llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o +# obj2yaml %t.o + +# .text +# .globl otherfunc +#otherfunc: +# ret +# .globl otherfunc2 +#otherfunc2: +# ret +# .globl mainfunc +#mainfunc: +# movl ptr(%rip), %eax +# call otherfunc +# call foo +# movq .Lmaindata(%rip), %rax +# ret +# +# .data +#ptr: +# .long 42 +# +# .section .rdata,"dr" +#.Lmaindata: +# .quad foo +# +# .section .rdata,"dr",associative,foo +#.Lfoodata: +# .quad foo +# +# .section .text,"dw",discard,foo +# .globl foo +#foo: +# movq .Lfoodata(%rip), %rax +# ret + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: C3C38B0500000000E8F3FFFFFFE800000000488B0500000000C3 + Relocations: + - VirtualAddress: 4 + SymbolName: ptr + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 14 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 21 + SymbolTableIndex: 6 + Type: IMAGE_REL_AMD64_REL32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 2A000000 + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: '0000000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: foo + Type: IMAGE_REL_AMD64_ADDR64 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 1 + SectionData: 488B0500000000C3 + Relocations: + - VirtualAddress: 3 + SymbolTableIndex: 8 + Type: IMAGE_REL_AMD64_REL32 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: '0000000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: foo + Type: IMAGE_REL_AMD64_ADDR64 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 26 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 814602877 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3482275674 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .rdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 4 + - Name: .rdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: .text + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 583624169 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: foo + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: otherfunc + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: otherfunc2 + Value: 1 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: mainfunc + Value: 2 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: ptr + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... Index: test/tools/llvm-objcopy/COFF/remove-symbol1.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/remove-symbol1.test @@ -0,0 +1,49 @@ +# RUN: yaml2obj %p/Inputs/remove-symbols.yaml > %t.o + +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-PRE +# RUN: llvm-objdump -t %t.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-PRE +# RUN: llvm-objcopy -N otherfunc %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-POST +# RUN: llvm-objdump -t %t.o | FileCheck %s --check-prefix=SYMBOLS + +# Explicitly listing the relocations for the input as well, to show +# that the symbol index of the symbol ptr is updated in the relocations, +# while keeping relocations to two distinct .rdata symbols separate. + +# RELOCS: Relocations [ +# RELOCS-NEXT: Section (1) .text { +# RELOCS-PRE-NEXT: 0x4 IMAGE_REL_AMD64_REL32 ptr (16) +# RELOCS-POST-NEXT: 0x4 IMAGE_REL_AMD64_REL32 ptr (15) +# RELOCS-NEXT: 0xE IMAGE_REL_AMD64_REL32 foo (12) +# RELOCS-NEXT: 0x15 IMAGE_REL_AMD64_REL32 .rdata (6) +# RELOCS-NEXT: } +# RELOCS-NEXT: Section (4) .rdata { +# RELOCS-NEXT: 0x0 IMAGE_REL_AMD64_ADDR64 foo (12) +# RELOCS-NEXT: } +# RELOCS-NEXT: Section (5) .text { +# RELOCS-NEXT: 0x3 IMAGE_REL_AMD64_REL32 .rdata (8) +# RELOCS-NEXT: } +# RELOCS-NEXT: Section (6) .rdata { +# RELOCS-NEXT: 0x0 IMAGE_REL_AMD64_ADDR64 foo (12) +# RELOCS-NEXT: } +# RELOCS-NEXT: ] + +# SYMBOLS: SYMBOL TABLE: +# SYMBOLS-NEXT: .text +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: .data +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: .bss +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: .rdata +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: .rdata +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: .text +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-NEXT: foo +# SYMBOLS-PRE-NEXT: otherfunc +# SYMBOLS-NEXT: otherfunc2 +# SYMBOLS-NEXT: mainfunc +# SYMBOLS-NEXT: ptr +# SYMBOLS-EMPTY: Index: test/tools/llvm-objcopy/COFF/remove-symbol2.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/remove-symbol2.test @@ -0,0 +1,4 @@ +# RUN: yaml2obj %p/Inputs/remove-symbols.yaml > %t.o +# RUN: not llvm-objcopy -N ptr %t.o 2>&1 | FileCheck %s --check-prefix=ERROR + +# ERROR: error: '{{.*}}/remove-symbol2.test.tmp.o': Can't remove referenced symbol 'ptr' Index: tools/llvm-objcopy/CMakeLists.txt =================================================================== --- tools/llvm-objcopy/CMakeLists.txt +++ tools/llvm-objcopy/CMakeLists.txt @@ -18,6 +18,7 @@ CopyConfig.cpp llvm-objcopy.cpp COFF/COFFObjcopy.cpp + COFF/Object.cpp COFF/Reader.cpp COFF/Writer.cpp ELF/ELFObjcopy.cpp Index: tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -17,6 +17,7 @@ #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Errc.h" #include namespace llvm { @@ -26,6 +27,29 @@ using namespace object; using namespace COFF; +static Error handleArgs(const CopyConfig &Config, Object &Obj) { + // If we need to do per-symbol removals, initialize the Referenced field. + if (!Config.SymbolsToRemove.empty()) + if (Error E = Obj.markSymbols()) + return E; + + // Actually do removals of symbols. + Obj.removeSymbols([&](const Symbol &Sym) { + if (is_contained(Config.SymbolsToRemove, Sym.Name)) { + // Explicitly removing a referenced symbol is an error. + if (Sym.Referenced) + reportError(Config.OutputFilename, + make_error("Can't remove referenced symbol '" + + Sym.Name + "'", + llvm::errc::invalid_argument)); + return true; + } + + return false; + }); + return Error::success(); +} + void executeObjcopyOnBinary(const CopyConfig &Config, object::COFFObjectFile &In, Buffer &Out) { COFFReader Reader(In); @@ -34,6 +58,8 @@ reportError(Config.InputFilename, ObjOrErr.takeError()); Object *Obj = ObjOrErr->get(); assert(Obj && "Unable to deserialize COFF object"); + if (Error E = handleArgs(Config, *Obj)) + reportError(Config.InputFilename, std::move(E)); COFFWriter Writer(*Obj, Out); if (Error E = Writer.write()) reportError(Config.OutputFilename, std::move(E)); Index: tools/llvm-objcopy/COFF/Object.h =================================================================== --- tools/llvm-objcopy/COFF/Object.h +++ tools/llvm-objcopy/COFF/Object.h @@ -11,7 +11,9 @@ #define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include @@ -22,10 +24,16 @@ namespace objcopy { namespace coff { +struct Relocation { + object::coff_relocation Reloc; + size_t Target; + StringRef TargetName; // Used for diagnostics only +}; + struct Section { object::coff_section Header; ArrayRef Contents; - std::vector Relocs; + std::vector Relocs; StringRef Name; }; @@ -33,6 +41,9 @@ object::coff_symbol32 Sym; StringRef Name; ArrayRef AuxData; + size_t UniqueId; + size_t RawIndex; + bool Referenced; }; struct Object { @@ -49,7 +60,31 @@ std::vector DataDirectories; std::vector
Sections; + + ArrayRef getSymbols() const { return Symbols; } + // This allows mutating individual Symbols, but not mutating the list + // of symbols itself. + iterator_range::iterator> getMutableSymbols() { + return make_range(Symbols.begin(), Symbols.end()); + } + + const Symbol *findSymbol(size_t UniqueId) const; + + void addSymbols(ArrayRef NewSymbols); + void removeSymbols(function_ref ToRemove); + + // Set the Referenced field on all Symbols, based on relocations in + // all sections. + Error markSymbols(); + +private: std::vector Symbols; + DenseMap SymbolMap; + + size_t NextSymbolUniqueId = 0; + + // Update SymbolMap and RawIndex in each Symbol. + void updateSymbols(); }; // Copy between coff_symbol16 and coff_symbol32. Index: tools/llvm-objcopy/COFF/Object.cpp =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Object.cpp @@ -0,0 +1,70 @@ +//===- Object.cpp ---------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Object.h" +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +using namespace object; + +void Object::addSymbols(ArrayRef NewSymbols) { + for (Symbol S : NewSymbols) { + S.UniqueId = NextSymbolUniqueId++; + Symbols.emplace_back(S); + } + updateSymbols(); +} + +void Object::updateSymbols() { + SymbolMap.clear(); + size_t RawSymIndex = 0; + for (Symbol &Sym : Symbols) { + SymbolMap[Sym.UniqueId] = &Sym; + Sym.RawIndex = RawSymIndex; + RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols; + } +} + +const Symbol *Object::findSymbol(size_t UniqueId) const { + auto It = SymbolMap.find(UniqueId); + if (It == SymbolMap.end()) + return nullptr; + return It->second; +} + +void Object::removeSymbols(function_ref ToRemove) { + Symbols.erase( + std::remove_if(std::begin(Symbols), std::end(Symbols), + [ToRemove](const Symbol &Sym) { return ToRemove(Sym); }), + std::end(Symbols)); + updateSymbols(); +} + +Error Object::markSymbols() { + for (Symbol &Sym : Symbols) + Sym.Referenced = false; + for (const Section &Sec : Sections) { + for (const Relocation &R : Sec.Relocs) { + auto It = SymbolMap.find(R.Target); + if (It == SymbolMap.end()) + return make_error("Relocation target " + Twine(R.Target) + + " not found", + object_error::invalid_symbol_index); + It->second->Referenced = true; + } + } + return Error::success(); +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm Index: tools/llvm-objcopy/COFF/Reader.h =================================================================== --- tools/llvm-objcopy/COFF/Reader.h +++ tools/llvm-objcopy/COFF/Reader.h @@ -35,6 +35,7 @@ Error readExecutableHeaders(Object &Obj) const; Error readSections(Object &Obj) const; Error readSymbols(Object &Obj, bool IsBigObj) const; + Error setRelocTargets(Object &Obj) const; public: explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {} Index: tools/llvm-objcopy/COFF/Reader.cpp =================================================================== --- tools/llvm-objcopy/COFF/Reader.cpp +++ tools/llvm-objcopy/COFF/Reader.cpp @@ -73,7 +73,7 @@ return errorCodeToError(EC); ArrayRef Relocs = COFFObj.getRelocations(Sec); for (const coff_relocation &R : Relocs) - S.Relocs.push_back(R); + S.Relocs.push_back(Relocation{R}); if (auto EC = COFFObj.getSectionName(Sec, S.Name)) return errorCodeToError(EC); if (Sec->hasExtendedRelocations()) @@ -84,14 +84,15 @@ } Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { + std::vector Symbols; for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) { Expected SymOrErr = COFFObj.getSymbol(I); if (!SymOrErr) return SymOrErr.takeError(); COFFSymbolRef SymRef = *SymOrErr; - Obj.Symbols.push_back(Symbol()); - Symbol &Sym = Obj.Symbols.back(); + Symbols.push_back(Symbol()); + Symbol &Sym = Symbols.back(); // Copy symbols from the original form into an intermediate coff_symbol32. if (IsBigObj) copySymbol(Sym.Sym, @@ -106,6 +107,30 @@ (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0); I += 1 + SymRef.getNumberOfAuxSymbols(); } + Obj.addSymbols(Symbols); + return Error::success(); +} + +Error COFFReader::setRelocTargets(Object &Obj) const { + std::vector RawSymbolTable; + for (const Symbol &Sym : Obj.getSymbols()) { + RawSymbolTable.push_back(&Sym); + for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) + RawSymbolTable.push_back(nullptr); + } + for (Section &Sec : Obj.Sections) { + for (Relocation &R : Sec.Relocs) { + if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) + return make_error("SymbolTableIndex out of range", + object_error::parse_failed); + const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; + if (Sym == nullptr) + return make_error("Invalid SymbolTableIndex", + object_error::parse_failed); + R.Target = Sym->UniqueId; + R.TargetName = Sym->Name; + } + } return Error::success(); } @@ -136,6 +161,8 @@ return std::move(E); if (Error E = readSymbols(*Obj, IsBigObj)) return std::move(E); + if (Error E = setRelocTargets(*Obj)) + return std::move(E); return std::move(Obj); } Index: tools/llvm-objcopy/COFF/Writer.h =================================================================== --- tools/llvm-objcopy/COFF/Writer.h +++ tools/llvm-objcopy/COFF/Writer.h @@ -40,11 +40,12 @@ size_t SizeOfInitializedData; StringTableBuilder StrTabBuilder; + Error finalizeRelocTargets(); void layoutSections(); size_t finalizeStringTable(); template std::pair finalizeSymbolTable(); - void finalize(bool IsBigObj); + Error finalize(bool IsBigObj); void writeHeaders(bool IsBigObj); void writeSections(); Index: tools/llvm-objcopy/COFF/Writer.cpp =================================================================== --- tools/llvm-objcopy/COFF/Writer.cpp +++ tools/llvm-objcopy/COFF/Writer.cpp @@ -27,6 +27,21 @@ Writer::~Writer() {} +Error COFFWriter::finalizeRelocTargets() { + for (Section &Sec : Obj.Sections) { + for (Relocation &R : Sec.Relocs) { + const Symbol *Sym = Obj.findSymbol(R.Target); + if (Sym == nullptr) + return make_error("Relocation target " + R.TargetName + + " (" + Twine(R.Target) + + ") not found", + object_error::invalid_symbol_index); + R.Reloc.SymbolTableIndex = Sym->RawIndex; + } + } + return Error::success(); +} + void COFFWriter::layoutSections() { for (auto &S : Obj.Sections) { if (S.Header.SizeOfRawData > 0) @@ -48,7 +63,7 @@ if (S.Name.size() > COFF::NameSize) StrTabBuilder.add(S.Name); - for (const auto &S : Obj.Symbols) + for (const auto &S : Obj.getSymbols()) if (S.Name.size() > COFF::NameSize) StrTabBuilder.add(S.Name); @@ -62,7 +77,7 @@ strncpy(S.Header.Name, S.Name.data(), COFF::NameSize); } } - for (auto &S : Obj.Symbols) { + for (auto &S : Obj.getMutableSymbols()) { if (S.Name.size() > COFF::NameSize) { S.Sym.Name.Offset.Zeroes = 0; S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name); @@ -75,13 +90,16 @@ template std::pair COFFWriter::finalizeSymbolTable() { - size_t SymTabSize = Obj.Symbols.size() * sizeof(SymbolTy); - for (const auto &S : Obj.Symbols) + size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy); + for (const auto &S : Obj.getSymbols()) SymTabSize += S.AuxData.size(); return std::make_pair(SymTabSize, sizeof(SymbolTy)); } -void COFFWriter::finalize(bool IsBigObj) { +Error COFFWriter::finalize(bool IsBigObj) { + if (Error E = finalizeRelocTargets()) + return E; + size_t SizeOfHeaders = 0; FileAlignment = 1; size_t PeHeaderSize = 0; @@ -149,6 +167,8 @@ Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; FileSize += SymTabSize + StrTabSize; FileSize = alignTo(FileSize, FileAlignment); + + return Error::success(); } void COFFWriter::writeHeaders(bool IsBigObj) { @@ -225,14 +245,16 @@ S.Header.SizeOfRawData - S.Contents.size()); Ptr += S.Header.SizeOfRawData; - std::copy(S.Relocs.begin(), S.Relocs.end(), - reinterpret_cast(Ptr)); + for (const auto &R : S.Relocs) { + memcpy(Ptr, &R.Reloc, sizeof(R.Reloc)); + Ptr += sizeof(R.Reloc); + } } } template void COFFWriter::writeSymbolStringTables() { uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable; - for (const auto &S : Obj.Symbols) { + for (const auto &S : Obj.getSymbols()) { // Convert symbols back to the right size, from coff_symbol32. copySymbol(*reinterpret_cast(Ptr), S.Sym); @@ -248,7 +270,8 @@ } Error COFFWriter::write(bool IsBigObj) { - finalize(IsBigObj); + if (Error E = finalize(IsBigObj)) + return E; Buf.allocate(FileSize);