1 //===- ELFObjcopy.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 "ELFObjcopy.h"
11 #include "Buffer.h"
12 #include "CopyConfig.h"
13 #include "Object.h"
14 #include "llvm-objcopy.h"
15 
16 #include "llvm/ADT/BitmaskEnum.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/ADT/Twine.h"
22 #include "llvm/BinaryFormat/ELF.h"
23 #include "llvm/MC/MCTargetOptions.h"
24 #include "llvm/Object/Binary.h"
25 #include "llvm/Object/ELFObjectFile.h"
26 #include "llvm/Object/ELFTypes.h"
27 #include "llvm/Object/Error.h"
28 #include "llvm/Option/Option.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/Compression.h"
31 #include "llvm/Support/Errc.h"
32 #include "llvm/Support/Error.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/ErrorOr.h"
35 #include "llvm/Support/Memory.h"
36 #include "llvm/Support/Path.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include <algorithm>
39 #include <cassert>
40 #include <cstdlib>
41 #include <functional>
42 #include <iterator>
43 #include <memory>
44 #include <string>
45 #include <system_error>
46 #include <utility>
47 
48 namespace llvm {
49 namespace objcopy {
50 namespace elf {
51 
52 using namespace object;
53 using namespace ELF;
54 using SectionPred = std::function<bool(const SectionBase &Sec)>;
55 
isDebugSection(const SectionBase & Sec)56 static bool isDebugSection(const SectionBase &Sec) {
57   return StringRef(Sec.Name).startswith(".debug") ||
58          StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
59 }
60 
isDWOSection(const SectionBase & Sec)61 static bool isDWOSection(const SectionBase &Sec) {
62   return StringRef(Sec.Name).endswith(".dwo");
63 }
64 
onlyKeepDWOPred(const Object & Obj,const SectionBase & Sec)65 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
66   // We can't remove the section header string table.
67   if (&Sec == Obj.SectionNames)
68     return false;
69   // Short of keeping the string table we want to keep everything that is a DWO
70   // section and remove everything else.
71   return !isDWOSection(Sec);
72 }
73 
getOutputElfType(const Binary & Bin)74 static ElfType getOutputElfType(const Binary &Bin) {
75   // Infer output ELF type from the input ELF object
76   if (isa<ELFObjectFile<ELF32LE>>(Bin))
77     return ELFT_ELF32LE;
78   if (isa<ELFObjectFile<ELF64LE>>(Bin))
79     return ELFT_ELF64LE;
80   if (isa<ELFObjectFile<ELF32BE>>(Bin))
81     return ELFT_ELF32BE;
82   if (isa<ELFObjectFile<ELF64BE>>(Bin))
83     return ELFT_ELF64BE;
84   llvm_unreachable("Invalid ELFType");
85 }
86 
getOutputElfType(const MachineInfo & MI)87 static ElfType getOutputElfType(const MachineInfo &MI) {
88   // Infer output ELF type from the binary arch specified
89   if (MI.Is64Bit)
90     return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
91   else
92     return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
93 }
94 
createWriter(const CopyConfig & Config,Object & Obj,Buffer & Buf,ElfType OutputElfType)95 static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
96                                             Object &Obj, Buffer &Buf,
97                                             ElfType OutputElfType) {
98   if (Config.OutputFormat == "binary") {
99     return llvm::make_unique<BinaryWriter>(Obj, Buf);
100   }
101   // Depending on the initial ELFT and OutputFormat we need a different Writer.
102   switch (OutputElfType) {
103   case ELFT_ELF32LE:
104     return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
105                                                  !Config.StripSections);
106   case ELFT_ELF64LE:
107     return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
108                                                  !Config.StripSections);
109   case ELFT_ELF32BE:
110     return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
111                                                  !Config.StripSections);
112   case ELFT_ELF64BE:
113     return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
114                                                  !Config.StripSections);
115   }
116   llvm_unreachable("Invalid output format");
117 }
118 
119 template <class ELFT>
120 static Expected<ArrayRef<uint8_t>>
findBuildID(const object::ELFFile<ELFT> & In)121 findBuildID(const object::ELFFile<ELFT> &In) {
122   for (const auto &Phdr : unwrapOrError(In.program_headers())) {
123     if (Phdr.p_type != PT_NOTE)
124       continue;
125     Error Err = Error::success();
126     for (const auto &Note : In.notes(Phdr, Err))
127       if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
128         return Note.getDesc();
129     if (Err)
130       return std::move(Err);
131   }
132   return createStringError(llvm::errc::invalid_argument,
133                            "Could not find build ID.");
134 }
135 
136 static Expected<ArrayRef<uint8_t>>
findBuildID(const object::ELFObjectFileBase & In)137 findBuildID(const object::ELFObjectFileBase &In) {
138   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
139     return findBuildID(*O->getELFFile());
140   else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
141     return findBuildID(*O->getELFFile());
142   else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
143     return findBuildID(*O->getELFFile());
144   else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
145     return findBuildID(*O->getELFFile());
146 
147   llvm_unreachable("Bad file format");
148 }
149 
linkToBuildIdDir(const CopyConfig & Config,StringRef ToLink,StringRef Suffix,ArrayRef<uint8_t> BuildIdBytes)150 static void linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
151                              StringRef Suffix, ArrayRef<uint8_t> BuildIdBytes) {
152   SmallString<128> Path = Config.BuildIdLinkDir;
153   sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
154   if (auto EC = sys::fs::create_directories(Path))
155     error("cannot create build ID link directory " + Path + ": " +
156           EC.message());
157 
158   sys::path::append(Path,
159                     llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
160   Path += Suffix;
161   if (auto EC = sys::fs::create_hard_link(ToLink, Path)) {
162     // Hard linking failed, try to remove the file first if it exists.
163     if (sys::fs::exists(Path))
164       sys::fs::remove(Path);
165     EC = sys::fs::create_hard_link(ToLink, Path);
166     if (EC)
167       error("cannot link " + ToLink + " to " + Path + ": " + EC.message());
168   }
169 }
170 
splitDWOToFile(const CopyConfig & Config,const Reader & Reader,StringRef File,ElfType OutputElfType)171 static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
172                            StringRef File, ElfType OutputElfType) {
173   auto DWOFile = Reader.create();
174   DWOFile->removeSections(
175       [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
176   if (Config.OutputArch)
177     DWOFile->Machine = Config.OutputArch.getValue().EMachine;
178   FileBuffer FB(File);
179   auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
180   Writer->finalize();
181   Writer->write();
182 }
183 
dumpSectionToFile(StringRef SecName,StringRef Filename,Object & Obj)184 static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
185                                Object &Obj) {
186   for (auto &Sec : Obj.sections()) {
187     if (Sec.Name == SecName) {
188       if (Sec.OriginalData.empty())
189         return make_error<StringError>("Can't dump section \"" + SecName +
190                                            "\": it has no contents",
191                                        object_error::parse_failed);
192       Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
193           FileOutputBuffer::create(Filename, Sec.OriginalData.size());
194       if (!BufferOrErr)
195         return BufferOrErr.takeError();
196       std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
197       std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
198                 Buf->getBufferStart());
199       if (Error E = Buf->commit())
200         return E;
201       return Error::success();
202     }
203   }
204   return make_error<StringError>("Section not found",
205                                  object_error::parse_failed);
206 }
207 
isCompressed(const SectionBase & Section)208 static bool isCompressed(const SectionBase &Section) {
209   const char *Magic = "ZLIB";
210   return StringRef(Section.Name).startswith(".zdebug") ||
211          (Section.OriginalData.size() > strlen(Magic) &&
212           !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
213                    Magic, strlen(Magic))) ||
214          (Section.Flags & ELF::SHF_COMPRESSED);
215 }
216 
isCompressable(const SectionBase & Section)217 static bool isCompressable(const SectionBase &Section) {
218   return !isCompressed(Section) && isDebugSection(Section) &&
219          Section.Name != ".gdb_index";
220 }
221 
replaceDebugSections(const CopyConfig & Config,Object & Obj,SectionPred & RemovePred,function_ref<bool (const SectionBase &)> shouldReplace,function_ref<SectionBase * (const SectionBase *)> addSection)222 static void replaceDebugSections(
223     const CopyConfig &Config, Object &Obj, SectionPred &RemovePred,
224     function_ref<bool(const SectionBase &)> shouldReplace,
225     function_ref<SectionBase *(const SectionBase *)> addSection) {
226   SmallVector<SectionBase *, 13> ToReplace;
227   SmallVector<RelocationSection *, 13> RelocationSections;
228   for (auto &Sec : Obj.sections()) {
229     if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
230       if (shouldReplace(*R->getSection()))
231         RelocationSections.push_back(R);
232       continue;
233     }
234 
235     if (shouldReplace(Sec))
236       ToReplace.push_back(&Sec);
237   }
238 
239   for (SectionBase *S : ToReplace) {
240     SectionBase *NewSection = addSection(S);
241 
242     for (RelocationSection *RS : RelocationSections) {
243       if (RS->getSection() == S)
244         RS->setSection(NewSection);
245     }
246   }
247 
248   RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
249     return shouldReplace(Sec) || RemovePred(Sec);
250   };
251 }
252 
253 // This function handles the high level operations of GNU objcopy including
254 // handling command line options. It's important to outline certain properties
255 // we expect to hold of the command line operations. Any operation that "keeps"
256 // should keep regardless of a remove. Additionally any removal should respect
257 // any previous removals. Lastly whether or not something is removed shouldn't
258 // depend a) on the order the options occur in or b) on some opaque priority
259 // system. The only priority is that keeps/copies overrule removes.
handleArgs(const CopyConfig & Config,Object & Obj,const Reader & Reader,ElfType OutputElfType)260 static void handleArgs(const CopyConfig &Config, Object &Obj,
261                        const Reader &Reader, ElfType OutputElfType) {
262 
263   if (!Config.SplitDWO.empty()) {
264     splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
265   }
266   if (Config.OutputArch)
267     Obj.Machine = Config.OutputArch.getValue().EMachine;
268 
269   // TODO: update or remove symbols only if there is an option that affects
270   // them.
271   if (Obj.SymbolTable) {
272     Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
273       if (!Sym.isCommon() &&
274           ((Config.LocalizeHidden &&
275             (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
276            is_contained(Config.SymbolsToLocalize, Sym.Name)))
277         Sym.Binding = STB_LOCAL;
278 
279       // Note: these two globalize flags have very similar names but different
280       // meanings:
281       //
282       // --globalize-symbol: promote a symbol to global
283       // --keep-global-symbol: all symbols except for these should be made local
284       //
285       // If --globalize-symbol is specified for a given symbol, it will be
286       // global in the output file even if it is not included via
287       // --keep-global-symbol. Because of that, make sure to check
288       // --globalize-symbol second.
289       if (!Config.SymbolsToKeepGlobal.empty() &&
290           !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) &&
291           Sym.getShndx() != SHN_UNDEF)
292         Sym.Binding = STB_LOCAL;
293 
294       if (is_contained(Config.SymbolsToGlobalize, Sym.Name) &&
295           Sym.getShndx() != SHN_UNDEF)
296         Sym.Binding = STB_GLOBAL;
297 
298       if (is_contained(Config.SymbolsToWeaken, Sym.Name) &&
299           Sym.Binding == STB_GLOBAL)
300         Sym.Binding = STB_WEAK;
301 
302       if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
303           Sym.getShndx() != SHN_UNDEF)
304         Sym.Binding = STB_WEAK;
305 
306       const auto I = Config.SymbolsToRename.find(Sym.Name);
307       if (I != Config.SymbolsToRename.end())
308         Sym.Name = I->getValue();
309 
310       if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
311         Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
312     });
313 
314     // The purpose of this loop is to mark symbols referenced by sections
315     // (like GroupSection or RelocationSection). This way, we know which
316     // symbols are still 'needed' and which are not.
317     if (Config.StripUnneeded) {
318       for (auto &Section : Obj.sections())
319         Section.markSymbols();
320     }
321 
322     Obj.removeSymbols([&](const Symbol &Sym) {
323       if (is_contained(Config.SymbolsToKeep, Sym.Name) ||
324           (Config.KeepFileSymbols && Sym.Type == STT_FILE))
325         return false;
326 
327       if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
328           Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
329           Sym.Type != STT_SECTION)
330         return true;
331 
332       if (Config.StripAll || Config.StripAllGNU)
333         return true;
334 
335       if (is_contained(Config.SymbolsToRemove, Sym.Name))
336         return true;
337 
338       if (Config.StripUnneeded && !Sym.Referenced &&
339           (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
340           Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
341         return true;
342 
343       return false;
344     });
345   }
346 
347   SectionPred RemovePred = [](const SectionBase &) { return false; };
348 
349   // Removes:
350   if (!Config.ToRemove.empty()) {
351     RemovePred = [&Config](const SectionBase &Sec) {
352       return is_contained(Config.ToRemove, Sec.Name);
353     };
354   }
355 
356   if (Config.StripDWO || !Config.SplitDWO.empty())
357     RemovePred = [RemovePred](const SectionBase &Sec) {
358       return isDWOSection(Sec) || RemovePred(Sec);
359     };
360 
361   if (Config.ExtractDWO)
362     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
363       return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
364     };
365 
366   if (Config.StripAllGNU)
367     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
368       if (RemovePred(Sec))
369         return true;
370       if ((Sec.Flags & SHF_ALLOC) != 0)
371         return false;
372       if (&Sec == Obj.SectionNames)
373         return false;
374       switch (Sec.Type) {
375       case SHT_SYMTAB:
376       case SHT_REL:
377       case SHT_RELA:
378       case SHT_STRTAB:
379         return true;
380       }
381       return isDebugSection(Sec);
382     };
383 
384   if (Config.StripSections) {
385     RemovePred = [RemovePred](const SectionBase &Sec) {
386       return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
387     };
388   }
389 
390   if (Config.StripDebug) {
391     RemovePred = [RemovePred](const SectionBase &Sec) {
392       return RemovePred(Sec) || isDebugSection(Sec);
393     };
394   }
395 
396   if (Config.StripNonAlloc)
397     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
398       if (RemovePred(Sec))
399         return true;
400       if (&Sec == Obj.SectionNames)
401         return false;
402       return (Sec.Flags & SHF_ALLOC) == 0;
403     };
404 
405   if (Config.StripAll)
406     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
407       if (RemovePred(Sec))
408         return true;
409       if (&Sec == Obj.SectionNames)
410         return false;
411       if (StringRef(Sec.Name).startswith(".gnu.warning"))
412         return false;
413       return (Sec.Flags & SHF_ALLOC) == 0;
414     };
415 
416   // Explicit copies:
417   if (!Config.OnlySection.empty()) {
418     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
419       // Explicitly keep these sections regardless of previous removes.
420       if (is_contained(Config.OnlySection, Sec.Name))
421         return false;
422 
423       // Allow all implicit removes.
424       if (RemovePred(Sec))
425         return true;
426 
427       // Keep special sections.
428       if (Obj.SectionNames == &Sec)
429         return false;
430       if (Obj.SymbolTable == &Sec ||
431           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
432         return false;
433 
434       // Remove everything else.
435       return true;
436     };
437   }
438 
439   if (!Config.KeepSection.empty()) {
440     RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
441       // Explicitly keep these sections regardless of previous removes.
442       if (is_contained(Config.KeepSection, Sec.Name))
443         return false;
444       // Otherwise defer to RemovePred.
445       return RemovePred(Sec);
446     };
447   }
448 
449   // This has to be the last predicate assignment.
450   // If the option --keep-symbol has been specified
451   // and at least one of those symbols is present
452   // (equivalently, the updated symbol table is not empty)
453   // the symbol table and the string table should not be removed.
454   if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
455       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
456     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
457       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
458         return false;
459       return RemovePred(Sec);
460     };
461   }
462 
463   if (Config.CompressionType != DebugCompressionType::None)
464     replaceDebugSections(Config, Obj, RemovePred, isCompressable,
465                          [&Config, &Obj](const SectionBase *S) {
466                            return &Obj.addSection<CompressedSection>(
467                                *S, Config.CompressionType);
468                          });
469   else if (Config.DecompressDebugSections)
470     replaceDebugSections(
471         Config, Obj, RemovePred,
472         [](const SectionBase &S) { return isa<CompressedSection>(&S); },
473         [&Obj](const SectionBase *S) {
474           auto CS = cast<CompressedSection>(S);
475           return &Obj.addSection<DecompressedSection>(*CS);
476         });
477 
478   Obj.removeSections(RemovePred);
479 
480   if (!Config.SectionsToRename.empty()) {
481     for (auto &Sec : Obj.sections()) {
482       const auto Iter = Config.SectionsToRename.find(Sec.Name);
483       if (Iter != Config.SectionsToRename.end()) {
484         const SectionRename &SR = Iter->second;
485         Sec.Name = SR.NewName;
486         if (SR.NewFlags.hasValue()) {
487           // Preserve some flags which should not be dropped when setting flags.
488           // Also, preserve anything OS/processor dependant.
489           const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
490                                         ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
491                                         ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
492                                         ELF::SHF_TLS | ELF::SHF_INFO_LINK;
493           Sec.Flags = (Sec.Flags & PreserveMask) |
494                       (SR.NewFlags.getValue() & ~PreserveMask);
495         }
496       }
497     }
498   }
499 
500   if (!Config.AddSection.empty()) {
501     for (const auto &Flag : Config.AddSection) {
502       std::pair<StringRef, StringRef> SecPair = Flag.split("=");
503       StringRef SecName = SecPair.first;
504       StringRef File = SecPair.second;
505       ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
506           MemoryBuffer::getFile(File);
507       if (!BufOrErr)
508         reportError(File, BufOrErr.getError());
509       std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
510       ArrayRef<uint8_t> Data(
511           reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
512           Buf->getBufferSize());
513       OwnedDataSection &NewSection =
514           Obj.addSection<OwnedDataSection>(SecName, Data);
515       if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
516         NewSection.Type = SHT_NOTE;
517     }
518   }
519 
520   if (!Config.DumpSection.empty()) {
521     for (const auto &Flag : Config.DumpSection) {
522       std::pair<StringRef, StringRef> SecPair = Flag.split("=");
523       StringRef SecName = SecPair.first;
524       StringRef File = SecPair.second;
525       if (Error E = dumpSectionToFile(SecName, File, Obj))
526         reportError(Config.InputFilename, std::move(E));
527     }
528   }
529 
530   if (!Config.AddGnuDebugLink.empty())
531     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
532 }
533 
executeObjcopyOnRawBinary(const CopyConfig & Config,MemoryBuffer & In,Buffer & Out)534 void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
535                                Buffer &Out) {
536   BinaryReader Reader(Config.BinaryArch, &In);
537   std::unique_ptr<Object> Obj = Reader.create();
538 
539   // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
540   // (-B<arch>).
541   const ElfType OutputElfType = getOutputElfType(
542       Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch);
543   handleArgs(Config, *Obj, Reader, OutputElfType);
544   std::unique_ptr<Writer> Writer =
545       createWriter(Config, *Obj, Out, OutputElfType);
546   Writer->finalize();
547   Writer->write();
548 }
549 
executeObjcopyOnBinary(const CopyConfig & Config,object::ELFObjectFileBase & In,Buffer & Out)550 void executeObjcopyOnBinary(const CopyConfig &Config,
551                             object::ELFObjectFileBase &In, Buffer &Out) {
552   ELFReader Reader(&In);
553   std::unique_ptr<Object> Obj = Reader.create();
554   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
555   const ElfType OutputElfType =
556       Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
557                         : getOutputElfType(In);
558   ArrayRef<uint8_t> BuildIdBytes;
559 
560   if (!Config.BuildIdLinkDir.empty()) {
561     BuildIdBytes = unwrapOrError(findBuildID(In));
562     if (BuildIdBytes.size() < 2)
563       error("build ID in file '" + Config.InputFilename +
564             "' is smaller than two bytes");
565   }
566 
567   if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) {
568     linkToBuildIdDir(Config, Config.InputFilename,
569                      Config.BuildIdLinkInput.getValue(), BuildIdBytes);
570   }
571   handleArgs(Config, *Obj, Reader, OutputElfType);
572   std::unique_ptr<Writer> Writer =
573       createWriter(Config, *Obj, Out, OutputElfType);
574   Writer->finalize();
575   Writer->write();
576   if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) {
577     linkToBuildIdDir(Config, Config.OutputFilename,
578                      Config.BuildIdLinkOutput.getValue(), BuildIdBytes);
579   }
580 }
581 
582 } // end namespace elf
583 } // end namespace objcopy
584 } // end namespace llvm
585