blob: d48bd0267faeaf2e4bbdaac10c298f1159e24d4c [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) {
31 // If we need to do per-symbol removals, initialize the Referenced field.
Martin Storsjofb909202019-01-11 14:13:04 +000032 if (Config.StripUnneeded || Config.DiscardAll ||
33 !Config.SymbolsToRemove.empty())
Martin Storsjo10b72962019-01-10 21:28:24 +000034 if (Error E = Obj.markSymbols())
35 return E;
36
37 // Actually do removals of symbols.
38 Obj.removeSymbols([&](const Symbol &Sym) {
39 if (is_contained(Config.SymbolsToRemove, Sym.Name)) {
40 // Explicitly removing a referenced symbol is an error.
41 if (Sym.Referenced)
42 reportError(Config.OutputFilename,
43 make_error<StringError>(
44 "not stripping symbol '" + Sym.Name +
45 "' because it is named in a relocation.",
46 llvm::errc::invalid_argument));
47 return true;
48 }
49
Martin Storsjofb909202019-01-11 14:13:04 +000050 if (!Sym.Referenced && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
51 if (Config.StripUnneeded)
52 return true;
53 // GNU objcopy keeps referenced local symbols and external symbols
54 // if --discard-all is set, similar to what --strip-unneeded does,
55 // but undefined local symbols are kept when --discard-all is set.
56 if (Config.DiscardAll && Sym.Sym.SectionNumber != 0)
57 return true;
58 }
59
Martin Storsjo10b72962019-01-10 21:28:24 +000060 return false;
61 });
62 return Error::success();
63}
64
Martin Storsjoe84a0b52018-12-19 07:24:38 +000065void executeObjcopyOnBinary(const CopyConfig &Config,
66 object::COFFObjectFile &In, Buffer &Out) {
67 COFFReader Reader(In);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000068 Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
69 if (!ObjOrErr)
70 reportError(Config.InputFilename, ObjOrErr.takeError());
71 Object *Obj = ObjOrErr->get();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000072 assert(Obj && "Unable to deserialize COFF object");
Martin Storsjo10b72962019-01-10 21:28:24 +000073 if (Error E = handleArgs(Config, *Obj))
74 reportError(Config.InputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000075 COFFWriter Writer(*Obj, Out);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000076 if (Error E = Writer.write())
77 reportError(Config.OutputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000078}
79
80} // end namespace coff
81} // end namespace objcopy
82} // end namespace llvm