Skip to content

Commit 10b7296

Browse files
committed
[llvm-objcopy] [COFF] Add support for removing symbols
Differential Revision: https://reviews.llvm.org/D55881 llvm-svn: 350893
1 parent 2511670 commit 10b7296

File tree

11 files changed

+290
-14
lines changed

11 files changed

+290
-14
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_AMD64
4+
Characteristics: [ ]
5+
sections:
6+
- Name: .text
7+
Characteristics: [ ]
8+
Alignment: 4
9+
SectionData: 488B0500000000488B0500000000488B0500000000
10+
Relocations:
11+
- VirtualAddress: 3
12+
SymbolTableIndex: 0
13+
Type: IMAGE_REL_AMD64_REL32
14+
- VirtualAddress: 10
15+
SymbolTableIndex: 1
16+
Type: IMAGE_REL_AMD64_REL32
17+
- VirtualAddress: 17
18+
SymbolName: foo
19+
Type: IMAGE_REL_AMD64_REL32
20+
- Name: .rdata
21+
Characteristics: [ ]
22+
Alignment: 1
23+
SectionData: '00'
24+
- Name: .rdata
25+
Characteristics: [ ]
26+
Alignment: 1
27+
SectionData: '01'
28+
symbols:
29+
- Name: .rdata
30+
Value: 0
31+
SectionNumber: 2
32+
SimpleType: IMAGE_SYM_TYPE_NULL
33+
ComplexType: IMAGE_SYM_DTYPE_NULL
34+
StorageClass: IMAGE_SYM_CLASS_STATIC
35+
- Name: .rdata
36+
Value: 0
37+
SectionNumber: 3
38+
SimpleType: IMAGE_SYM_TYPE_NULL
39+
ComplexType: IMAGE_SYM_DTYPE_NULL
40+
StorageClass: IMAGE_SYM_CLASS_STATIC
41+
- Name: mainfunc
42+
Value: 0
43+
SectionNumber: 1
44+
SimpleType: IMAGE_SYM_TYPE_NULL
45+
ComplexType: IMAGE_SYM_DTYPE_NULL
46+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
47+
- Name: foo
48+
Value: 0
49+
SectionNumber: 3
50+
SimpleType: IMAGE_SYM_TYPE_NULL
51+
ComplexType: IMAGE_SYM_DTYPE_NULL
52+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
53+
...
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# RUN: yaml2obj %p/Inputs/strip-symbols.yaml > %t.o
2+
# RUN: not llvm-objcopy -N foo %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
3+
# RUN: not llvm-objcopy --strip-symbol foo %t.o 2>&1 | FileCheck %s --check-prefix=ERROR
4+
5+
# ERROR: error: '{{.*}}/strip-reloc-symbol.test.tmp.o': not stripping symbol 'foo' because it is named in a relocation.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# RUN: yaml2obj %p/Inputs/strip-symbols.yaml > %t.in.o
2+
3+
# RUN: llvm-readobj -relocations %t.in.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-PRE
4+
# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-PRE
5+
6+
# RUN: llvm-objcopy -N mainfunc %t.in.o %t.out.o
7+
# RUN: llvm-readobj -relocations %t.out.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-POST
8+
# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefix=SYMBOLS
9+
10+
# RUN: llvm-objcopy --strip-symbol mainfunc %t.in.o %t.out.o
11+
# RUN: llvm-readobj -relocations %t.out.o | FileCheck %s --check-prefixes=RELOCS,RELOCS-POST
12+
# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefix=SYMBOLS
13+
14+
# Explicitly listing the relocations for the input as well, to show
15+
# that the symbol index of the symbol foo is updated in the relocations,
16+
# while keeping relocations to two distinct .rdata symbols separate.
17+
18+
# RELOCS: Relocations [
19+
# RELOCS-NEXT: Section (1) .text {
20+
# RELOCS-NEXT: 0x3 IMAGE_REL_AMD64_REL32 .rdata (0)
21+
# RELOCS-NEXT: 0xA IMAGE_REL_AMD64_REL32 .rdata (1)
22+
# RELOCS-PRE-NEXT: 0x11 IMAGE_REL_AMD64_REL32 foo (3)
23+
# RELOCS-POST-NEXT: 0x11 IMAGE_REL_AMD64_REL32 foo (2)
24+
# RELOCS-NEXT: }
25+
# RELOCS-NEXT: ]
26+
27+
# SYMBOLS: SYMBOL TABLE:
28+
# SYMBOLS-NEXT: .rdata
29+
# SYMBOLS-NEXT: .rdata
30+
# SYMBOLS-PRE-NEXT: mainfunc
31+
# SYMBOLS-NEXT: foo
32+
# SYMBOLS-EMPTY:

