[llvm-objcopy] [COFF] Add support for removing symbols

Differential Revision: https://reviews.llvm.org/D55881

llvm-svn: 350893
This commit is contained in:
Martin Storsjo 2019-01-10 21:28:24 +00:00
parent 25116708c4
commit 10b7296484
11 changed files with 290 additions and 14 deletions

View File

@ -0,0 +1,53 @@
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: [ ]
sections:
- Name: .text
Characteristics: [ ]
Alignment: 4
SectionData: 488B0500000000488B0500000000488B0500000000
Relocations:
- VirtualAddress: 3
SymbolTableIndex: 0
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 10
SymbolTableIndex: 1
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 17
SymbolName: foo
Type: IMAGE_REL_AMD64_REL32
- Name: .rdata
Characteristics: [ ]
Alignment: 1
SectionData: '00'
- Name: .rdata
Characteristics: [ ]
Alignment: 1
SectionData: '01'
symbols:
- Name: .rdata
Value: 0
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: .rdata
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: mainfunc
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: foo
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...

View File

@ -0,0 +1,5 @@
# RUN: yaml2obj %p/Inputs/strip-symbols.yaml > %t.o
# RUN: not llvm-objcopy -N foo %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
# RUN: not llvm-objcopy --strip-symbol foo %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
# ERROR: error: '{{.*}}/strip-reloc-symbol.test.tmp.o': not stripping symbol 'foo' because it is named in a relocation.

View File

@ -0,0 +1,32 @@
# RUN: yaml2obj %p/Inputs/strip-symbols.yaml > %t.in.o
# RUN: llvm-readobj -relocations %t.in.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-PRE
# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-PRE
# RUN: llvm-objcopy -N mainfunc %t.in.o %t.out.o
# RUN: llvm-readobj -relocations %t.out.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-POST
# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefix=SYMBOLS
# RUN: llvm-objcopy --strip-symbol mainfunc %t.in.o %t.out.o
# RUN: llvm-readobj -relocations %t.out.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-POST
# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefix=SYMBOLS
# Explicitly listing the relocations for the input as well, to show
# that the symbol index of the symbol foo is updated in the relocations,
# while keeping relocations to two distinct .rdata symbols separate.
# RELOCS: Relocations [
# RELOCS-NEXT: Section (1) .text {
# RELOCS-NEXT: 0x3 IMAGE_REL_AMD64_REL32 .rdata (0)
# RELOCS-NEXT: 0xA IMAGE_REL_AMD64_REL32 .rdata (1)
# RELOCS-PRE-NEXT: 0x11 IMAGE_REL_AMD64_REL32 foo (3)
# RELOCS-POST-NEXT: 0x11 IMAGE_REL_AMD64_REL32 foo (2)
# RELOCS-NEXT: }
# RELOCS-NEXT: ]
# SYMBOLS: SYMBOL TABLE:
# SYMBOLS-NEXT: .rdata
# SYMBOLS-NEXT: .rdata
# SYMBOLS-PRE-NEXT: mainfunc
# SYMBOLS-NEXT: foo
# SYMBOLS-EMPTY:

View File

