1 //===- COFFObjcopy.cpp ----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "COFFObjcopy.h"
11 #include "CopyConfig.h"
15 #include "llvm-objcopy.h"
17 #include "llvm/Object/Binary.h"
18 #include "llvm/Object/COFF.h"
19 #include "llvm/Support/Errc.h"
26 using namespace object
;
29 static bool isDebugSection(const Section
&Sec
) {
30 return Sec
.Name
.startswith(".debug");
33 static Error
handleArgs(const CopyConfig
&Config
, Object
&Obj
) {
34 // Perform the actual section removals.
35 Obj
.removeSections([&Config
](const Section
&Sec
) {
36 if (Config
.StripDebug
|| Config
.StripAll
|| Config
.StripAllGNU
||
37 Config
.DiscardAll
|| Config
.StripUnneeded
) {
38 if (isDebugSection(Sec
) &&
39 (Sec
.Header
.Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
) != 0)
43 if (is_contained(Config
.ToRemove
, Sec
.Name
))
49 if (Config
.OnlyKeepDebug
) {
50 // For --only-keep-debug, we keep all other sections, but remove their
51 // content. The VirtualSize field in the section header is kept intact.
52 Obj
.truncateSections([](const Section
&Sec
) {
53 return !isDebugSection(Sec
) && Sec
.Name
!= ".buildid" &&
54 ((Sec
.Header
.Characteristics
&
55 (IMAGE_SCN_CNT_CODE
| IMAGE_SCN_CNT_INITIALIZED_DATA
)) != 0);
59 // StripAll removes all symbols and thus also removes all relocations.
60 if (Config
.StripAll
|| Config
.StripAllGNU
)
61 for (Section
&Sec
: Obj
.getMutableSections())
64 // If we need to do per-symbol removals, initialize the Referenced field.
65 if (Config
.StripUnneeded
|| Config
.DiscardAll
||
66 !Config
.SymbolsToRemove
.empty())
67 if (Error E
= Obj
.markSymbols())
70 // Actually do removals of symbols.
71 Obj
.removeSymbols([&](const Symbol
&Sym
) {
72 // For StripAll, all relocations have been stripped and we remove all
74 if (Config
.StripAll
|| Config
.StripAllGNU
)
77 if (is_contained(Config
.SymbolsToRemove
, Sym
.Name
)) {
78 // Explicitly removing a referenced symbol is an error.
80 reportError(Config
.OutputFilename
,
81 make_error
<StringError
>(
82 "not stripping symbol '" + Sym
.Name
+
83 "' because it is named in a relocation.",
84 llvm::errc::invalid_argument
));
88 if (!Sym
.Referenced
) {
89 // With --strip-unneeded, GNU objcopy removes all unreferenced local
90 // symbols, and any unreferenced undefined external.
91 if (Config
.StripUnneeded
&&
92 (Sym
.Sym
.StorageClass
== IMAGE_SYM_CLASS_STATIC
||
93 Sym
.Sym
.SectionNumber
== 0))
96 // GNU objcopy keeps referenced local symbols and external symbols
97 // if --discard-all is set, similar to what --strip-unneeded does,
98 // but undefined local symbols are kept when --discard-all is set.
99 if (Config
.DiscardAll
&& Sym
.Sym
.StorageClass
== IMAGE_SYM_CLASS_STATIC
&&
100 Sym
.Sym
.SectionNumber
!= 0)
106 return Error::success();
109 void executeObjcopyOnBinary(const CopyConfig
&Config
,
110 COFFObjectFile
&In
, Buffer
&Out
) {
111 COFFReader
Reader(In
);
112 Expected
<std::unique_ptr
<Object
>> ObjOrErr
= Reader
.create();
114 reportError(Config
.InputFilename
, ObjOrErr
.takeError());
115 Object
*Obj
= ObjOrErr
->get();
116 assert(Obj
&& "Unable to deserialize COFF object");
117 if (Error E
= handleArgs(Config
, *Obj
))
118 reportError(Config
.InputFilename
, std::move(E
));
119 COFFWriter
Writer(*Obj
, Out
);
120 if (Error E
= Writer
.write())
121 reportError(Config
.OutputFilename
, std::move(E
));
124 } // end namespace coff
125 } // end namespace objcopy
126 } // end namespace llvm