llvm/tools/llvm-objcopy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_llvm_tool(llvm-objcopy
1818
CopyConfig.cpp
1919
llvm-objcopy.cpp
2020
COFF/COFFObjcopy.cpp
21+
COFF/Object.cpp
2122
COFF/Reader.cpp
2223
COFF/Writer.cpp
2324
ELF/ELFObjcopy.cpp

llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "llvm/Object/Binary.h"
1919
#include "llvm/Object/COFF.h"
20+
#include "llvm/Support/Errc.h"
2021
#include <cassert>
2122

2223
namespace llvm {
@@ -26,6 +27,30 @@ namespace coff {
2627
using namespace object;
2728
using namespace COFF;
2829

30+
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
31+
// If we need to do per-symbol removals, initialize the Referenced field.
32+
if (!Config.SymbolsToRemove.empty())
33+
if (Error E = Obj.markSymbols())
34+
return E;
35+
36+
// Actually do removals of symbols.
37+
Obj.removeSymbols([&](const Symbol &Sym) {
38+
if (is_contained(Config.SymbolsToRemove, Sym.Name)) {
39+
// Explicitly removing a referenced symbol is an error.
40+
if (Sym.Referenced)
41+
reportError(Config.OutputFilename,
42+
make_error<StringError>(
43+
"not stripping symbol '" + Sym.Name +
44+
"' because it is named in a relocation.",
45+
llvm::errc::invalid_argument));
46+
return true;
47+
}
48+
49+
return false;
50+
});
51+
return Error::success();
52+
}
53+
2954
void executeObjcopyOnBinary(const CopyConfig &Config,
3055
object::COFFObjectFile &In, Buffer &Out) {
3156
COFFReader Reader(In);
@@ -34,6 +59,8 @@ void executeObjcopyOnBinary(const CopyConfig &Config,
3459
reportError(Config.InputFilename, ObjOrErr.takeError());
3560
Object *Obj = ObjOrErr->get();
3661
assert(Obj && "Unable to deserialize COFF object");
62+
if (Error E = handleArgs(Config, *Obj))
63+
reportError(Config.InputFilename, std::move(E));
3764
COFFWriter Writer(*Obj, Out);
3865
if (Error E = Writer.write())
3966
reportError(Config.OutputFilename, std::move(E));
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//===- Object.cpp ---------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "Object.h"
11+
#include <algorithm>
12+
13+
namespace llvm {
14+
namespace objcopy {
15+
namespace coff {
16+
17+
using namespace object;
18+
19+
void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
20+
for (Symbol S : NewSymbols) {
21+
S.UniqueId = NextSymbolUniqueId++;
22+
Symbols.emplace_back(S);
23+
}
24+
updateSymbols();
25+
}
26+
27+
void Object::updateSymbols() {
28+
SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
29+
size_t RawSymIndex = 0;
30+
for (Symbol &Sym : Symbols) {
31+
SymbolMap[Sym.UniqueId] = &Sym;
32+
Sym.RawIndex = RawSymIndex;
33+
RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols;
34+
}
35+
}
36+
37+
const Symbol *Object::findSymbol(size_t UniqueId) const {
38+
auto It = SymbolMap.find(UniqueId);
39+
if (It == SymbolMap.end())
40+
return nullptr;
41+
return It->second;
42+
}
43+
44+
void Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
45+
Symbols.erase(
46+
std::remove_if(std::begin(Symbols), std::end(Symbols),
47+
[ToRemove](const Symbol &Sym) { return ToRemove(Sym); }),
48+
std::end(Symbols));
49+
updateSymbols();
50+
}
51+
52+
Error Object::markSymbols() {
53+
for (Symbol &Sym : Symbols)
54+
Sym.Referenced = false;
55+
for (const Section &Sec : Sections) {
56+
for (const Relocation &R : Sec.Relocs) {
57+
auto It = SymbolMap.find(R.Target);
58+
if (It == SymbolMap.end())
59+
return make_error<StringError>("Relocation target " + Twine(R.Target) +
60+
" not found",
61+
object_error::invalid_symbol_index);
62+
It->second->Referenced = true;
63+
}
64+
}
65+
return Error::success();
66+
}
67+
68+
} // end namespace coff
69+
} // end namespace objcopy
70+
} // end namespace llvm

llvm/tools/llvm-objcopy/COFF/Object.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
#define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
1212

1313
#include "llvm/ADT/ArrayRef.h"
14+
#include "llvm/ADT/DenseMap.h"
1415
#include "llvm/ADT/StringRef.h"
16+
#include "llvm/ADT/iterator_range.h"
1517
#include "llvm/BinaryFormat/COFF.h"
1618
#include "llvm/Object/COFF.h"
1719
#include <cstddef>
@@ -22,17 +24,26 @@ namespace llvm {
2224
namespace objcopy {
2325
namespace coff {
2426

27+
struct Relocation {
28+
object::coff_relocation Reloc;
29+
size_t Target;
30+
StringRef TargetName; // Used for diagnostics only
31+
};
32+
2533
struct Section {
2634
object::coff_section Header;
2735
ArrayRef<uint8_t> Contents;
28-
std::vector<object::coff_relocation> Relocs;
36+
std::vector<Relocation> Relocs;
2937
StringRef Name;
3038
};
3139

3240
struct Symbol {
3341
object::coff_symbol32 Sym;
3442
StringRef Name;
3543
ArrayRef<uint8_t> AuxData;
44+
size_t UniqueId;
45+
size_t RawIndex;
46+
bool Referenced;
3647
};
3748

3849
struct Object {
@@ -49,7 +60,31 @@ struct Object {
4960

5061
std::vector<object::data_directory> DataDirectories;
5162
std::vector<Section> Sections;
63+
64+
ArrayRef<Symbol> getSymbols() const { return Symbols; }
65+
// This allows mutating individual Symbols, but not mutating the list
66+
// of symbols itself.
67+
iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
68+
return make_range(Symbols.begin(), Symbols.end());
69+
}
70+
71+
const Symbol *findSymbol(size_t UniqueId) const;
72+
73+
void addSymbols(ArrayRef<Symbol> NewSymbols);
74+
void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
75+
76+
// Set the Referenced field on all Symbols, based on relocations in
77+
// all sections.
78+
Error markSymbols();
79+
80+
private:
5281
std::vector<Symbol> Symbols;
82+
DenseMap<size_t, Symbol *> SymbolMap;
83+
84+
size_t NextSymbolUniqueId = 0;
85+
86+
// Update SymbolMap and RawIndex in each Symbol.
87+
void updateSymbols();
5388
};
5489

5590
// Copy between coff_symbol16 and coff_symbol32.

llvm/tools/llvm-objcopy/COFF/Reader.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Error COFFReader::readSections(Object &Obj) const {
7373
return errorCodeToError(EC);
7474
ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
7575
for (const coff_relocation &R : Relocs)
76-
S.Relocs.push_back(R);
76+
S.Relocs.push_back(Relocation{R});
7777
if (auto EC = COFFObj.getSectionName(Sec, S.Name))
7878
return errorCodeToError(EC);
7979
if (Sec->hasExtendedRelocations())
@@ -84,14 +84,16 @@ Error COFFReader::readSections(Object &Obj) const {
8484
}
8585

8686
Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
87+
std::vector<Symbol> Symbols;
88+
Symbols.reserve(COFFObj.getRawNumberOfSymbols());
8789
for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
8890
Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
8991
if (!SymOrErr)
9092
return SymOrErr.takeError();
9193
COFFSymbolRef SymRef = *SymOrErr;
9294

93-
Obj.Symbols.push_back(Symbol());
94-
Symbol &Sym = Obj.Symbols.back();
95+
Symbols.push_back(Symbol());
96+
Symbol &Sym = Symbols.back();
9597
// Copy symbols from the original form into an intermediate coff_symbol32.
9698
if (IsBigObj)
9799
copySymbol(Sym.Sym,
@@ -106,6 +108,30 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
106108
(IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
107109
I += 1 + SymRef.getNumberOfAuxSymbols();
108110
}
111+
Obj.addSymbols(Symbols);
112+
return Error::success();
113+
}
114+
115+
Error COFFReader::setRelocTargets(Object &Obj) const {
116+
std::vector<const Symbol *> RawSymbolTable;
117+
for (const Symbol &Sym : Obj.getSymbols()) {
118+
RawSymbolTable.push_back(&Sym);
119+
for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
120+
RawSymbolTable.push_back(nullptr);
121+
}
122+
for (Section &Sec : Obj.Sections) {
123+
for (Relocation &R : Sec.Relocs) {
124+
if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
125+
return make_error<StringError>("SymbolTableIndex out of range",
126+
object_error::parse_failed);
127+
const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
128+
if (Sym == nullptr)
129+
return make_error<StringError>("Invalid SymbolTableIndex",
130+
object_error::parse_failed);
131+
R.Target = Sym->UniqueId;
132+
R.TargetName = Sym->Name;
133+
}
134+
}
109135
return Error::success();
110136
}
111137

@@ -136,6 +162,8 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
136162
return std::move(E);
137163
if (Error E = readSymbols(*Obj, IsBigObj))
138164
return std::move(E);
165+
if (Error E = setRelocTargets(*Obj))
166+
return std::move(E);
139167

140168
return std::move(Obj);
141169
}

llvm/tools/llvm-objcopy/COFF/Reader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class COFFReader : public Reader {
3535
Error readExecutableHeaders(Object &Obj) const;
3636
Error readSections(Object &Obj) const;
3737
Error readSymbols(Object &Obj, bool IsBigObj) const;
38+
Error setRelocTargets(Object &Obj) const;
3839

3940
public:
4041
explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}

0 commit comments

Comments
 (0)