@ -18,6 +18,7 @@ add_llvm_tool(llvm-objcopy
CopyConfig.cpp
llvm-objcopy.cpp
COFF/COFFObjcopy.cpp
COFF/Object.cpp
COFF/Reader.cpp
COFF/Writer.cpp
ELF/ELFObjcopy.cpp

View File

@ -17,6 +17,7 @@
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Errc.h"
#include <cassert>
namespace llvm {
@ -26,6 +27,30 @@ namespace coff {
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<StringError>(
"not stripping symbol '" + Sym.Name +
"' because it is named in a relocation.",
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 +59,8 @@ void executeObjcopyOnBinary(const CopyConfig &Config,
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));

View File

@ -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 <algorithm>
namespace llvm {
namespace objcopy {
namespace coff {
using namespace object;
void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
for (Symbol S : NewSymbols) {
S.UniqueId = NextSymbolUniqueId++;
Symbols.emplace_back(S);
}
updateSymbols();
}
void Object::updateSymbols() {
SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
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<bool(const Symbol &)> 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<StringError>("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

View File

@ -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 <cstddef>
@ -22,10 +24,16 @@ namespace llvm {
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<uint8_t> Contents;
std::vector<object::coff_relocation> Relocs;
std::vector<Relocation> Relocs;
StringRef Name;
};
@ -33,6 +41,9 @@ struct Symbol {
object::coff_symbol32 Sym;
StringRef Name;
ArrayRef<uint8_t> AuxData;
size_t UniqueId;
size_t RawIndex;
bool Referenced;
};
struct Object {
@ -49,7 +60,31 @@ struct Object {
std::vector<object::data_directory> DataDirectories;
std::vector<Section> Sections;
ArrayRef<Symbol> getSymbols() const { return Symbols; }
// This allows mutating individual Symbols, but not mutating the list
// of symbols itself.
iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
return make_range(Symbols.begin(), Symbols.end());
}
const Symbol *findSymbol(size_t UniqueId) const;
void addSymbols(ArrayRef<Symbol> NewSymbols);
void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
// Set the Referenced field on all Symbols, based on relocations in
// all sections.
Error markSymbols();
private:
std::vector<Symbol> Symbols;
DenseMap<size_t, Symbol *> SymbolMap;
size_t NextSymbolUniqueId = 0;
// Update SymbolMap and RawIndex in each Symbol.
void updateSymbols();
};
// Copy between coff_symbol16 and coff_symbol32.

View File

@ -73,7 +73,7 @@ Error COFFReader::readSections(Object &Obj) const {
return errorCodeToError(EC);
ArrayRef<coff_relocation> 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,16 @@ Error COFFReader::readSections(Object &Obj) const {
}
Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
std::vector<Symbol> Symbols;
Symbols.reserve(COFFObj.getRawNumberOfSymbols());
for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
Expected<COFFSymbolRef> 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 +108,30 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
(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<const Symbol *> 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<StringError>("SymbolTableIndex out of range",
object_error::parse_failed);
const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
if (Sym == nullptr)
return make_error<StringError>("Invalid SymbolTableIndex",
object_error::parse_failed);
R.Target = Sym->UniqueId;
R.TargetName = Sym->Name;
}
}
return Error::success();
}
@ -136,6 +162,8 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
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);
}

View File

@ -35,6 +35,7 @@ class COFFReader : public Reader {
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) {}

View File

@ -27,6 +27,21 @@ using namespace COFF;
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<StringError>("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 @@ size_t COFFWriter::finalizeStringTable() {
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 @@ size_t COFFWriter::finalizeStringTable() {
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 @@ size_t COFFWriter::finalizeStringTable() {
template <class SymbolTy>
std::pair<size_t, size_t> 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 @@ void COFFWriter::finalize(bool IsBigObj) {
Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
FileSize += SymTabSize + StrTabSize;
FileSize = alignTo(FileSize, FileAlignment);
return Error::success();
}
void COFFWriter::writeHeaders(bool IsBigObj) {
@ -225,14 +245,16 @@ void COFFWriter::writeSections() {
S.Header.SizeOfRawData - S.Contents.size());
Ptr += S.Header.SizeOfRawData;
std::copy(S.Relocs.begin(), S.Relocs.end(),
reinterpret_cast<coff_relocation *>(Ptr));
for (const auto &R : S.Relocs) {
memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
Ptr += sizeof(R.Reloc);
}
}
}
template <class SymbolTy> 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<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
S.Sym);
@ -248,7 +270,8 @@ template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
}
Error COFFWriter::write(bool IsBigObj) {
finalize(IsBigObj);
if (Error E = finalize(IsBigObj))
return E;
Buf.allocate(FileSize);

View File

@ -40,11 +40,12 @@ class COFFWriter : public Writer {
size_t SizeOfInitializedData;
StringTableBuilder StrTabBuilder;
Error finalizeRelocTargets();
void layoutSections();
size_t finalizeStringTable();
template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
void finalize(bool IsBigObj);
Error finalize(bool IsBigObj);
void writeHeaders(bool IsBigObj);
void writeSections();