blob: dd2e48292185bb58c8530f47bec2a9a5e0b0da68 [file] [log] [blame]
Martin Storsjoe84a0b52018-12-19 07:24:38 +00001//===- COFFObjcopy.cpp ----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Martin Storsjoe84a0b52018-12-19 07:24:38 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "COFFObjcopy.h"
10#include "Buffer.h"
11#include "CopyConfig.h"
12#include "Object.h"
13#include "Reader.h"
14#include "Writer.h"
15#include "llvm-objcopy.h"
16
17#include "llvm/Object/Binary.h"
18#include "llvm/Object/COFF.h"
Martin Storsjo10b72962019-01-10 21:28:24 +000019#include "llvm/Support/Errc.h"
Martin Storsjoe84a0b52018-12-19 07:24:38 +000020#include <cassert>
21
22namespace llvm {
23namespace objcopy {
24namespace coff {
25
26using namespace object;
27using namespace COFF;
28
Martin Storsjo10b72962019-01-10 21:28:24 +000029static Error handleArgs(const CopyConfig &Config, Object &Obj) {
Martin Storsjof9e14342019-01-19 19:42:35 +000030 // Perform the actual section removals.
31 Obj.removeSections([&Config](const Section &Sec) {
32 if (is_contained(Config.ToRemove, Sec.Name))
33 return true;
34
35 return false;
36 });
37
Martin Storsjof51f5ea2019-01-15 09:34:55 +000038 // StripAll removes all symbols and thus also removes all relocations.
39 if (Config.StripAll || Config.StripAllGNU)
Martin Storsjof9e14342019-01-19 19:42:35 +000040 for (Section &Sec : Obj.getMutableSections())
Martin Storsjof51f5ea2019-01-15 09:34:55 +000041 Sec.Relocs.clear();
42
Martin Storsjo10b72962019-01-10 21:28:24 +000043 // If we need to do per-symbol removals, initialize the Referenced field.
Martin Storsjofb909202019-01-11 14:13:04 +000044 if (Config.StripUnneeded || Config.DiscardAll ||
45 !Config.SymbolsToRemove.empty())
Martin Storsjo10b72962019-01-10 21:28:24 +000046 if (Error E = Obj.markSymbols())
47 return E;
48
49 // Actually do removals of symbols.
50 Obj.removeSymbols([&](const Symbol &Sym) {
Martin Storsjof51f5ea2019-01-15 09:34:55 +000051 // For StripAll, all relocations have been stripped and we remove all
52 // symbols.
53 if (Config.StripAll || Config.StripAllGNU)
54 return true;
55
Martin Storsjo10b72962019-01-10 21:28:24 +000056 if (is_contained(Config.SymbolsToRemove, Sym.Name)) {
57 // Explicitly removing a referenced symbol is an error.
58 if (Sym.Referenced)
59 reportError(Config.OutputFilename,
60 make_error<StringError>(
61 "not stripping symbol '" + Sym.Name +
62 "' because it is named in a relocation.",
63 llvm::errc::invalid_argument));
64 return true;
65 }
66
Martin Storsjo4b0694b2019-01-14 18:56:47 +000067 if (!Sym.Referenced) {
68 // With --strip-unneeded, GNU objcopy removes all unreferenced local
69 // symbols, and any unreferenced undefined external.
70 if (Config.StripUnneeded &&
71 (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
72 Sym.Sym.SectionNumber == 0))
Martin Storsjofb909202019-01-11 14:13:04 +000073 return true;
Martin Storsjo4b0694b2019-01-14 18:56:47 +000074
Martin Storsjofb909202019-01-11 14:13:04 +000075 // GNU objcopy keeps referenced local symbols and external symbols
76 // if --discard-all is set, similar to what --strip-unneeded does,
77 // but undefined local symbols are kept when --discard-all is set.
Martin Storsjo4b0694b2019-01-14 18:56:47 +000078 if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
79 Sym.Sym.SectionNumber != 0)
Martin Storsjofb909202019-01-11 14:13:04 +000080 return true;
81 }
82
Martin Storsjo10b72962019-01-10 21:28:24 +000083 return false;
84 });
85 return Error::success();
86}
87
Martin Storsjoe84a0b52018-12-19 07:24:38 +000088void executeObjcopyOnBinary(const CopyConfig &Config,
Martin Storsjo10042422019-01-19 19:42:23 +000089 COFFObjectFile &In, Buffer &Out) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +000090 COFFReader Reader(In);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000091 Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
92 if (!ObjOrErr)
93 reportError(Config.InputFilename, ObjOrErr.takeError());
94 Object *Obj = ObjOrErr->get();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000095 assert(Obj && "Unable to deserialize COFF object");
Martin Storsjo10b72962019-01-10 21:28:24 +000096 if (Error E = handleArgs(Config, *Obj))
97 reportError(Config.InputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000098 COFFWriter Writer(*Obj, Out);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000099 if (Error E = Writer.write())
100 reportError(Config.OutputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000101}
102
103} // end namespace coff
104} // end namespace objcopy
105} // end namespace llvm