1 //===- COFFObjcopy.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 "COFFObjcopy.h"
11 #include "Buffer.h"
12 #include "CopyConfig.h"
13 #include "Object.h"
14 #include "Reader.h"
15 #include "Writer.h"
16 #include "llvm-objcopy.h"
17
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/COFF.h"
20 #include "llvm/Support/Errc.h"
21 #include <cassert>
22
23 namespace llvm {
24 namespace objcopy {
25 namespace coff {
26
27 using namespace object;
28 using namespace COFF;
29
handleArgs(const CopyConfig & Config,Object & Obj)30 static Error handleArgs(const CopyConfig &Config, Object &Obj) {
31 // StripAll removes all symbols and thus also removes all relocations.
32 if (Config.StripAll || Config.StripAllGNU)
33 for (Section &Sec : Obj.Sections)
34 Sec.Relocs.clear();
35
36 // If we need to do per-symbol removals, initialize the Referenced field.
37 if (Config.StripUnneeded || Config.DiscardAll ||
38 !Config.SymbolsToRemove.empty())
39 if (Error E = Obj.markSymbols())
40 return E;
41
42 // Actually do removals of symbols.
43 Obj.removeSymbols([&](const Symbol &Sym) {
44 // For StripAll, all relocations have been stripped and we remove all
45 // symbols.
46 if (Config.StripAll || Config.StripAllGNU)
47 return true;
48
49 if (is_contained(Config.SymbolsToRemove, Sym.Name)) {
50 // Explicitly removing a referenced symbol is an error.
51 if (Sym.Referenced)
52 reportError(Config.OutputFilename,
53 make_error<StringError>(
54 "not stripping symbol '" + Sym.Name +
55 "' because it is named in a relocation.",
56 llvm::errc::invalid_argument));
57 return true;
58 }
59
60 if (!Sym.Referenced) {
61 // With --strip-unneeded, GNU objcopy removes all unreferenced local
62 // symbols, and any unreferenced undefined external.
63 if (Config.StripUnneeded &&
64 (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
65 Sym.Sym.SectionNumber == 0))
66 return true;
67
68 // GNU objcopy keeps referenced local symbols and external symbols
69 // if --discard-all is set, similar to what --strip-unneeded does,
70 // but undefined local symbols are kept when --discard-all is set.
71 if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
72 Sym.Sym.SectionNumber != 0)
73 return true;
74 }
75
76 return false;
77 });
78 return Error::success();
79 }
80
executeObjcopyOnBinary(const CopyConfig & Config,object::COFFObjectFile & In,Buffer & Out)81 void executeObjcopyOnBinary(const CopyConfig &Config,
82 object::COFFObjectFile &In, Buffer &Out) {
83 COFFReader Reader(In);
84 Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
85 if (!ObjOrErr)
86 reportError(Config.InputFilename, ObjOrErr.takeError());
87 Object *Obj = ObjOrErr->get();
88 assert(Obj && "Unable to deserialize COFF object");
89 if (Error E = handleArgs(Config, *Obj))
90 reportError(Config.InputFilename, std::move(E));
91 COFFWriter Writer(*Obj, Out);
92 if (Error E = Writer.write())
93 reportError(Config.OutputFilename, std::move(E));
94 }
95
96 } // end namespace coff
97 } // end namespace objcopy
98 } // end namespace llvm
99