blob: ea46b841bcff4550225004c0c0cae17f0122c6b2 [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 Storsjo4b0694b2019-01-14 18:56:47 +000050 if (!Sym.Referenced) {
51 // With --strip-unneeded, GNU objcopy removes all unreferenced local
52 // symbols, and any unreferenced undefined external.
53 if (Config.StripUnneeded &&
54 (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
55 Sym.Sym.SectionNumber == 0))
Martin Storsjofb909202019-01-11 14:13:04 +000056 return true;
Martin Storsjo4b0694b2019-01-14 18:56:47 +000057
Martin Storsjofb909202019-01-11 14:13:04 +000058 // GNU objcopy keeps referenced local symbols and external symbols
59 // if --discard-all is set, similar to what --strip-unneeded does,
60 // but undefined local symbols are kept when --discard-all is set.
Martin Storsjo4b0694b2019-01-14 18:56:47 +000061 if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
62 Sym.Sym.SectionNumber != 0)
Martin Storsjofb909202019-01-11 14:13:04 +000063 return true;
64 }
65
Martin Storsjo10b72962019-01-10 21:28:24 +000066 return false;
67 });
68 return Error::success();
69}
70
Martin Storsjoe84a0b52018-12-19 07:24:38 +000071void executeObjcopyOnBinary(const CopyConfig &Config,
72 object::COFFObjectFile &In, Buffer &Out) {
73 COFFReader Reader(In);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000074 Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
75 if (!ObjOrErr)
76 reportError(Config.InputFilename, ObjOrErr.takeError());
77 Object *Obj = ObjOrErr->get();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000078 assert(Obj && "Unable to deserialize COFF object");
Martin Storsjo10b72962019-01-10 21:28:24 +000079 if (Error E = handleArgs(Config, *Obj))
80 reportError(Config.InputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000081 COFFWriter Writer(*Obj, Out);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000082 if (Error E = Writer.write())
83 reportError(Config.OutputFilename, std::move(E));
Martin Storsjoe84a0b52018-12-19 07:24:38 +000084}
85
86} // end namespace coff
87} // end namespace objcopy
88} // end namespace llvm