xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
181ad6265SDimitry Andric //===- COFFObjcopy.cpp ----------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFObjcopy.h"
1081ad6265SDimitry Andric #include "COFFObject.h"
1181ad6265SDimitry Andric #include "COFFReader.h"
1281ad6265SDimitry Andric #include "COFFWriter.h"
1381ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFConfig.h"
1481ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h"
1581ad6265SDimitry Andric 
1606c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
1781ad6265SDimitry Andric #include "llvm/Object/Binary.h"
1881ad6265SDimitry Andric #include "llvm/Object/COFF.h"
1981ad6265SDimitry Andric #include "llvm/Support/CRC.h"
2081ad6265SDimitry Andric #include "llvm/Support/Errc.h"
2181ad6265SDimitry Andric #include "llvm/Support/Path.h"
2281ad6265SDimitry Andric #include <cassert>
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric namespace llvm {
2581ad6265SDimitry Andric namespace objcopy {
2681ad6265SDimitry Andric namespace coff {
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric using namespace object;
2981ad6265SDimitry Andric using namespace COFF;
3081ad6265SDimitry Andric 
isDebugSection(const Section & Sec)3181ad6265SDimitry Andric static bool isDebugSection(const Section &Sec) {
32*5f757f3fSDimitry Andric   return Sec.Name.starts_with(".debug");
3381ad6265SDimitry Andric }
3481ad6265SDimitry Andric 
getNextRVA(const Object & Obj)3581ad6265SDimitry Andric static uint64_t getNextRVA(const Object &Obj) {
3681ad6265SDimitry Andric   if (Obj.getSections().empty())
3781ad6265SDimitry Andric     return 0;
3881ad6265SDimitry Andric   const Section &Last = Obj.getSections().back();
3981ad6265SDimitry Andric   return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
4081ad6265SDimitry Andric                  Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
4181ad6265SDimitry Andric }
4281ad6265SDimitry Andric 
4381ad6265SDimitry Andric static Expected<std::vector<uint8_t>>
createGnuDebugLinkSectionContents(StringRef File)4481ad6265SDimitry Andric createGnuDebugLinkSectionContents(StringRef File) {
4581ad6265SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
4681ad6265SDimitry Andric       MemoryBuffer::getFile(File);
4781ad6265SDimitry Andric   if (!LinkTargetOrErr)
4881ad6265SDimitry Andric     return createFileError(File, LinkTargetOrErr.getError());
4981ad6265SDimitry Andric   auto LinkTarget = std::move(*LinkTargetOrErr);
5081ad6265SDimitry Andric   uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric   StringRef FileName = sys::path::filename(File);
5381ad6265SDimitry Andric   size_t CRCPos = alignTo(FileName.size() + 1, 4);
5481ad6265SDimitry Andric   std::vector<uint8_t> Data(CRCPos + 4);
5581ad6265SDimitry Andric   memcpy(Data.data(), FileName.data(), FileName.size());
5681ad6265SDimitry Andric   support::endian::write32le(Data.data() + CRCPos, CRC32);
5781ad6265SDimitry Andric   return Data;
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric // Adds named section with given contents to the object.
addSection(Object & Obj,StringRef Name,ArrayRef<uint8_t> Contents,uint32_t Characteristics)6181ad6265SDimitry Andric static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents,
6281ad6265SDimitry Andric                        uint32_t Characteristics) {
6381ad6265SDimitry Andric   bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
6481ad6265SDimitry Andric                                    IMAGE_SCN_MEM_WRITE);
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   Section Sec;
6781ad6265SDimitry Andric   Sec.setOwnedContents(Contents);
6881ad6265SDimitry Andric   Sec.Name = Name;
6981ad6265SDimitry Andric   Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u;
7081ad6265SDimitry Andric   Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u;
7181ad6265SDimitry Andric   Sec.Header.SizeOfRawData =
7281ad6265SDimitry Andric       NeedVA ? alignTo(Sec.Header.VirtualSize,
7381ad6265SDimitry Andric                        Obj.IsPE ? Obj.PeHeader.FileAlignment : 1)
7481ad6265SDimitry Andric              : Sec.getContents().size();
7581ad6265SDimitry Andric   // Sec.Header.PointerToRawData is filled in by the writer.
7681ad6265SDimitry Andric   Sec.Header.PointerToRelocations = 0;
7781ad6265SDimitry Andric   Sec.Header.PointerToLinenumbers = 0;
7881ad6265SDimitry Andric   // Sec.Header.NumberOfRelocations is filled in by the writer.
7981ad6265SDimitry Andric   Sec.Header.NumberOfLinenumbers = 0;
8081ad6265SDimitry Andric   Sec.Header.Characteristics = Characteristics;
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric   Obj.addSections(Sec);
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric 
addGnuDebugLink(Object & Obj,StringRef DebugLinkFile)8581ad6265SDimitry Andric static Error addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
8681ad6265SDimitry Andric   Expected<std::vector<uint8_t>> Contents =
8781ad6265SDimitry Andric       createGnuDebugLinkSectionContents(DebugLinkFile);
8881ad6265SDimitry Andric   if (!Contents)
8981ad6265SDimitry Andric     return Contents.takeError();
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric   addSection(Obj, ".gnu_debuglink", *Contents,
9281ad6265SDimitry Andric              IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
9381ad6265SDimitry Andric                  IMAGE_SCN_MEM_DISCARDABLE);
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   return Error::success();
9681ad6265SDimitry Andric }
9781ad6265SDimitry Andric 
flagsToCharacteristics(SectionFlag AllFlags,uint32_t OldChar)9881ad6265SDimitry Andric static uint32_t flagsToCharacteristics(SectionFlag AllFlags, uint32_t OldChar) {
9981ad6265SDimitry Andric   // Need to preserve alignment flags.
10081ad6265SDimitry Andric   const uint32_t PreserveMask =
10181ad6265SDimitry Andric       IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES |
10281ad6265SDimitry Andric       IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES |
10381ad6265SDimitry Andric       IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES |
10481ad6265SDimitry Andric       IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES |
10581ad6265SDimitry Andric       IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES |
10681ad6265SDimitry Andric       IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES |
10781ad6265SDimitry Andric       IMAGE_SCN_ALIGN_8192BYTES;
10881ad6265SDimitry Andric 
10981ad6265SDimitry Andric   // Setup new section characteristics based on the flags provided in command
11081ad6265SDimitry Andric   // line.
11181ad6265SDimitry Andric   uint32_t NewCharacteristics = (OldChar & PreserveMask) | IMAGE_SCN_MEM_READ;
11281ad6265SDimitry Andric 
11381ad6265SDimitry Andric   if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad))
11481ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
11581ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecNoload)
11681ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
11781ad6265SDimitry Andric   if (!(AllFlags & SectionFlag::SecReadonly))
11881ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_MEM_WRITE;
11981ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecDebug)
12081ad6265SDimitry Andric     NewCharacteristics |=
12181ad6265SDimitry Andric         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
12281ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecCode)
12381ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
12481ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecData)
12581ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
12681ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecShare)
12781ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_MEM_SHARED;
12881ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecExclude)
12981ad6265SDimitry Andric     NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
13081ad6265SDimitry Andric 
13181ad6265SDimitry Andric   return NewCharacteristics;
13281ad6265SDimitry Andric }
13381ad6265SDimitry Andric 
dumpSection(Object & O,StringRef SectionName,StringRef FileName)13406c3fb27SDimitry Andric static Error dumpSection(Object &O, StringRef SectionName, StringRef FileName) {
13506c3fb27SDimitry Andric   for (const coff::Section &Section : O.getSections()) {
13606c3fb27SDimitry Andric     if (Section.Name != SectionName)
13706c3fb27SDimitry Andric       continue;
13806c3fb27SDimitry Andric 
13906c3fb27SDimitry Andric     ArrayRef<uint8_t> Contents = Section.getContents();
14006c3fb27SDimitry Andric 
14106c3fb27SDimitry Andric     std::unique_ptr<FileOutputBuffer> Buffer;
14206c3fb27SDimitry Andric     if (auto B = FileOutputBuffer::create(FileName, Contents.size()))
14306c3fb27SDimitry Andric       Buffer = std::move(*B);
14406c3fb27SDimitry Andric     else
14506c3fb27SDimitry Andric       return B.takeError();
14606c3fb27SDimitry Andric 
14706c3fb27SDimitry Andric     llvm::copy(Contents, Buffer->getBufferStart());
14806c3fb27SDimitry Andric     if (Error E = Buffer->commit())
14906c3fb27SDimitry Andric       return E;
15006c3fb27SDimitry Andric 
15106c3fb27SDimitry Andric     return Error::success();
15206c3fb27SDimitry Andric   }
15306c3fb27SDimitry Andric   return createStringError(object_error::parse_failed, "section '%s' not found",
15406c3fb27SDimitry Andric                            SectionName.str().c_str());
15506c3fb27SDimitry Andric }
15606c3fb27SDimitry Andric 
handleArgs(const CommonConfig & Config,const COFFConfig & COFFConfig,Object & Obj)15781ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config,
15881ad6265SDimitry Andric                         const COFFConfig &COFFConfig, Object &Obj) {
15906c3fb27SDimitry Andric   for (StringRef Op : Config.DumpSection) {
16006c3fb27SDimitry Andric     auto [Section, File] = Op.split('=');
16106c3fb27SDimitry Andric     if (Error E = dumpSection(Obj, Section, File))
16206c3fb27SDimitry Andric       return E;
16306c3fb27SDimitry Andric   }
16406c3fb27SDimitry Andric 
16581ad6265SDimitry Andric   // Perform the actual section removals.
16681ad6265SDimitry Andric   Obj.removeSections([&Config](const Section &Sec) {
16781ad6265SDimitry Andric     // Contrary to --only-keep-debug, --only-section fully removes sections that
16881ad6265SDimitry Andric     // aren't mentioned.
16981ad6265SDimitry Andric     if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name))
17081ad6265SDimitry Andric       return true;
17181ad6265SDimitry Andric 
17281ad6265SDimitry Andric     if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
17381ad6265SDimitry Andric         Config.DiscardMode == DiscardType::All || Config.StripUnneeded) {
17481ad6265SDimitry Andric       if (isDebugSection(Sec) &&
17581ad6265SDimitry Andric           (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
17681ad6265SDimitry Andric         return true;
17781ad6265SDimitry Andric     }
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric     if (Config.ToRemove.matches(Sec.Name))
18081ad6265SDimitry Andric       return true;
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric     return false;
18381ad6265SDimitry Andric   });
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric   if (Config.OnlyKeepDebug) {
18681ad6265SDimitry Andric     // For --only-keep-debug, we keep all other sections, but remove their
18781ad6265SDimitry Andric     // content. The VirtualSize field in the section header is kept intact.
18881ad6265SDimitry Andric     Obj.truncateSections([](const Section &Sec) {
18981ad6265SDimitry Andric       return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
19081ad6265SDimitry Andric              ((Sec.Header.Characteristics &
19181ad6265SDimitry Andric                (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
19281ad6265SDimitry Andric     });
19381ad6265SDimitry Andric   }
19481ad6265SDimitry Andric 
19581ad6265SDimitry Andric   // StripAll removes all symbols and thus also removes all relocations.
19681ad6265SDimitry Andric   if (Config.StripAll || Config.StripAllGNU)
19781ad6265SDimitry Andric     for (Section &Sec : Obj.getMutableSections())
19881ad6265SDimitry Andric       Sec.Relocs.clear();
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   // If we need to do per-symbol removals, initialize the Referenced field.
20181ad6265SDimitry Andric   if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All ||
20281ad6265SDimitry Andric       !Config.SymbolsToRemove.empty())
20381ad6265SDimitry Andric     if (Error E = Obj.markSymbols())
20481ad6265SDimitry Andric       return E;
20581ad6265SDimitry Andric 
20681ad6265SDimitry Andric   for (Symbol &Sym : Obj.getMutableSymbols()) {
20781ad6265SDimitry Andric     auto I = Config.SymbolsToRename.find(Sym.Name);
20881ad6265SDimitry Andric     if (I != Config.SymbolsToRename.end())
20981ad6265SDimitry Andric       Sym.Name = I->getValue();
21081ad6265SDimitry Andric   }
21181ad6265SDimitry Andric 
21281ad6265SDimitry Andric   auto ToRemove = [&](const Symbol &Sym) -> Expected<bool> {
21381ad6265SDimitry Andric     // For StripAll, all relocations have been stripped and we remove all
21481ad6265SDimitry Andric     // symbols.
21581ad6265SDimitry Andric     if (Config.StripAll || Config.StripAllGNU)
21681ad6265SDimitry Andric       return true;
21781ad6265SDimitry Andric 
21881ad6265SDimitry Andric     if (Config.SymbolsToRemove.matches(Sym.Name)) {
21981ad6265SDimitry Andric       // Explicitly removing a referenced symbol is an error.
22081ad6265SDimitry Andric       if (Sym.Referenced)
22181ad6265SDimitry Andric         return createStringError(
22281ad6265SDimitry Andric             llvm::errc::invalid_argument,
22381ad6265SDimitry Andric             "'" + Config.OutputFilename + "': not stripping symbol '" +
22481ad6265SDimitry Andric                 Sym.Name.str() + "' because it is named in a relocation");
22581ad6265SDimitry Andric       return true;
22681ad6265SDimitry Andric     }
22781ad6265SDimitry Andric 
22881ad6265SDimitry Andric     if (!Sym.Referenced) {
22981ad6265SDimitry Andric       // With --strip-unneeded, GNU objcopy removes all unreferenced local
23081ad6265SDimitry Andric       // symbols, and any unreferenced undefined external.
23181ad6265SDimitry Andric       // With --strip-unneeded-symbol we strip only specific unreferenced
23281ad6265SDimitry Andric       // local symbol instead of removing all of such.
23381ad6265SDimitry Andric       if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
23481ad6265SDimitry Andric           Sym.Sym.SectionNumber == 0)
23581ad6265SDimitry Andric         if (Config.StripUnneeded ||
23681ad6265SDimitry Andric             Config.UnneededSymbolsToRemove.matches(Sym.Name))
23781ad6265SDimitry Andric           return true;
23881ad6265SDimitry Andric 
23981ad6265SDimitry Andric       // GNU objcopy keeps referenced local symbols and external symbols
24081ad6265SDimitry Andric       // if --discard-all is set, similar to what --strip-unneeded does,
24181ad6265SDimitry Andric       // but undefined local symbols are kept when --discard-all is set.
24281ad6265SDimitry Andric       if (Config.DiscardMode == DiscardType::All &&
24381ad6265SDimitry Andric           Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
24481ad6265SDimitry Andric           Sym.Sym.SectionNumber != 0)
24581ad6265SDimitry Andric         return true;
24681ad6265SDimitry Andric     }
24781ad6265SDimitry Andric 
24881ad6265SDimitry Andric     return false;
24981ad6265SDimitry Andric   };
25081ad6265SDimitry Andric 
25181ad6265SDimitry Andric   // Actually do removals of symbols.
25281ad6265SDimitry Andric   if (Error Err = Obj.removeSymbols(ToRemove))
25381ad6265SDimitry Andric     return Err;
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric   if (!Config.SetSectionFlags.empty())
25681ad6265SDimitry Andric     for (Section &Sec : Obj.getMutableSections()) {
25781ad6265SDimitry Andric       const auto It = Config.SetSectionFlags.find(Sec.Name);
25881ad6265SDimitry Andric       if (It != Config.SetSectionFlags.end())
25981ad6265SDimitry Andric         Sec.Header.Characteristics = flagsToCharacteristics(
26081ad6265SDimitry Andric             It->second.NewFlags, Sec.Header.Characteristics);
26181ad6265SDimitry Andric     }
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.AddSection) {
26481ad6265SDimitry Andric     uint32_t Characteristics;
26581ad6265SDimitry Andric     const auto It = Config.SetSectionFlags.find(NewSection.SectionName);
26681ad6265SDimitry Andric     if (It != Config.SetSectionFlags.end())
26781ad6265SDimitry Andric       Characteristics = flagsToCharacteristics(It->second.NewFlags, 0);
26881ad6265SDimitry Andric     else
26981ad6265SDimitry Andric       Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES;
27081ad6265SDimitry Andric 
27181ad6265SDimitry Andric     addSection(Obj, NewSection.SectionName,
272bdd1243dSDimitry Andric                ArrayRef(reinterpret_cast<const uint8_t *>(
27381ad6265SDimitry Andric                             NewSection.SectionData->getBufferStart()),
27481ad6265SDimitry Andric                         NewSection.SectionData->getBufferSize()),
27581ad6265SDimitry Andric                Characteristics);
27681ad6265SDimitry Andric   }
27781ad6265SDimitry Andric 
27881ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
27981ad6265SDimitry Andric     auto It = llvm::find_if(Obj.getMutableSections(), [&](auto &Sec) {
28081ad6265SDimitry Andric       return Sec.Name == NewSection.SectionName;
28181ad6265SDimitry Andric     });
28281ad6265SDimitry Andric     if (It == Obj.getMutableSections().end())
28381ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
28481ad6265SDimitry Andric                                "could not find section with name '%s'",
28581ad6265SDimitry Andric                                NewSection.SectionName.str().c_str());
28681ad6265SDimitry Andric     size_t ContentSize = It->getContents().size();
28781ad6265SDimitry Andric     if (!ContentSize)
28881ad6265SDimitry Andric       return createStringError(
28981ad6265SDimitry Andric           errc::invalid_argument,
29081ad6265SDimitry Andric           "section '%s' cannot be updated because it does not have contents",
29181ad6265SDimitry Andric           NewSection.SectionName.str().c_str());
29281ad6265SDimitry Andric     if (ContentSize < NewSection.SectionData->getBufferSize())
29381ad6265SDimitry Andric       return createStringError(
29481ad6265SDimitry Andric           errc::invalid_argument,
29581ad6265SDimitry Andric           "new section cannot be larger than previous section");
29681ad6265SDimitry Andric     It->setOwnedContents({NewSection.SectionData->getBufferStart(),
29781ad6265SDimitry Andric                           NewSection.SectionData->getBufferEnd()});
29881ad6265SDimitry Andric   }
29981ad6265SDimitry Andric 
30081ad6265SDimitry Andric   if (!Config.AddGnuDebugLink.empty())
30181ad6265SDimitry Andric     if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
30281ad6265SDimitry Andric       return E;
30381ad6265SDimitry Andric 
30481ad6265SDimitry Andric   if (COFFConfig.Subsystem || COFFConfig.MajorSubsystemVersion ||
30581ad6265SDimitry Andric       COFFConfig.MinorSubsystemVersion) {
30681ad6265SDimitry Andric     if (!Obj.IsPE)
30781ad6265SDimitry Andric       return createStringError(
30881ad6265SDimitry Andric           errc::invalid_argument,
30981ad6265SDimitry Andric           "'" + Config.OutputFilename +
31081ad6265SDimitry Andric               "': unable to set subsystem on a relocatable object file");
31181ad6265SDimitry Andric     if (COFFConfig.Subsystem)
31281ad6265SDimitry Andric       Obj.PeHeader.Subsystem = *COFFConfig.Subsystem;
31381ad6265SDimitry Andric     if (COFFConfig.MajorSubsystemVersion)
31481ad6265SDimitry Andric       Obj.PeHeader.MajorSubsystemVersion = *COFFConfig.MajorSubsystemVersion;
31581ad6265SDimitry Andric     if (COFFConfig.MinorSubsystemVersion)
31681ad6265SDimitry Andric       Obj.PeHeader.MinorSubsystemVersion = *COFFConfig.MinorSubsystemVersion;
31781ad6265SDimitry Andric   }
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   return Error::success();
32081ad6265SDimitry Andric }
32181ad6265SDimitry Andric 
executeObjcopyOnBinary(const CommonConfig & Config,const COFFConfig & COFFConfig,COFFObjectFile & In,raw_ostream & Out)32281ad6265SDimitry Andric Error executeObjcopyOnBinary(const CommonConfig &Config,
32381ad6265SDimitry Andric                              const COFFConfig &COFFConfig, COFFObjectFile &In,
32481ad6265SDimitry Andric                              raw_ostream &Out) {
32581ad6265SDimitry Andric   COFFReader Reader(In);
32681ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
32781ad6265SDimitry Andric   if (!ObjOrErr)
32881ad6265SDimitry Andric     return createFileError(Config.InputFilename, ObjOrErr.takeError());
32981ad6265SDimitry Andric   Object *Obj = ObjOrErr->get();
33081ad6265SDimitry Andric   assert(Obj && "Unable to deserialize COFF object");
33181ad6265SDimitry Andric   if (Error E = handleArgs(Config, COFFConfig, *Obj))
33281ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
33381ad6265SDimitry Andric   COFFWriter Writer(*Obj, Out);
33481ad6265SDimitry Andric   if (Error E = Writer.write())
33581ad6265SDimitry Andric     return createFileError(Config.OutputFilename, std::move(E));
33681ad6265SDimitry Andric   return Error::success();
33781ad6265SDimitry Andric }
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric } // end namespace coff
34081ad6265SDimitry Andric } // end namespace objcopy
34181ad6265SDimitry Andric } // end namespace llvm
342