blob: 6b386d29979c0f2d71b8b798c9211fc995b01bc7 [file] [log] [blame]
Martin Storsjoe84a0b52018-12-19 07:24:38 +00001//===- 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"
Martin Storsjo10b72962019-01-10 21:28:24 +000020#include "llvm/Support/Errc.h"
Martin Storsjoe84a0b52018-12-19 07:24:38 +000021#include <cassert>
22
23namespace llvm {
24namespace objcopy {
25namespace coff {
26
27using namespace object;
28using namespace COFF;
29
Martin Storsjo10b72962019-01-10 21:28:24 +000030static Error handleArgs(const CopyConfig &Config, Object &Obj) {
Martin Storsjof51f5ea2019-01-15 09:34:55 +000031 // 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
Martin Storsjo10b72962019-01-10 21:28:24 +000036 // If we need to do per-symbol removals, initialize the Referenced field.
Martin Storsjofb909202019-01-11 14:13:04 +000037 if (Config.StripUnneeded || Config.DiscardAll ||
38 !Config.SymbolsToRemove.empty())
Martin Storsjo10b72962019-01-10 21:28:24 +000039 if (Error E = Obj.markSymbols())
40 return E;
41
42 // Actually do removals of symbols.
43 Obj.removeSymbols([&](const Symbol &Sym) {
Martin Storsjof51f5ea2019-01-15 09:34:55 +000044 // For StripAll, all relocations have been stripped and we remove all
45 // symbols.
46 if (Config.StripAll || Config.StripAllGNU)
47 return true;
48
Martin Storsjo10b72962019-01-10 21:28:24 +000049 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
Martin Storsjo4b0694b2019-01-14 18:56:47 +000060 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))
Martin Storsjofb909202019-01-11 14:13:04 +000066 return true;
Martin Storsjo4b0694b2019-01-14 18:56:47 +000067
Martin Storsjofb909202019-01-11 14:13:04 +000068 // 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.
Martin Storsjo4b0694b2019-01-14 18:56:47 +000071 if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
72 Sym.Sym.SectionNumber != 0)
Martin Storsjofb909202019-01-11 14:13:04 +000073 return true;
74 }
75
Martin Storsjo10b72962019-01-10 21:28:24 +000076 return false;
77 });
78 return Error::success();
79}
80
Martin Storsjoe84a0b52018-12-19 07:24:38 +000081void executeObjcopyOnBinary(const CopyConfig &Config,
82 object::COFFObjectFile &In, Buffer &Out) {
83 COFFReader Reader(In);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000084 Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
85 if (!ObjOrErr)
86 reportError(Config.InputFilename, ObjOrErr.takeError());
87 Object *Obj = ObjOrErr->get();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000088 assert(Obj && "Unable to deserialize COFF object");
Martin Storsjo10b72962019-01-10 21:28:24 +000089 if (Error E = handleArgs(Config, *Obj))
90 reportError(Config.InputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000091 COFFWriter Writer(*Obj, Out);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000092 if (Error E = Writer.write())
93 reportError(Config.OutputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000094}
95
96} // end namespace coff
97} // end namespace objcopy
98} // end namespace llvm