Index: test/tools/llvm-objcopy/COFF/X86/lit.local.cfg =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/lit.local.cfg @@ -0,0 +1,4 @@ +# These tests require a registered x86 backend. + +if not 'X86' in config.root.targets: + config.unsupported = True Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s @@ -0,0 +1,79 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %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 + +# 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: + + + .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 Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s @@ -0,0 +1,22 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: not llvm-objcopy -N ptr %t.o 2>&1 | FileCheck %s --check-prefix=ERROR + +# ERROR: error: '{{.*}}/remove-symbol2.s.tmp.o': Can't remove referenced symbol 'ptr' + + .text + .globl mainfunc +mainfunc: + movl ptr(%rip), %eax + call otherfunc + ret + .globl otherfunc +otherfunc: + ret + .globl otherfunc2 +otherfunc2: + ret + + .data +ptr: + .long 42 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,29 @@ std::vector DataDirectories; std::vector
Sections; + + const std::vector &getSymbols() const { return Symbols; } + const Symbol *findSymbol(size_t UniqueId) const; + + void addSymbols(const std::vector &NewSymbols); + void removeSymbols(function_ref ToRemove); + + // This allows mutating individual Symbols, but not mutating the list + // of symbols itself. + iterator_range::iterator> getMutableSymbols() { return make_range(Symbols.begin(), Symbols.end()); } + + // 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(const std::vector &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,20 @@ 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 +62,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 +76,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 +89,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 +166,8 @@ Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; FileSize += SymTabSize + StrTabSize; FileSize = alignTo(FileSize, FileAlignment); + + return Error::success(); } void COFFWriter::writeHeaders(bool IsBigObj) { @@ -225,14 +244,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 +269,8 @@ } Error COFFWriter::write(bool IsBigObj) { - finalize(IsBigObj); + if (Error E = finalize(IsBigObj)) + return E; Buf.allocate(FileSize);