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