xref: /freebsd/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- ELFObjcopy.cpp -----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ObjCopy/ELF/ELFObjcopy.h"
10 #include "ELFObject.h"
11 #include "llvm/ADT/BitmaskEnum.h"
12 #include "llvm/ADT/DenseSet.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/Twine.h"
16 #include "llvm/BinaryFormat/ELF.h"
17 #include "llvm/MC/MCTargetOptions.h"
18 #include "llvm/ObjCopy/CommonConfig.h"
19 #include "llvm/ObjCopy/ELF/ELFConfig.h"
20 #include "llvm/Object/Binary.h"
21 #include "llvm/Object/ELFObjectFile.h"
22 #include "llvm/Object/ELFTypes.h"
23 #include "llvm/Object/Error.h"
24 #include "llvm/Option/Option.h"
25 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/Compression.h"
27 #include "llvm/Support/Errc.h"
28 #include "llvm/Support/Error.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/Memory.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include <algorithm>
33 #include <cassert>
34 #include <cstdlib>
35 #include <functional>
36 #include <memory>
37 #include <string>
38 #include <system_error>
39 #include <utility>
40 
41 using namespace llvm;
42 using namespace llvm::ELF;
43 using namespace llvm::objcopy;
44 using namespace llvm::objcopy::elf;
45 using namespace llvm::object;
46 
47 using SectionPred = std::function<bool(const SectionBase &Sec)>;
48 
isDebugSection(const SectionBase & Sec)49 static bool isDebugSection(const SectionBase &Sec) {
50   return StringRef(Sec.Name).starts_with(".debug") || Sec.Name == ".gdb_index";
51 }
52 
isDWOSection(const SectionBase & Sec)53 static bool isDWOSection(const SectionBase &Sec) {
54   return StringRef(Sec.Name).ends_with(".dwo");
55 }
56 
onlyKeepDWOPred(const Object & Obj,const SectionBase & Sec)57 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
58   // We can't remove the section header string table.
59   if (&Sec == Obj.SectionNames)
60     return false;
61   // Short of keeping the string table we want to keep everything that is a DWO
62   // section and remove everything else.
63   return !isDWOSection(Sec);
64 }
65 
getNewShfFlags(SectionFlag AllFlags,uint16_t EMachine)66 static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,
67                                          uint16_t EMachine) {
68   uint64_t NewFlags = 0;
69   if (AllFlags & SectionFlag::SecAlloc)
70     NewFlags |= ELF::SHF_ALLOC;
71   if (!(AllFlags & SectionFlag::SecReadonly))
72     NewFlags |= ELF::SHF_WRITE;
73   if (AllFlags & SectionFlag::SecCode)
74     NewFlags |= ELF::SHF_EXECINSTR;
75   if (AllFlags & SectionFlag::SecMerge)
76     NewFlags |= ELF::SHF_MERGE;
77   if (AllFlags & SectionFlag::SecStrings)
78     NewFlags |= ELF::SHF_STRINGS;
79   if (AllFlags & SectionFlag::SecExclude)
80     NewFlags |= ELF::SHF_EXCLUDE;
81   if (AllFlags & SectionFlag::SecLarge) {
82     if (EMachine != EM_X86_64)
83       return createStringError(errc::invalid_argument,
84                                "section flag SHF_X86_64_LARGE can only be used "
85                                "with x86_64 architecture");
86     NewFlags |= ELF::SHF_X86_64_LARGE;
87   }
88   return NewFlags;
89 }
90 
getSectionFlagsPreserveMask(uint64_t OldFlags,uint64_t NewFlags,uint16_t EMachine)91 static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
92                                             uint64_t NewFlags,
93                                             uint16_t EMachine) {
94   // Preserve some flags which should not be dropped when setting flags.
95   // Also, preserve anything OS/processor dependant.
96   const uint64_t PreserveMask =
97       (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
98        ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
99        ELF::SHF_INFO_LINK) &
100       ~ELF::SHF_EXCLUDE &
101       ~(EMachine == EM_X86_64 ? (uint64_t)ELF::SHF_X86_64_LARGE : 0UL);
102   return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
103 }
104 
setSectionType(SectionBase & Sec,uint64_t Type)105 static void setSectionType(SectionBase &Sec, uint64_t Type) {
106   // If Sec's type is changed from SHT_NOBITS due to --set-section-flags,
107   // Offset may not be aligned. Align it to max(Align, 1).
108   if (Sec.Type == ELF::SHT_NOBITS && Type != ELF::SHT_NOBITS)
109     Sec.Offset = alignTo(Sec.Offset, std::max(Sec.Align, uint64_t(1)));
110   Sec.Type = Type;
111 }
112 
setSectionFlagsAndType(SectionBase & Sec,SectionFlag Flags,uint16_t EMachine)113 static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,
114                                     uint16_t EMachine) {
115   Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);
116   if (!NewFlags)
117     return NewFlags.takeError();
118   Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);
119 
120   // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
121   // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
122   // non-ALLOC SHT_NOBITS sections do not make much sense.
123   if (Sec.Type == SHT_NOBITS &&
124       (!(Sec.Flags & ELF::SHF_ALLOC) ||
125        Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
126     setSectionType(Sec, ELF::SHT_PROGBITS);
127 
128   return Error::success();
129 }
130 
getOutputElfType(const Binary & Bin)131 static ElfType getOutputElfType(const Binary &Bin) {
132   // Infer output ELF type from the input ELF object
133   if (isa<ELFObjectFile<ELF32LE>>(Bin))
134     return ELFT_ELF32LE;
135   if (isa<ELFObjectFile<ELF64LE>>(Bin))
136     return ELFT_ELF64LE;
137   if (isa<ELFObjectFile<ELF32BE>>(Bin))
138     return ELFT_ELF32BE;
139   if (isa<ELFObjectFile<ELF64BE>>(Bin))
140     return ELFT_ELF64BE;
141   llvm_unreachable("Invalid ELFType");
142 }
143 
getOutputElfType(const MachineInfo & MI)144 static ElfType getOutputElfType(const MachineInfo &MI) {
145   // Infer output ELF type from the binary arch specified
146   if (MI.Is64Bit)
147     return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
148   else
149     return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
150 }
151 
createELFWriter(const CommonConfig & Config,Object & Obj,raw_ostream & Out,ElfType OutputElfType)152 static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,
153                                                Object &Obj, raw_ostream &Out,
154                                                ElfType OutputElfType) {
155   // Depending on the initial ELFT and OutputFormat we need a different Writer.
156   switch (OutputElfType) {
157   case ELFT_ELF32LE:
158     return std::make_unique<ELFWriter<ELF32LE>>(Obj, Out, !Config.StripSections,
159                                                 Config.OnlyKeepDebug);
160   case ELFT_ELF64LE:
161     return std::make_unique<ELFWriter<ELF64LE>>(Obj, Out, !Config.StripSections,
162                                                 Config.OnlyKeepDebug);
163   case ELFT_ELF32BE:
164     return std::make_unique<ELFWriter<ELF32BE>>(Obj, Out, !Config.StripSections,
165                                                 Config.OnlyKeepDebug);
166   case ELFT_ELF64BE:
167     return std::make_unique<ELFWriter<ELF64BE>>(Obj, Out, !Config.StripSections,
168                                                 Config.OnlyKeepDebug);
169   }
170   llvm_unreachable("Invalid output format");
171 }
172 
createWriter(const CommonConfig & Config,Object & Obj,raw_ostream & Out,ElfType OutputElfType)173 static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
174                                             Object &Obj, raw_ostream &Out,
175                                             ElfType OutputElfType) {
176   switch (Config.OutputFormat) {
177   case FileFormat::Binary:
178     return std::make_unique<BinaryWriter>(Obj, Out, Config);
179   case FileFormat::IHex:
180     return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);
181   case FileFormat::SREC:
182     return std::make_unique<SRECWriter>(Obj, Out, Config.OutputFilename);
183   default:
184     return createELFWriter(Config, Obj, Out, OutputElfType);
185   }
186 }
187 
dumpSectionToFile(StringRef SecName,StringRef Filename,StringRef InputFilename,Object & Obj)188 static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
189                                StringRef InputFilename, Object &Obj) {
190   for (auto &Sec : Obj.sections()) {
191     if (Sec.Name == SecName) {
192       if (Sec.Type == SHT_NOBITS)
193         return createFileError(InputFilename, object_error::parse_failed,
194                                "cannot dump section '%s': it has no contents",
195                                SecName.str().c_str());
196       Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
197           FileOutputBuffer::create(Filename, Sec.OriginalData.size());
198       if (!BufferOrErr)
199         return createFileError(Filename, BufferOrErr.takeError());
200       std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
201       std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
202                 Buf->getBufferStart());
203       if (Error E = Buf->commit())
204         return createFileError(Filename, std::move(E));
205       return Error::success();
206     }
207   }
208 
209   return createFileError(InputFilename, object_error::parse_failed,
210                          "section '%s' not found", SecName.str().c_str());
211 }
212 
compressOrDecompressSections(const CommonConfig & Config)213 Error Object::compressOrDecompressSections(const CommonConfig &Config) {
214   // Build a list of sections we are going to replace.
215   // We can't call `addSection` while iterating over sections,
216   // because it would mutate the sections array.
217   SmallVector<std::pair<SectionBase *, std::function<SectionBase *()>>, 0>
218       ToReplace;
219   for (SectionBase &Sec : sections()) {
220     std::optional<DebugCompressionType> CType;
221     for (auto &[Matcher, T] : Config.compressSections)
222       if (Matcher.matches(Sec.Name))
223         CType = T;
224     // Handle --compress-debug-sections and --decompress-debug-sections, which
225     // apply to non-ALLOC debug sections.
226     if (!(Sec.Flags & SHF_ALLOC) && StringRef(Sec.Name).starts_with(".debug")) {
227       if (Config.CompressionType != DebugCompressionType::None)
228         CType = Config.CompressionType;
229       else if (Config.DecompressDebugSections)
230         CType = DebugCompressionType::None;
231     }
232     if (!CType)
233       continue;
234 
235     if (Sec.ParentSegment)
236       return createStringError(
237           errc::invalid_argument,
238           "section '" + Sec.Name +
239               "' within a segment cannot be (de)compressed");
240 
241     if (auto *CS = dyn_cast<CompressedSection>(&Sec)) {
242       if (*CType == DebugCompressionType::None)
243         ToReplace.emplace_back(
244             &Sec, [=] { return &addSection<DecompressedSection>(*CS); });
245     } else if (*CType != DebugCompressionType::None) {
246       ToReplace.emplace_back(&Sec, [=, S = &Sec] {
247         return &addSection<CompressedSection>(
248             CompressedSection(*S, *CType, Is64Bits));
249       });
250     }
251   }
252 
253   DenseMap<SectionBase *, SectionBase *> FromTo;
254   for (auto [S, Func] : ToReplace)
255     FromTo[S] = Func();
256   return replaceSections(FromTo);
257 }
258 
isAArch64MappingSymbol(const Symbol & Sym)259 static bool isAArch64MappingSymbol(const Symbol &Sym) {
260   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
261       Sym.getShndx() == SHN_UNDEF)
262     return false;
263   StringRef Name = Sym.Name;
264   if (!Name.consume_front("$x") && !Name.consume_front("$d"))
265     return false;
266   return Name.empty() || Name.starts_with(".");
267 }
268 
isArmMappingSymbol(const Symbol & Sym)269 static bool isArmMappingSymbol(const Symbol &Sym) {
270   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
271       Sym.getShndx() == SHN_UNDEF)
272     return false;
273   StringRef Name = Sym.Name;
274   if (!Name.consume_front("$a") && !Name.consume_front("$d") &&
275       !Name.consume_front("$t"))
276     return false;
277   return Name.empty() || Name.starts_with(".");
278 }
279 
280 // Check if the symbol should be preserved because it is required by ABI.
isRequiredByABISymbol(const Object & Obj,const Symbol & Sym)281 static bool isRequiredByABISymbol(const Object &Obj, const Symbol &Sym) {
282   switch (Obj.Machine) {
283   case EM_AARCH64:
284     // Mapping symbols should be preserved for a relocatable object file.
285     return Obj.isRelocatable() && isAArch64MappingSymbol(Sym);
286   case EM_ARM:
287     // Mapping symbols should be preserved for a relocatable object file.
288     return Obj.isRelocatable() && isArmMappingSymbol(Sym);
289   default:
290     return false;
291   }
292 }
293 
isUnneededSymbol(const Symbol & Sym)294 static bool isUnneededSymbol(const Symbol &Sym) {
295   return !Sym.Referenced &&
296          (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
297          Sym.Type != STT_SECTION;
298 }
299 
updateAndRemoveSymbols(const CommonConfig & Config,const ELFConfig & ELFConfig,Object & Obj)300 static Error updateAndRemoveSymbols(const CommonConfig &Config,
301                                     const ELFConfig &ELFConfig, Object &Obj) {
302   // TODO: update or remove symbols only if there is an option that affects
303   // them.
304   if (!Obj.SymbolTable)
305     return Error::success();
306 
307   Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
308     if (Config.SymbolsToSkip.matches(Sym.Name))
309       return;
310 
311     // Common and undefined symbols don't make sense as local symbols, and can
312     // even cause crashes if we localize those, so skip them.
313     if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
314         ((ELFConfig.LocalizeHidden &&
315           (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
316          Config.SymbolsToLocalize.matches(Sym.Name)))
317       Sym.Binding = STB_LOCAL;
318 
319     for (auto &[Matcher, Visibility] : ELFConfig.SymbolsToSetVisibility)
320       if (Matcher.matches(Sym.Name))
321         Sym.Visibility = Visibility;
322 
323     // Note: these two globalize flags have very similar names but different
324     // meanings:
325     //
326     // --globalize-symbol: promote a symbol to global
327     // --keep-global-symbol: all symbols except for these should be made local
328     //
329     // If --globalize-symbol is specified for a given symbol, it will be
330     // global in the output file even if it is not included via
331     // --keep-global-symbol. Because of that, make sure to check
332     // --globalize-symbol second.
333     if (!Config.SymbolsToKeepGlobal.empty() &&
334         !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
335         Sym.getShndx() != SHN_UNDEF)
336       Sym.Binding = STB_LOCAL;
337 
338     if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
339         Sym.getShndx() != SHN_UNDEF)
340       Sym.Binding = STB_GLOBAL;
341 
342     // SymbolsToWeaken applies to both STB_GLOBAL and STB_GNU_UNIQUE.
343     if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding != STB_LOCAL)
344       Sym.Binding = STB_WEAK;
345 
346     if (Config.Weaken && Sym.Binding != STB_LOCAL &&
347         Sym.getShndx() != SHN_UNDEF)
348       Sym.Binding = STB_WEAK;
349 
350     const auto I = Config.SymbolsToRename.find(Sym.Name);
351     if (I != Config.SymbolsToRename.end())
352       Sym.Name = std::string(I->getValue());
353 
354     if (!Config.SymbolsPrefixRemove.empty() && Sym.Type != STT_SECTION)
355       if (StringRef(Sym.Name).starts_with(Config.SymbolsPrefixRemove))
356         Sym.Name = Sym.Name.substr(Config.SymbolsPrefixRemove.size());
357 
358     if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
359       Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
360   });
361 
362   // The purpose of this loop is to mark symbols referenced by sections
363   // (like GroupSection or RelocationSection). This way, we know which
364   // symbols are still 'needed' and which are not.
365   if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
366       !Config.OnlySection.empty() || Config.DiscardMode != DiscardType::None) {
367     for (SectionBase &Sec : Obj.sections())
368       Sec.markSymbols();
369   }
370 
371   auto RemoveSymbolsPred = [&](const Symbol &Sym) {
372     if (Config.SymbolsToKeep.matches(Sym.Name) ||
373         (ELFConfig.KeepFileSymbols && Sym.Type == STT_FILE))
374       return false;
375 
376     if (Config.SymbolsToRemove.matches(Sym.Name))
377       return true;
378 
379     if (Config.StripAll || Config.StripAllGNU)
380       return true;
381 
382     if (isRequiredByABISymbol(Obj, Sym))
383       return false;
384 
385     if (Config.StripDebug && Sym.Type == STT_FILE)
386       return true;
387 
388     if ((Config.StripUnneeded ||
389          Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
390         (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
391       return true;
392 
393     if (!Sym.Referenced) {
394       if ((Config.DiscardMode == DiscardType::All ||
395            (Config.DiscardMode == DiscardType::Locals &&
396             StringRef(Sym.Name).starts_with(".L"))) &&
397           Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
398           Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
399         return true;
400       // We want to remove undefined symbols if all references have been
401       // stripped.
402       if (!Config.OnlySection.empty() && Sym.getShndx() == SHN_UNDEF)
403         return true;
404     }
405 
406     return false;
407   };
408 
409   return Obj.removeSymbols(RemoveSymbolsPred);
410 }
411 
replaceAndRemoveSections(const CommonConfig & Config,const ELFConfig & ELFConfig,Object & Obj)412 static Error replaceAndRemoveSections(const CommonConfig &Config,
413                                       const ELFConfig &ELFConfig, Object &Obj) {
414   SectionPred RemovePred = [](const SectionBase &) { return false; };
415 
416   // Removes:
417   if (!Config.ToRemove.empty()) {
418     RemovePred = [&Config](const SectionBase &Sec) {
419       return Config.ToRemove.matches(Sec.Name);
420     };
421   }
422 
423   if (Config.StripDWO)
424     RemovePred = [RemovePred](const SectionBase &Sec) {
425       return isDWOSection(Sec) || RemovePred(Sec);
426     };
427 
428   if (Config.ExtractDWO)
429     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
430       return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
431     };
432 
433   if (Config.StripAllGNU)
434     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
435       if (RemovePred(Sec))
436         return true;
437       if ((Sec.Flags & SHF_ALLOC) != 0)
438         return false;
439       if (&Sec == Obj.SectionNames)
440         return false;
441       switch (Sec.Type) {
442       case SHT_SYMTAB:
443       case SHT_REL:
444       case SHT_RELA:
445       case SHT_STRTAB:
446         return true;
447       }
448       return isDebugSection(Sec);
449     };
450 
451   if (Config.StripSections) {
452     RemovePred = [RemovePred](const SectionBase &Sec) {
453       return RemovePred(Sec) || Sec.ParentSegment == nullptr;
454     };
455   }
456 
457   if (Config.StripDebug || Config.StripUnneeded) {
458     RemovePred = [RemovePred](const SectionBase &Sec) {
459       return RemovePred(Sec) || isDebugSection(Sec);
460     };
461   }
462 
463   if (Config.StripNonAlloc)
464     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
465       if (RemovePred(Sec))
466         return true;
467       if (&Sec == Obj.SectionNames)
468         return false;
469       return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
470     };
471 
472   if (Config.StripAll)
473     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
474       if (RemovePred(Sec))
475         return true;
476       if (&Sec == Obj.SectionNames)
477         return false;
478       if (StringRef(Sec.Name).starts_with(".gnu.warning"))
479         return false;
480       if (StringRef(Sec.Name).starts_with(".gnu_debuglink"))
481         return false;
482       // We keep the .ARM.attribute section to maintain compatibility
483       // with Debian derived distributions. This is a bug in their
484       // patchset as documented here:
485       // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
486       if (Sec.Type == SHT_ARM_ATTRIBUTES)
487         return false;
488       if (Sec.ParentSegment != nullptr)
489         return false;
490       return (Sec.Flags & SHF_ALLOC) == 0;
491     };
492 
493   if (Config.ExtractPartition || Config.ExtractMainPartition) {
494     RemovePred = [RemovePred](const SectionBase &Sec) {
495       if (RemovePred(Sec))
496         return true;
497       if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
498         return true;
499       return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
500     };
501   }
502 
503   // Explicit copies:
504   if (!Config.OnlySection.empty()) {
505     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
506       // Explicitly keep these sections regardless of previous removes.
507       if (Config.OnlySection.matches(Sec.Name))
508         return false;
509 
510       // Allow all implicit removes.
511       if (RemovePred(Sec))
512         return true;
513 
514       // Keep special sections.
515       if (Obj.SectionNames == &Sec)
516         return false;
517       if (Obj.SymbolTable == &Sec ||
518           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
519         return false;
520 
521       // Remove everything else.
522       return true;
523     };
524   }
525 
526   if (!Config.KeepSection.empty()) {
527     RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
528       // Explicitly keep these sections regardless of previous removes.
529       if (Config.KeepSection.matches(Sec.Name))
530         return false;
531       // Otherwise defer to RemovePred.
532       return RemovePred(Sec);
533     };
534   }
535 
536   // This has to be the last predicate assignment.
537   // If the option --keep-symbol has been specified
538   // and at least one of those symbols is present
539   // (equivalently, the updated symbol table is not empty)
540   // the symbol table and the string table should not be removed.
541   if ((!Config.SymbolsToKeep.empty() || ELFConfig.KeepFileSymbols) &&
542       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
543     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
544       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
545         return false;
546       return RemovePred(Sec);
547     };
548   }
549 
550   if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))
551     return E;
552 
553   if (Error E = Obj.compressOrDecompressSections(Config))
554     return E;
555 
556   return Error::success();
557 }
558 
559 // Add symbol to the Object symbol table with the specified properties.
addSymbol(Object & Obj,const NewSymbolInfo & SymInfo,uint8_t DefaultVisibility)560 static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
561                       uint8_t DefaultVisibility) {
562   SectionBase *Sec = Obj.findSection(SymInfo.SectionName);
563   uint64_t Value = Sec ? Sec->Addr + SymInfo.Value : SymInfo.Value;
564 
565   uint8_t Bind = ELF::STB_GLOBAL;
566   uint8_t Type = ELF::STT_NOTYPE;
567   uint8_t Visibility = DefaultVisibility;
568 
569   for (SymbolFlag FlagValue : SymInfo.Flags)
570     switch (FlagValue) {
571     case SymbolFlag::Global:
572       Bind = ELF::STB_GLOBAL;
573       break;
574     case SymbolFlag::Local:
575       Bind = ELF::STB_LOCAL;
576       break;
577     case SymbolFlag::Weak:
578       Bind = ELF::STB_WEAK;
579       break;
580     case SymbolFlag::Default:
581       Visibility = ELF::STV_DEFAULT;
582       break;
583     case SymbolFlag::Hidden:
584       Visibility = ELF::STV_HIDDEN;
585       break;
586     case SymbolFlag::Protected:
587       Visibility = ELF::STV_PROTECTED;
588       break;
589     case SymbolFlag::File:
590       Type = ELF::STT_FILE;
591       break;
592     case SymbolFlag::Section:
593       Type = ELF::STT_SECTION;
594       break;
595     case SymbolFlag::Object:
596       Type = ELF::STT_OBJECT;
597       break;
598     case SymbolFlag::Function:
599       Type = ELF::STT_FUNC;
600       break;
601     case SymbolFlag::IndirectFunction:
602       Type = ELF::STT_GNU_IFUNC;
603       break;
604     default: /* Other flag values are ignored for ELF. */
605       break;
606     };
607 
608   Obj.SymbolTable->addSymbol(
609       SymInfo.SymbolName, Bind, Type, Sec, Value, Visibility,
610       Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
611 }
612 
613 namespace {
614 struct RemoveNoteDetail {
615   struct DeletedRange {
616     uint64_t OldFrom;
617     uint64_t OldTo;
618   };
619 
620   template <class ELFT>
621   static std::vector<DeletedRange>
622   findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
623                     ArrayRef<RemoveNoteInfo> NotesToRemove);
624   static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
625                                          ArrayRef<DeletedRange> ToRemove);
626 };
627 } // namespace
628 
629 template <class ELFT>
630 std::vector<RemoveNoteDetail::DeletedRange>
findNotesToRemove(ArrayRef<uint8_t> Data,size_t Align,ArrayRef<RemoveNoteInfo> NotesToRemove)631 RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
632                                     ArrayRef<RemoveNoteInfo> NotesToRemove) {
633   using Elf_Nhdr = typename ELFT::Nhdr;
634   using Elf_Note = typename ELFT::Note;
635   std::vector<DeletedRange> ToRemove;
636   uint64_t CurPos = 0;
637   while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {
638     auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);
639     size_t FullSize = Nhdr->getSize(Align);
640     if (CurPos + FullSize > Data.size())
641       break;
642     Elf_Note Note(*Nhdr);
643     bool ShouldRemove =
644         llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) {
645           return NoteInfo.TypeId == Note.getType() &&
646                  (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
647         });
648     if (ShouldRemove)
649       ToRemove.push_back({CurPos, CurPos + FullSize});
650     CurPos += FullSize;
651   }
652   return ToRemove;
653 }
654 
655 std::vector<uint8_t>
updateData(ArrayRef<uint8_t> OldData,ArrayRef<DeletedRange> ToRemove)656 RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
657                              ArrayRef<DeletedRange> ToRemove) {
658   std::vector<uint8_t> NewData;
659   NewData.reserve(OldData.size());
660   uint64_t CurPos = 0;
661   for (const DeletedRange &RemRange : ToRemove) {
662     if (CurPos < RemRange.OldFrom) {
663       auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
664       llvm::append_range(NewData, Slice);
665     }
666     CurPos = RemRange.OldTo;
667   }
668   if (CurPos < OldData.size()) {
669     auto Slice = OldData.slice(CurPos);
670     llvm::append_range(NewData, Slice);
671   }
672   return NewData;
673 }
674 
removeNotes(Object & Obj,endianness Endianness,ArrayRef<RemoveNoteInfo> NotesToRemove,function_ref<Error (Error)> ErrorCallback)675 static Error removeNotes(Object &Obj, endianness Endianness,
676                          ArrayRef<RemoveNoteInfo> NotesToRemove,
677                          function_ref<Error(Error)> ErrorCallback) {
678   // TODO: Support note segments.
679   if (ErrorCallback) {
680     for (Segment &Seg : Obj.segments()) {
681       if (Seg.Type == PT_NOTE) {
682         if (Error E = ErrorCallback(createStringError(
683                 errc::not_supported, "note segments are not supported")))
684           return E;
685         break;
686       }
687     }
688   }
689   for (auto &Sec : Obj.sections()) {
690     if (Sec.Type != SHT_NOTE || !Sec.hasContents())
691       continue;
692     // TODO: Support note sections in segments.
693     if (Sec.ParentSegment) {
694       if (ErrorCallback)
695         if (Error E = ErrorCallback(createStringError(
696                 errc::not_supported,
697                 "cannot remove note(s) from " + Sec.Name +
698                     ": sections in segments are not supported")))
699           return E;
700       continue;
701     }
702     ArrayRef<uint8_t> OldData = Sec.getContents();
703     size_t Align = std::max<size_t>(4, Sec.Align);
704     // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
705     // header, so the parsers are the same.
706     auto ToRemove = (Endianness == endianness::little)
707                         ? RemoveNoteDetail::findNotesToRemove<ELF64LE>(
708                               OldData, Align, NotesToRemove)
709                         : RemoveNoteDetail::findNotesToRemove<ELF64BE>(
710                               OldData, Align, NotesToRemove);
711     if (!ToRemove.empty()) {
712       if (Error E = Obj.updateSectionData(
713               Sec, RemoveNoteDetail::updateData(OldData, ToRemove)))
714         return E;
715     }
716   }
717   return Error::success();
718 }
719 
720 static Error
handleUserSection(const NewSectionInfo & NewSection,function_ref<Error (StringRef,ArrayRef<uint8_t>)> F)721 handleUserSection(const NewSectionInfo &NewSection,
722                   function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
723   ArrayRef<uint8_t> Data(reinterpret_cast<const uint8_t *>(
724                              NewSection.SectionData->getBufferStart()),
725                          NewSection.SectionData->getBufferSize());
726   return F(NewSection.SectionName, Data);
727 }
728 
verifyNoteSection(StringRef Name,endianness Endianness,ArrayRef<uint8_t> Data)729 static Error verifyNoteSection(StringRef Name, endianness Endianness,
730                                ArrayRef<uint8_t> Data) {
731   // An ELF note has the following structure:
732   // Name Size: 4 bytes (integer)
733   // Desc Size: 4 bytes (integer)
734   // Type     : 4 bytes
735   // Name     : variable size, padded to a 4 byte boundary
736   // Desc     : variable size, padded to a 4 byte boundary
737 
738   if (Data.empty())
739     return Error::success();
740 
741   if (Data.size() < 12) {
742     std::string msg;
743     raw_string_ostream(msg)
744         << Name << " data must be either empty or at least 12 bytes long";
745     return createStringError(errc::invalid_argument, msg);
746   }
747   if (Data.size() % 4 != 0) {
748     std::string msg;
749     raw_string_ostream(msg)
750         << Name << " data size must be a  multiple of 4 bytes";
751     return createStringError(errc::invalid_argument, msg);
752   }
753   ArrayRef<uint8_t> NameSize = Data.slice(0, 4);
754   ArrayRef<uint8_t> DescSize = Data.slice(4, 4);
755 
756   uint32_t NameSizeValue = support::endian::read32(NameSize.data(), Endianness);
757   uint32_t DescSizeValue = support::endian::read32(DescSize.data(), Endianness);
758 
759   uint64_t ExpectedDataSize =
760       /*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 +
761       /*Name=*/alignTo(NameSizeValue, 4) +
762       /*Desc=*/alignTo(DescSizeValue, 4);
763   uint64_t ActualDataSize = Data.size();
764   if (ActualDataSize != ExpectedDataSize) {
765     std::string msg;
766     raw_string_ostream(msg)
767         << Name
768         << " data size is incompatible with the content of "
769            "the name and description size fields:"
770         << " expecting " << ExpectedDataSize << ", found " << ActualDataSize;
771     return createStringError(errc::invalid_argument, msg);
772   }
773 
774   return Error::success();
775 }
776 
777 // This function handles the high level operations of GNU objcopy including
778 // handling command line options. It's important to outline certain properties
779 // we expect to hold of the command line operations. Any operation that "keeps"
780 // should keep regardless of a remove. Additionally any removal should respect
781 // any previous removals. Lastly whether or not something is removed shouldn't
782 // depend a) on the order the options occur in or b) on some opaque priority
783 // system. The only priority is that keeps/copies overrule removes.
handleArgs(const CommonConfig & Config,const ELFConfig & ELFConfig,ElfType OutputElfType,Object & Obj)784 static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
785                         ElfType OutputElfType, Object &Obj) {
786   if (Config.OutputArch) {
787     Obj.Machine = Config.OutputArch->EMachine;
788     Obj.OSABI = Config.OutputArch->OSABI;
789   }
790 
791   if (!Config.SplitDWO.empty() && Config.ExtractDWO) {
792     return Obj.removeSections(
793         ELFConfig.AllowBrokenLinks,
794         [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); });
795   }
796 
797   // Dump sections before add/remove for compatibility with GNU objcopy.
798   for (StringRef Flag : Config.DumpSection) {
799     StringRef SectionName;
800     StringRef FileName;
801     std::tie(SectionName, FileName) = Flag.split('=');
802     if (Error E =
803             dumpSectionToFile(SectionName, FileName, Config.InputFilename, Obj))
804       return E;
805   }
806 
807   // It is important to remove the sections first. For example, we want to
808   // remove the relocation sections before removing the symbols. That allows
809   // us to avoid reporting the inappropriate errors about removing symbols
810   // named in relocations.
811   if (Error E = replaceAndRemoveSections(Config, ELFConfig, Obj))
812     return createFileError(Config.InputFilename, std::move(E));
813 
814   if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj))
815     return createFileError(Config.InputFilename, std::move(E));
816 
817   if (!Config.SetSectionAlignment.empty()) {
818     for (SectionBase &Sec : Obj.sections()) {
819       auto I = Config.SetSectionAlignment.find(Sec.Name);
820       if (I != Config.SetSectionAlignment.end())
821         Sec.Align = I->second;
822     }
823   }
824 
825   if (Config.ChangeSectionLMAValAll != 0) {
826     for (Segment &Seg : Obj.segments()) {
827       if (Seg.MemSize > 0) {
828         if (Config.ChangeSectionLMAValAll > 0 &&
829             Seg.PAddr > std::numeric_limits<uint64_t>::max() -
830                             Config.ChangeSectionLMAValAll) {
831           return createFileError(
832               Config.InputFilename, errc::invalid_argument,
833               "address 0x" + Twine::utohexstr(Seg.PAddr) +
834                   " cannot be increased by 0x" +
835                   Twine::utohexstr(Config.ChangeSectionLMAValAll) +
836                   ". The result would overflow");
837         } else if (Config.ChangeSectionLMAValAll < 0 &&
838                    Seg.PAddr < std::numeric_limits<uint64_t>::min() -
839                                    Config.ChangeSectionLMAValAll) {
840           return createFileError(
841               Config.InputFilename, errc::invalid_argument,
842               "address 0x" + Twine::utohexstr(Seg.PAddr) +
843                   " cannot be decreased by 0x" +
844                   Twine::utohexstr(std::abs(Config.ChangeSectionLMAValAll)) +
845                   ". The result would underflow");
846         }
847         Seg.PAddr += Config.ChangeSectionLMAValAll;
848       }
849     }
850   }
851 
852   if (!Config.ChangeSectionAddress.empty()) {
853     if (Obj.Type != ELF::ET_REL)
854       return createFileError(
855           Config.InputFilename, object_error::invalid_file_type,
856           "cannot change section address in a non-relocatable file");
857     StringMap<AddressUpdate> SectionsToUpdateAddress;
858     for (const SectionPatternAddressUpdate &PatternUpdate :
859          reverse(Config.ChangeSectionAddress)) {
860       for (SectionBase &Sec : Obj.sections()) {
861         if (PatternUpdate.SectionPattern.matches(Sec.Name) &&
862             SectionsToUpdateAddress.try_emplace(Sec.Name, PatternUpdate.Update)
863                 .second) {
864           if (PatternUpdate.Update.Kind == AdjustKind::Subtract &&
865               Sec.Addr < PatternUpdate.Update.Value) {
866             return createFileError(
867                 Config.InputFilename, errc::invalid_argument,
868                 "address 0x" + Twine::utohexstr(Sec.Addr) +
869                     " cannot be decreased by 0x" +
870                     Twine::utohexstr(PatternUpdate.Update.Value) +
871                     ". The result would underflow");
872           }
873           if (PatternUpdate.Update.Kind == AdjustKind::Add &&
874               Sec.Addr > std::numeric_limits<uint64_t>::max() -
875                              PatternUpdate.Update.Value) {
876             return createFileError(
877                 Config.InputFilename, errc::invalid_argument,
878                 "address 0x" + Twine::utohexstr(Sec.Addr) +
879                     " cannot be increased by 0x" +
880                     Twine::utohexstr(PatternUpdate.Update.Value) +
881                     ". The result would overflow");
882           }
883 
884           switch (PatternUpdate.Update.Kind) {
885           case (AdjustKind::Set):
886             Sec.Addr = PatternUpdate.Update.Value;
887             break;
888           case (AdjustKind::Subtract):
889             Sec.Addr -= PatternUpdate.Update.Value;
890             break;
891           case (AdjustKind::Add):
892             Sec.Addr += PatternUpdate.Update.Value;
893             break;
894           }
895         }
896       }
897     }
898   }
899 
900   if (Config.OnlyKeepDebug)
901     for (auto &Sec : Obj.sections())
902       if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
903         Sec.Type = SHT_NOBITS;
904 
905   endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE
906                      ? endianness::little
907                      : endianness::big;
908 
909   if (!ELFConfig.NotesToRemove.empty()) {
910     if (Error Err =
911             removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))
912       return createFileError(Config.InputFilename, std::move(Err));
913   }
914 
915   for (const NewSectionInfo &AddedSection : Config.AddSection) {
916     auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {
917       OwnedDataSection &NewSection =
918           Obj.addSection<OwnedDataSection>(Name, Data);
919       if (Name.starts_with(".note") && Name != ".note.GNU-stack") {
920         NewSection.Type = SHT_NOTE;
921         if (ELFConfig.VerifyNoteSections)
922           return verifyNoteSection(Name, E, Data);
923       }
924       return Error::success();
925     };
926     if (Error E = handleUserSection(AddedSection, AddSection))
927       return createFileError(Config.InputFilename, std::move(E));
928   }
929 
930   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
931     auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
932       return Obj.updateSection(Name, Data);
933     };
934     if (Error E = handleUserSection(NewSection, UpdateSection))
935       return createFileError(Config.InputFilename, std::move(E));
936   }
937 
938   if (!Config.AddGnuDebugLink.empty())
939     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
940                                         Config.GnuDebugLinkCRC32);
941 
942   // If the symbol table was previously removed, we need to create a new one
943   // before adding new symbols.
944   if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty())
945     if (Error E = Obj.addNewSymbolTable())
946       return createFileError(Config.InputFilename, std::move(E));
947 
948   for (const NewSymbolInfo &SI : Config.SymbolsToAdd)
949     addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);
950 
951   // --set-section-{flags,type} work with sections added by --add-section.
952   if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {
953     for (auto &Sec : Obj.sections()) {
954       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
955       if (Iter != Config.SetSectionFlags.end()) {
956         const SectionFlagsUpdate &SFU = Iter->second;
957         if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))
958           return createFileError(Config.InputFilename, std::move(E));
959       }
960       auto It2 = Config.SetSectionType.find(Sec.Name);
961       if (It2 != Config.SetSectionType.end())
962         setSectionType(Sec, It2->second);
963     }
964   }
965 
966   if (!Config.SectionsToRename.empty()) {
967     std::vector<RelocationSectionBase *> RelocSections;
968     DenseSet<SectionBase *> RenamedSections;
969     for (SectionBase &Sec : Obj.sections()) {
970       auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec);
971       const auto Iter = Config.SectionsToRename.find(Sec.Name);
972       if (Iter != Config.SectionsToRename.end()) {
973         const SectionRename &SR = Iter->second;
974         Sec.Name = std::string(SR.NewName);
975         if (SR.NewFlags) {
976           if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))
977             return createFileError(Config.InputFilename, std::move(E));
978         }
979         RenamedSections.insert(&Sec);
980       } else if (RelocSec && !(Sec.Flags & SHF_ALLOC))
981         // Postpone processing relocation sections which are not specified in
982         // their explicit '--rename-section' commands until after their target
983         // sections are renamed.
984         // Dynamic relocation sections (i.e. ones with SHF_ALLOC) should be
985         // renamed only explicitly. Otherwise, renaming, for example, '.got.plt'
986         // would affect '.rela.plt', which is not desirable.
987         RelocSections.push_back(RelocSec);
988     }
989 
990     // Rename relocation sections according to their target sections.
991     for (RelocationSectionBase *RelocSec : RelocSections) {
992       auto Iter = RenamedSections.find(RelocSec->getSection());
993       if (Iter != RenamedSections.end())
994         RelocSec->Name = (RelocSec->getNamePrefix() + (*Iter)->Name).str();
995     }
996   }
997 
998   // Add a prefix to allocated sections and their relocation sections. This
999   // should be done after renaming the section by Config.SectionToRename to
1000   // imitate the GNU objcopy behavior.
1001   if (!Config.AllocSectionsPrefix.empty()) {
1002     DenseSet<SectionBase *> PrefixedSections;
1003     for (SectionBase &Sec : Obj.sections()) {
1004       if (Sec.Flags & SHF_ALLOC) {
1005         Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
1006         PrefixedSections.insert(&Sec);
1007       } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
1008         // Rename relocation sections associated to the allocated sections.
1009         // For example, if we rename .text to .prefix.text, we also rename
1010         // .rel.text to .rel.prefix.text.
1011         //
1012         // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
1013         // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
1014         // .rela.prefix.plt since GNU objcopy does so.
1015         const SectionBase *TargetSec = RelocSec->getSection();
1016         if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
1017           // If the relocation section comes *after* the target section, we
1018           // don't add Config.AllocSectionsPrefix because we've already added
1019           // the prefix to TargetSec->Name. Otherwise, if the relocation
1020           // section comes *before* the target section, we add the prefix.
1021           if (PrefixedSections.count(TargetSec))
1022             Sec.Name = (RelocSec->getNamePrefix() + TargetSec->Name).str();
1023           else
1024             Sec.Name = (RelocSec->getNamePrefix() + Config.AllocSectionsPrefix +
1025                         TargetSec->Name)
1026                            .str();
1027         }
1028       }
1029     }
1030   }
1031 
1032   if (ELFConfig.EntryExpr)
1033     Obj.Entry = ELFConfig.EntryExpr(Obj.Entry);
1034   return Error::success();
1035 }
1036 
writeOutput(const CommonConfig & Config,Object & Obj,raw_ostream & Out,ElfType OutputElfType)1037 static Error writeOutput(const CommonConfig &Config, Object &Obj,
1038                          raw_ostream &Out, ElfType OutputElfType) {
1039   std::unique_ptr<Writer> Writer =
1040       createWriter(Config, Obj, Out, OutputElfType);
1041   if (Error E = Writer->finalize())
1042     return E;
1043   return Writer->write();
1044 }
1045 
executeObjcopyOnIHex(const CommonConfig & Config,const ELFConfig & ELFConfig,MemoryBuffer & In,raw_ostream & Out)1046 Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
1047                                          const ELFConfig &ELFConfig,
1048                                          MemoryBuffer &In, raw_ostream &Out) {
1049   IHexReader Reader(&In);
1050   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
1051   if (!Obj)
1052     return Obj.takeError();
1053 
1054   const ElfType OutputElfType =
1055       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
1056   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1057     return E;
1058   return writeOutput(Config, **Obj, Out, OutputElfType);
1059 }
1060 
executeObjcopyOnRawBinary(const CommonConfig & Config,const ELFConfig & ELFConfig,MemoryBuffer & In,raw_ostream & Out)1061 Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
1062                                               const ELFConfig &ELFConfig,
1063                                               MemoryBuffer &In,
1064                                               raw_ostream &Out) {
1065   BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);
1066   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
1067   if (!Obj)
1068     return Obj.takeError();
1069 
1070   // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
1071   // (-B<arch>).
1072   const ElfType OutputElfType =
1073       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
1074   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1075     return E;
1076   return writeOutput(Config, **Obj, Out, OutputElfType);
1077 }
1078 
executeObjcopyOnBinary(const CommonConfig & Config,const ELFConfig & ELFConfig,object::ELFObjectFileBase & In,raw_ostream & Out)1079 Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
1080                                            const ELFConfig &ELFConfig,
1081                                            object::ELFObjectFileBase &In,
1082                                            raw_ostream &Out) {
1083   ELFReader Reader(&In, Config.ExtractPartition);
1084   Expected<std::unique_ptr<Object>> Obj =
1085       Reader.create(!Config.SymbolsToAdd.empty());
1086   if (!Obj)
1087     return Obj.takeError();
1088   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
1089   const ElfType OutputElfType = Config.OutputArch
1090                                     ? getOutputElfType(*Config.OutputArch)
1091                                     : getOutputElfType(In);
1092 
1093   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1094     return E;
1095 
1096   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
1097     return createFileError(Config.InputFilename, std::move(E));
1098 
1099   return Error::success();
1100 }
1101