xref: /freebsd/contrib/llvm-project/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===- COFFObjcopy.cpp ----------------------------------------------------===//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric 
9*81ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFObjcopy.h"
10*81ad6265SDimitry Andric #include "COFFObject.h"
11*81ad6265SDimitry Andric #include "COFFReader.h"
12*81ad6265SDimitry Andric #include "COFFWriter.h"
13*81ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFConfig.h"
14*81ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h"
15*81ad6265SDimitry Andric 
16*81ad6265SDimitry Andric #include "llvm/Object/Binary.h"
17*81ad6265SDimitry Andric #include "llvm/Object/COFF.h"
18*81ad6265SDimitry Andric #include "llvm/Support/CRC.h"
19*81ad6265SDimitry Andric #include "llvm/Support/Errc.h"
20*81ad6265SDimitry Andric #include "llvm/Support/Path.h"
21*81ad6265SDimitry Andric #include <cassert>
22*81ad6265SDimitry Andric 
23*81ad6265SDimitry Andric namespace llvm {
24*81ad6265SDimitry Andric namespace objcopy {
25*81ad6265SDimitry Andric namespace coff {
26*81ad6265SDimitry Andric 
27*81ad6265SDimitry Andric using namespace object;
28*81ad6265SDimitry Andric using namespace COFF;
29*81ad6265SDimitry Andric 
30*81ad6265SDimitry Andric static bool isDebugSection(const Section &Sec) {
31*81ad6265SDimitry Andric   return Sec.Name.startswith(".debug");
32*81ad6265SDimitry Andric }
33*81ad6265SDimitry Andric 
34*81ad6265SDimitry Andric static uint64_t getNextRVA(const Object &Obj) {
35*81ad6265SDimitry Andric   if (Obj.getSections().empty())
36*81ad6265SDimitry Andric     return 0;
37*81ad6265SDimitry Andric   const Section &Last = Obj.getSections().back();
38*81ad6265SDimitry Andric   return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
39*81ad6265SDimitry Andric                  Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
40*81ad6265SDimitry Andric }
41*81ad6265SDimitry Andric 
42*81ad6265SDimitry Andric static Expected<std::vector<uint8_t>>
43*81ad6265SDimitry Andric createGnuDebugLinkSectionContents(StringRef File) {
44*81ad6265SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
45*81ad6265SDimitry Andric       MemoryBuffer::getFile(File);
46*81ad6265SDimitry Andric   if (!LinkTargetOrErr)
47*81ad6265SDimitry Andric     return createFileError(File, LinkTargetOrErr.getError());
48*81ad6265SDimitry Andric   auto LinkTarget = std::move(*LinkTargetOrErr);
49*81ad6265SDimitry Andric   uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));
50*81ad6265SDimitry Andric 
51*81ad6265SDimitry Andric   StringRef FileName = sys::path::filename(File);
52*81ad6265SDimitry Andric   size_t CRCPos = alignTo(FileName.size() + 1, 4);
53*81ad6265SDimitry Andric   std::vector<uint8_t> Data(CRCPos + 4);
54*81ad6265SDimitry Andric   memcpy(Data.data(), FileName.data(), FileName.size());
55*81ad6265SDimitry Andric   support::endian::write32le(Data.data() + CRCPos, CRC32);
56*81ad6265SDimitry Andric   return Data;
57*81ad6265SDimitry Andric }
58*81ad6265SDimitry Andric 
59*81ad6265SDimitry Andric // Adds named section with given contents to the object.
60*81ad6265SDimitry Andric static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents,
61*81ad6265SDimitry Andric                        uint32_t Characteristics) {
62*81ad6265SDimitry Andric   bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
63*81ad6265SDimitry Andric                                    IMAGE_SCN_MEM_WRITE);
64*81ad6265SDimitry Andric 
65*81ad6265SDimitry Andric   Section Sec;
66*81ad6265SDimitry Andric   Sec.setOwnedContents(Contents);
67*81ad6265SDimitry Andric   Sec.Name = Name;
68*81ad6265SDimitry Andric   Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u;
69*81ad6265SDimitry Andric   Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u;
70*81ad6265SDimitry Andric   Sec.Header.SizeOfRawData =
71*81ad6265SDimitry Andric       NeedVA ? alignTo(Sec.Header.VirtualSize,
72*81ad6265SDimitry Andric                        Obj.IsPE ? Obj.PeHeader.FileAlignment : 1)
73*81ad6265SDimitry Andric              : Sec.getContents().size();
74*81ad6265SDimitry Andric   // Sec.Header.PointerToRawData is filled in by the writer.
75*81ad6265SDimitry Andric   Sec.Header.PointerToRelocations = 0;
76*81ad6265SDimitry Andric   Sec.Header.PointerToLinenumbers = 0;
77*81ad6265SDimitry Andric   // Sec.Header.NumberOfRelocations is filled in by the writer.
78*81ad6265SDimitry Andric   Sec.Header.NumberOfLinenumbers = 0;
79*81ad6265SDimitry Andric   Sec.Header.Characteristics = Characteristics;
80*81ad6265SDimitry Andric 
81*81ad6265SDimitry Andric   Obj.addSections(Sec);
82*81ad6265SDimitry Andric }
83*81ad6265SDimitry Andric 
84*81ad6265SDimitry Andric static Error addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
85*81ad6265SDimitry Andric   Expected<std::vector<uint8_t>> Contents =
86*81ad6265SDimitry Andric       createGnuDebugLinkSectionContents(DebugLinkFile);
87*81ad6265SDimitry Andric   if (!Contents)
88*81ad6265SDimitry Andric     return Contents.takeError();
89*81ad6265SDimitry Andric 
90*81ad6265SDimitry Andric   addSection(Obj, ".gnu_debuglink", *Contents,
91*81ad6265SDimitry Andric              IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
92*81ad6265SDimitry Andric                  IMAGE_SCN_MEM_DISCARDABLE);
93*81ad6265SDimitry Andric 
94*81ad6265SDimitry Andric   return Error::success();
95*81ad6265SDimitry Andric }
96*81ad6265SDimitry Andric 
97*81ad6265SDimitry Andric static uint32_t flagsToCharacteristics(SectionFlag AllFlags, uint32_t OldChar) {
98*81ad6265SDimitry Andric   // Need to preserve alignment flags.
99*81ad6265SDimitry Andric   const uint32_t PreserveMask =
100*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES |
101*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES |
102*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES |
103*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES |
104*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES |
105*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES |
106*81ad6265SDimitry Andric       IMAGE_SCN_ALIGN_8192BYTES;
107*81ad6265SDimitry Andric 
108*81ad6265SDimitry Andric   // Setup new section characteristics based on the flags provided in command
109*81ad6265SDimitry Andric   // line.
110*81ad6265SDimitry Andric   uint32_t NewCharacteristics = (OldChar & PreserveMask) | IMAGE_SCN_MEM_READ;
111*81ad6265SDimitry Andric 
112*81ad6265SDimitry Andric   if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad))
113*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
114*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecNoload)
115*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
116*81ad6265SDimitry Andric   if (!(AllFlags & SectionFlag::SecReadonly))
117*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_MEM_WRITE;
118*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecDebug)
119*81ad6265SDimitry Andric     NewCharacteristics |=
120*81ad6265SDimitry Andric         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
121*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecCode)
122*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
123*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecData)
124*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
125*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecShare)
126*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_MEM_SHARED;
127*81ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecExclude)
128*81ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
129*81ad6265SDimitry Andric 
130*81ad6265SDimitry Andric   return NewCharacteristics;
131*81ad6265SDimitry Andric }
132*81ad6265SDimitry Andric 
133*81ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config,
134*81ad6265SDimitry Andric                         const COFFConfig &COFFConfig, Object &Obj) {
135*81ad6265SDimitry Andric   // Perform the actual section removals.
136*81ad6265SDimitry Andric   Obj.removeSections([&Config](const Section &Sec) {
137*81ad6265SDimitry Andric     // Contrary to --only-keep-debug, --only-section fully removes sections that
138*81ad6265SDimitry Andric     // aren't mentioned.
139*81ad6265SDimitry Andric     if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name))
140*81ad6265SDimitry Andric       return true;
141*81ad6265SDimitry Andric 
142*81ad6265SDimitry Andric     if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
143*81ad6265SDimitry Andric         Config.DiscardMode == DiscardType::All || Config.StripUnneeded) {
144*81ad6265SDimitry Andric       if (isDebugSection(Sec) &&
145*81ad6265SDimitry Andric           (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
146*81ad6265SDimitry Andric         return true;
147*81ad6265SDimitry Andric     }
148*81ad6265SDimitry Andric 
149*81ad6265SDimitry Andric     if (Config.ToRemove.matches(Sec.Name))
150*81ad6265SDimitry Andric       return true;
151*81ad6265SDimitry Andric 
152*81ad6265SDimitry Andric     return false;
153*81ad6265SDimitry Andric   });
154*81ad6265SDimitry Andric 
155*81ad6265SDimitry Andric   if (Config.OnlyKeepDebug) {
156*81ad6265SDimitry Andric     // For --only-keep-debug, we keep all other sections, but remove their
157*81ad6265SDimitry Andric     // content. The VirtualSize field in the section header is kept intact.
158*81ad6265SDimitry Andric     Obj.truncateSections([](const Section &Sec) {
159*81ad6265SDimitry Andric       return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
160*81ad6265SDimitry Andric              ((Sec.Header.Characteristics &
161*81ad6265SDimitry Andric                (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
162*81ad6265SDimitry Andric     });
163*81ad6265SDimitry Andric   }
164*81ad6265SDimitry Andric 
165*81ad6265SDimitry Andric   // StripAll removes all symbols and thus also removes all relocations.
166*81ad6265SDimitry Andric   if (Config.StripAll || Config.StripAllGNU)
167*81ad6265SDimitry Andric     for (Section &Sec : Obj.getMutableSections())
168*81ad6265SDimitry Andric       Sec.Relocs.clear();
169*81ad6265SDimitry Andric 
170*81ad6265SDimitry Andric   // If we need to do per-symbol removals, initialize the Referenced field.
171*81ad6265SDimitry Andric   if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All ||
172*81ad6265SDimitry Andric       !Config.SymbolsToRemove.empty())
173*81ad6265SDimitry Andric     if (Error E = Obj.markSymbols())
174*81ad6265SDimitry Andric       return E;
175*81ad6265SDimitry Andric 
176*81ad6265SDimitry Andric   for (Symbol &Sym : Obj.getMutableSymbols()) {
177*81ad6265SDimitry Andric     auto I = Config.SymbolsToRename.find(Sym.Name);
178*81ad6265SDimitry Andric     if (I != Config.SymbolsToRename.end())
179*81ad6265SDimitry Andric       Sym.Name = I->getValue();
180*81ad6265SDimitry Andric   }
181*81ad6265SDimitry Andric 
182*81ad6265SDimitry Andric   auto ToRemove = [&](const Symbol &Sym) -> Expected<bool> {
183*81ad6265SDimitry Andric     // For StripAll, all relocations have been stripped and we remove all
184*81ad6265SDimitry Andric     // symbols.
185*81ad6265SDimitry Andric     if (Config.StripAll || Config.StripAllGNU)
186*81ad6265SDimitry Andric       return true;
187*81ad6265SDimitry Andric 
188*81ad6265SDimitry Andric     if (Config.SymbolsToRemove.matches(Sym.Name)) {
189*81ad6265SDimitry Andric       // Explicitly removing a referenced symbol is an error.
190*81ad6265SDimitry Andric       if (Sym.Referenced)
191*81ad6265SDimitry Andric         return createStringError(
192*81ad6265SDimitry Andric             llvm::errc::invalid_argument,
193*81ad6265SDimitry Andric             "'" + Config.OutputFilename + "': not stripping symbol '" +
194*81ad6265SDimitry Andric                 Sym.Name.str() + "' because it is named in a relocation");
195*81ad6265SDimitry Andric       return true;
196*81ad6265SDimitry Andric     }
197*81ad6265SDimitry Andric 
198*81ad6265SDimitry Andric     if (!Sym.Referenced) {
199*81ad6265SDimitry Andric       // With --strip-unneeded, GNU objcopy removes all unreferenced local
200*81ad6265SDimitry Andric       // symbols, and any unreferenced undefined external.
201*81ad6265SDimitry Andric       // With --strip-unneeded-symbol we strip only specific unreferenced
202*81ad6265SDimitry Andric       // local symbol instead of removing all of such.
203*81ad6265SDimitry Andric       if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
204*81ad6265SDimitry Andric           Sym.Sym.SectionNumber == 0)
205*81ad6265SDimitry Andric         if (Config.StripUnneeded ||
206*81ad6265SDimitry Andric             Config.UnneededSymbolsToRemove.matches(Sym.Name))
207*81ad6265SDimitry Andric           return true;
208*81ad6265SDimitry Andric 
209*81ad6265SDimitry Andric       // GNU objcopy keeps referenced local symbols and external symbols
210*81ad6265SDimitry Andric       // if --discard-all is set, similar to what --strip-unneeded does,
211*81ad6265SDimitry Andric       // but undefined local symbols are kept when --discard-all is set.
212*81ad6265SDimitry Andric       if (Config.DiscardMode == DiscardType::All &&
213*81ad6265SDimitry Andric           Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
214*81ad6265SDimitry Andric           Sym.Sym.SectionNumber != 0)
215*81ad6265SDimitry Andric         return true;
216*81ad6265SDimitry Andric     }
217*81ad6265SDimitry Andric 
218*81ad6265SDimitry Andric     return false;
219*81ad6265SDimitry Andric   };
220*81ad6265SDimitry Andric 
221*81ad6265SDimitry Andric   // Actually do removals of symbols.
222*81ad6265SDimitry Andric   if (Error Err = Obj.removeSymbols(ToRemove))
223*81ad6265SDimitry Andric     return Err;
224*81ad6265SDimitry Andric 
225*81ad6265SDimitry Andric   if (!Config.SetSectionFlags.empty())
226*81ad6265SDimitry Andric     for (Section &Sec : Obj.getMutableSections()) {
227*81ad6265SDimitry Andric       const auto It = Config.SetSectionFlags.find(Sec.Name);
228*81ad6265SDimitry Andric       if (It != Config.SetSectionFlags.end())
229*81ad6265SDimitry Andric         Sec.Header.Characteristics = flagsToCharacteristics(
230*81ad6265SDimitry Andric             It->second.NewFlags, Sec.Header.Characteristics);
231*81ad6265SDimitry Andric     }
232*81ad6265SDimitry Andric 
233*81ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.AddSection) {
234*81ad6265SDimitry Andric     uint32_t Characteristics;
235*81ad6265SDimitry Andric     const auto It = Config.SetSectionFlags.find(NewSection.SectionName);
236*81ad6265SDimitry Andric     if (It != Config.SetSectionFlags.end())
237*81ad6265SDimitry Andric       Characteristics = flagsToCharacteristics(It->second.NewFlags, 0);
238*81ad6265SDimitry Andric     else
239*81ad6265SDimitry Andric       Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES;
240*81ad6265SDimitry Andric 
241*81ad6265SDimitry Andric     addSection(Obj, NewSection.SectionName,
242*81ad6265SDimitry Andric                makeArrayRef(reinterpret_cast<const uint8_t *>(
243*81ad6265SDimitry Andric                                 NewSection.SectionData->getBufferStart()),
244*81ad6265SDimitry Andric                             NewSection.SectionData->getBufferSize()),
245*81ad6265SDimitry Andric                Characteristics);
246*81ad6265SDimitry Andric   }
247*81ad6265SDimitry Andric 
248*81ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
249*81ad6265SDimitry Andric     auto It = llvm::find_if(Obj.getMutableSections(), [&](auto &Sec) {
250*81ad6265SDimitry Andric       return Sec.Name == NewSection.SectionName;
251*81ad6265SDimitry Andric     });
252*81ad6265SDimitry Andric     if (It == Obj.getMutableSections().end())
253*81ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
254*81ad6265SDimitry Andric                                "could not find section with name '%s'",
255*81ad6265SDimitry Andric                                NewSection.SectionName.str().c_str());
256*81ad6265SDimitry Andric     size_t ContentSize = It->getContents().size();
257*81ad6265SDimitry Andric     if (!ContentSize)
258*81ad6265SDimitry Andric       return createStringError(
259*81ad6265SDimitry Andric           errc::invalid_argument,
260*81ad6265SDimitry Andric           "section '%s' cannot be updated because it does not have contents",
261*81ad6265SDimitry Andric           NewSection.SectionName.str().c_str());
262*81ad6265SDimitry Andric     if (ContentSize < NewSection.SectionData->getBufferSize())
263*81ad6265SDimitry Andric       return createStringError(
264*81ad6265SDimitry Andric           errc::invalid_argument,
265*81ad6265SDimitry Andric           "new section cannot be larger than previous section");
266*81ad6265SDimitry Andric     It->setOwnedContents({NewSection.SectionData->getBufferStart(),
267*81ad6265SDimitry Andric                           NewSection.SectionData->getBufferEnd()});
268*81ad6265SDimitry Andric   }
269*81ad6265SDimitry Andric 
270*81ad6265SDimitry Andric   if (!Config.AddGnuDebugLink.empty())
271*81ad6265SDimitry Andric     if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
272*81ad6265SDimitry Andric       return E;
273*81ad6265SDimitry Andric 
274*81ad6265SDimitry Andric   if (COFFConfig.Subsystem || COFFConfig.MajorSubsystemVersion ||
275*81ad6265SDimitry Andric       COFFConfig.MinorSubsystemVersion) {
276*81ad6265SDimitry Andric     if (!Obj.IsPE)
277*81ad6265SDimitry Andric       return createStringError(
278*81ad6265SDimitry Andric           errc::invalid_argument,
279*81ad6265SDimitry Andric           "'" + Config.OutputFilename +
280*81ad6265SDimitry Andric               "': unable to set subsystem on a relocatable object file");
281*81ad6265SDimitry Andric     if (COFFConfig.Subsystem)
282*81ad6265SDimitry Andric       Obj.PeHeader.Subsystem = *COFFConfig.Subsystem;
283*81ad6265SDimitry Andric     if (COFFConfig.MajorSubsystemVersion)
284*81ad6265SDimitry Andric       Obj.PeHeader.MajorSubsystemVersion = *COFFConfig.MajorSubsystemVersion;
285*81ad6265SDimitry Andric     if (COFFConfig.MinorSubsystemVersion)
286*81ad6265SDimitry Andric       Obj.PeHeader.MinorSubsystemVersion = *COFFConfig.MinorSubsystemVersion;
287*81ad6265SDimitry Andric   }
288*81ad6265SDimitry Andric 
289*81ad6265SDimitry Andric   return Error::success();
290*81ad6265SDimitry Andric }
291*81ad6265SDimitry Andric 
292*81ad6265SDimitry Andric Error executeObjcopyOnBinary(const CommonConfig &Config,
293*81ad6265SDimitry Andric                              const COFFConfig &COFFConfig, COFFObjectFile &In,
294*81ad6265SDimitry Andric                              raw_ostream &Out) {
295*81ad6265SDimitry Andric   COFFReader Reader(In);
296*81ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
297*81ad6265SDimitry Andric   if (!ObjOrErr)
298*81ad6265SDimitry Andric     return createFileError(Config.InputFilename, ObjOrErr.takeError());
299*81ad6265SDimitry Andric   Object *Obj = ObjOrErr->get();
300*81ad6265SDimitry Andric   assert(Obj && "Unable to deserialize COFF object");
301*81ad6265SDimitry Andric   if (Error E = handleArgs(Config, COFFConfig, *Obj))
302*81ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
303*81ad6265SDimitry Andric   COFFWriter Writer(*Obj, Out);
304*81ad6265SDimitry Andric   if (Error E = Writer.write())
305*81ad6265SDimitry Andric     return createFileError(Config.OutputFilename, std::move(E));
306*81ad6265SDimitry Andric   return Error::success();
307*81ad6265SDimitry Andric }
308*81ad6265SDimitry Andric 
309*81ad6265SDimitry Andric } // end namespace coff
310*81ad6265SDimitry Andric } // end namespace objcopy
311*81ad6265SDimitry Andric } // end namespace llvm
312