xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- ELFObjcopy.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/ELF/ELFObjcopy.h"
1081ad6265SDimitry Andric #include "ELFObject.h"
1181ad6265SDimitry Andric #include "llvm/ADT/BitmaskEnum.h"
1281ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h"
1381ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
1481ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
1581ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
1681ad6265SDimitry Andric #include "llvm/ADT/Twine.h"
1781ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
1881ad6265SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
1981ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h"
2081ad6265SDimitry Andric #include "llvm/ObjCopy/ELF/ELFConfig.h"
2181ad6265SDimitry Andric #include "llvm/Object/Binary.h"
2281ad6265SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
2381ad6265SDimitry Andric #include "llvm/Object/ELFTypes.h"
2481ad6265SDimitry Andric #include "llvm/Object/Error.h"
2581ad6265SDimitry Andric #include "llvm/Option/Option.h"
2681ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2781ad6265SDimitry Andric #include "llvm/Support/Compression.h"
2881ad6265SDimitry Andric #include "llvm/Support/Errc.h"
2981ad6265SDimitry Andric #include "llvm/Support/Error.h"
3081ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
3181ad6265SDimitry Andric #include "llvm/Support/ErrorOr.h"
3281ad6265SDimitry Andric #include "llvm/Support/FileSystem.h"
3381ad6265SDimitry Andric #include "llvm/Support/Memory.h"
3481ad6265SDimitry Andric #include "llvm/Support/Path.h"
3581ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
3681ad6265SDimitry Andric #include <algorithm>
3781ad6265SDimitry Andric #include <cassert>
3881ad6265SDimitry Andric #include <cstdlib>
3981ad6265SDimitry Andric #include <functional>
4081ad6265SDimitry Andric #include <iterator>
4181ad6265SDimitry Andric #include <memory>
4281ad6265SDimitry Andric #include <string>
4381ad6265SDimitry Andric #include <system_error>
4481ad6265SDimitry Andric #include <utility>
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric using namespace llvm;
4781ad6265SDimitry Andric using namespace llvm::ELF;
4881ad6265SDimitry Andric using namespace llvm::objcopy;
4981ad6265SDimitry Andric using namespace llvm::objcopy::elf;
5081ad6265SDimitry Andric using namespace llvm::object;
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric using SectionPred = std::function<bool(const SectionBase &Sec)>;
5381ad6265SDimitry Andric 
5481ad6265SDimitry Andric static bool isDebugSection(const SectionBase &Sec) {
555f757f3fSDimitry Andric   return StringRef(Sec.Name).starts_with(".debug") || Sec.Name == ".gdb_index";
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric 
5881ad6265SDimitry Andric static bool isDWOSection(const SectionBase &Sec) {
595f757f3fSDimitry Andric   return StringRef(Sec.Name).ends_with(".dwo");
6081ad6265SDimitry Andric }
6181ad6265SDimitry Andric 
6281ad6265SDimitry Andric static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
6381ad6265SDimitry Andric   // We can't remove the section header string table.
6481ad6265SDimitry Andric   if (&Sec == Obj.SectionNames)
6581ad6265SDimitry Andric     return false;
6681ad6265SDimitry Andric   // Short of keeping the string table we want to keep everything that is a DWO
6781ad6265SDimitry Andric   // section and remove everything else.
6881ad6265SDimitry Andric   return !isDWOSection(Sec);
6981ad6265SDimitry Andric }
7081ad6265SDimitry Andric 
715f757f3fSDimitry Andric static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,
725f757f3fSDimitry Andric                                          uint16_t EMachine) {
7381ad6265SDimitry Andric   uint64_t NewFlags = 0;
7481ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecAlloc)
7581ad6265SDimitry Andric     NewFlags |= ELF::SHF_ALLOC;
7681ad6265SDimitry Andric   if (!(AllFlags & SectionFlag::SecReadonly))
7781ad6265SDimitry Andric     NewFlags |= ELF::SHF_WRITE;
7881ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecCode)
7981ad6265SDimitry Andric     NewFlags |= ELF::SHF_EXECINSTR;
8081ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecMerge)
8181ad6265SDimitry Andric     NewFlags |= ELF::SHF_MERGE;
8281ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecStrings)
8381ad6265SDimitry Andric     NewFlags |= ELF::SHF_STRINGS;
8481ad6265SDimitry Andric   if (AllFlags & SectionFlag::SecExclude)
8581ad6265SDimitry Andric     NewFlags |= ELF::SHF_EXCLUDE;
865f757f3fSDimitry Andric   if (AllFlags & SectionFlag::SecLarge) {
875f757f3fSDimitry Andric     if (EMachine != EM_X86_64)
885f757f3fSDimitry Andric       return createStringError(errc::invalid_argument,
895f757f3fSDimitry Andric                                "section flag SHF_X86_64_LARGE can only be used "
905f757f3fSDimitry Andric                                "with x86_64 architecture");
915f757f3fSDimitry Andric     NewFlags |= ELF::SHF_X86_64_LARGE;
925f757f3fSDimitry Andric   }
9381ad6265SDimitry Andric   return NewFlags;
9481ad6265SDimitry Andric }
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
975f757f3fSDimitry Andric                                             uint64_t NewFlags,
985f757f3fSDimitry Andric                                             uint16_t EMachine) {
9981ad6265SDimitry Andric   // Preserve some flags which should not be dropped when setting flags.
10081ad6265SDimitry Andric   // Also, preserve anything OS/processor dependant.
10181ad6265SDimitry Andric   const uint64_t PreserveMask =
10281ad6265SDimitry Andric       (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
10381ad6265SDimitry Andric        ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
10481ad6265SDimitry Andric        ELF::SHF_INFO_LINK) &
1055f757f3fSDimitry Andric       ~ELF::SHF_EXCLUDE &
1065f757f3fSDimitry Andric       ~(EMachine == EM_X86_64 ? (uint64_t)ELF::SHF_X86_64_LARGE : 0UL);
10781ad6265SDimitry Andric   return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
10881ad6265SDimitry Andric }
10981ad6265SDimitry Andric 
11006c3fb27SDimitry Andric static void setSectionType(SectionBase &Sec, uint64_t Type) {
11106c3fb27SDimitry Andric   // If Sec's type is changed from SHT_NOBITS due to --set-section-flags,
11206c3fb27SDimitry Andric   // Offset may not be aligned. Align it to max(Align, 1).
11306c3fb27SDimitry Andric   if (Sec.Type == ELF::SHT_NOBITS && Type != ELF::SHT_NOBITS)
11406c3fb27SDimitry Andric     Sec.Offset = alignTo(Sec.Offset, std::max(Sec.Align, uint64_t(1)));
11506c3fb27SDimitry Andric   Sec.Type = Type;
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric 
1185f757f3fSDimitry Andric static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,
1195f757f3fSDimitry Andric                                     uint16_t EMachine) {
1205f757f3fSDimitry Andric   Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);
1215f757f3fSDimitry Andric   if (!NewFlags)
1225f757f3fSDimitry Andric     return NewFlags.takeError();
1235f757f3fSDimitry Andric   Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
12681ad6265SDimitry Andric   // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
12781ad6265SDimitry Andric   // non-ALLOC SHT_NOBITS sections do not make much sense.
12881ad6265SDimitry Andric   if (Sec.Type == SHT_NOBITS &&
12981ad6265SDimitry Andric       (!(Sec.Flags & ELF::SHF_ALLOC) ||
13081ad6265SDimitry Andric        Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
13106c3fb27SDimitry Andric     setSectionType(Sec, ELF::SHT_PROGBITS);
1325f757f3fSDimitry Andric 
1335f757f3fSDimitry Andric   return Error::success();
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric static ElfType getOutputElfType(const Binary &Bin) {
13781ad6265SDimitry Andric   // Infer output ELF type from the input ELF object
13881ad6265SDimitry Andric   if (isa<ELFObjectFile<ELF32LE>>(Bin))
13981ad6265SDimitry Andric     return ELFT_ELF32LE;
14081ad6265SDimitry Andric   if (isa<ELFObjectFile<ELF64LE>>(Bin))
14181ad6265SDimitry Andric     return ELFT_ELF64LE;
14281ad6265SDimitry Andric   if (isa<ELFObjectFile<ELF32BE>>(Bin))
14381ad6265SDimitry Andric     return ELFT_ELF32BE;
14481ad6265SDimitry Andric   if (isa<ELFObjectFile<ELF64BE>>(Bin))
14581ad6265SDimitry Andric     return ELFT_ELF64BE;
14681ad6265SDimitry Andric   llvm_unreachable("Invalid ELFType");
14781ad6265SDimitry Andric }
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric static ElfType getOutputElfType(const MachineInfo &MI) {
15081ad6265SDimitry Andric   // Infer output ELF type from the binary arch specified
15181ad6265SDimitry Andric   if (MI.Is64Bit)
15281ad6265SDimitry Andric     return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
15381ad6265SDimitry Andric   else
15481ad6265SDimitry Andric     return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
15581ad6265SDimitry Andric }
15681ad6265SDimitry Andric 
15781ad6265SDimitry Andric static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,
15881ad6265SDimitry Andric                                                Object &Obj, raw_ostream &Out,
15981ad6265SDimitry Andric                                                ElfType OutputElfType) {
16081ad6265SDimitry Andric   // Depending on the initial ELFT and OutputFormat we need a different Writer.
16181ad6265SDimitry Andric   switch (OutputElfType) {
16281ad6265SDimitry Andric   case ELFT_ELF32LE:
16381ad6265SDimitry Andric     return std::make_unique<ELFWriter<ELF32LE>>(Obj, Out, !Config.StripSections,
16481ad6265SDimitry Andric                                                 Config.OnlyKeepDebug);
16581ad6265SDimitry Andric   case ELFT_ELF64LE:
16681ad6265SDimitry Andric     return std::make_unique<ELFWriter<ELF64LE>>(Obj, Out, !Config.StripSections,
16781ad6265SDimitry Andric                                                 Config.OnlyKeepDebug);
16881ad6265SDimitry Andric   case ELFT_ELF32BE:
16981ad6265SDimitry Andric     return std::make_unique<ELFWriter<ELF32BE>>(Obj, Out, !Config.StripSections,
17081ad6265SDimitry Andric                                                 Config.OnlyKeepDebug);
17181ad6265SDimitry Andric   case ELFT_ELF64BE:
17281ad6265SDimitry Andric     return std::make_unique<ELFWriter<ELF64BE>>(Obj, Out, !Config.StripSections,
17381ad6265SDimitry Andric                                                 Config.OnlyKeepDebug);
17481ad6265SDimitry Andric   }
17581ad6265SDimitry Andric   llvm_unreachable("Invalid output format");
17681ad6265SDimitry Andric }
17781ad6265SDimitry Andric 
17881ad6265SDimitry Andric static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
17981ad6265SDimitry Andric                                             Object &Obj, raw_ostream &Out,
18081ad6265SDimitry Andric                                             ElfType OutputElfType) {
18181ad6265SDimitry Andric   switch (Config.OutputFormat) {
18281ad6265SDimitry Andric   case FileFormat::Binary:
1835f757f3fSDimitry Andric     return std::make_unique<BinaryWriter>(Obj, Out, Config);
18481ad6265SDimitry Andric   case FileFormat::IHex:
185*0fca6ea1SDimitry Andric     return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);
186*0fca6ea1SDimitry Andric   case FileFormat::SREC:
187*0fca6ea1SDimitry Andric     return std::make_unique<SRECWriter>(Obj, Out, Config.OutputFilename);
18881ad6265SDimitry Andric   default:
18981ad6265SDimitry Andric     return createELFWriter(Config, Obj, Out, OutputElfType);
19081ad6265SDimitry Andric   }
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric 
19381ad6265SDimitry Andric static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
19481ad6265SDimitry Andric                                Object &Obj) {
19581ad6265SDimitry Andric   for (auto &Sec : Obj.sections()) {
19681ad6265SDimitry Andric     if (Sec.Name == SecName) {
19781ad6265SDimitry Andric       if (Sec.Type == SHT_NOBITS)
19881ad6265SDimitry Andric         return createStringError(object_error::parse_failed,
19981ad6265SDimitry Andric                                  "cannot dump section '%s': it has no contents",
20081ad6265SDimitry Andric                                  SecName.str().c_str());
20181ad6265SDimitry Andric       Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
20281ad6265SDimitry Andric           FileOutputBuffer::create(Filename, Sec.OriginalData.size());
20381ad6265SDimitry Andric       if (!BufferOrErr)
20481ad6265SDimitry Andric         return BufferOrErr.takeError();
20581ad6265SDimitry Andric       std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
20681ad6265SDimitry Andric       std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
20781ad6265SDimitry Andric                 Buf->getBufferStart());
20881ad6265SDimitry Andric       if (Error E = Buf->commit())
20981ad6265SDimitry Andric         return E;
21081ad6265SDimitry Andric       return Error::success();
21181ad6265SDimitry Andric     }
21281ad6265SDimitry Andric   }
21381ad6265SDimitry Andric   return createStringError(object_error::parse_failed, "section '%s' not found",
21481ad6265SDimitry Andric                            SecName.str().c_str());
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric 
217*0fca6ea1SDimitry Andric Error Object::compressOrDecompressSections(const CommonConfig &Config) {
218*0fca6ea1SDimitry Andric   // Build a list of sections we are going to replace.
219*0fca6ea1SDimitry Andric   // We can't call `addSection` while iterating over sections,
22081ad6265SDimitry Andric   // because it would mutate the sections array.
221*0fca6ea1SDimitry Andric   SmallVector<std::pair<SectionBase *, std::function<SectionBase *()>>, 0>
222*0fca6ea1SDimitry Andric       ToReplace;
223*0fca6ea1SDimitry Andric   for (SectionBase &Sec : sections()) {
224*0fca6ea1SDimitry Andric     std::optional<DebugCompressionType> CType;
225*0fca6ea1SDimitry Andric     for (auto &[Matcher, T] : Config.compressSections)
226*0fca6ea1SDimitry Andric       if (Matcher.matches(Sec.Name))
227*0fca6ea1SDimitry Andric         CType = T;
228*0fca6ea1SDimitry Andric     // Handle --compress-debug-sections and --decompress-debug-sections, which
229*0fca6ea1SDimitry Andric     // apply to non-ALLOC debug sections.
230*0fca6ea1SDimitry Andric     if (!(Sec.Flags & SHF_ALLOC) && StringRef(Sec.Name).starts_with(".debug")) {
231*0fca6ea1SDimitry Andric       if (Config.CompressionType != DebugCompressionType::None)
232*0fca6ea1SDimitry Andric         CType = Config.CompressionType;
233*0fca6ea1SDimitry Andric       else if (Config.DecompressDebugSections)
234*0fca6ea1SDimitry Andric         CType = DebugCompressionType::None;
235*0fca6ea1SDimitry Andric     }
236*0fca6ea1SDimitry Andric     if (!CType)
237*0fca6ea1SDimitry Andric       continue;
23881ad6265SDimitry Andric 
239*0fca6ea1SDimitry Andric     if (Sec.ParentSegment)
240*0fca6ea1SDimitry Andric       return createStringError(
241*0fca6ea1SDimitry Andric           errc::invalid_argument,
242*0fca6ea1SDimitry Andric           "section '" + Sec.Name +
243*0fca6ea1SDimitry Andric               "' within a segment cannot be (de)compressed");
24481ad6265SDimitry Andric 
245*0fca6ea1SDimitry Andric     if (auto *CS = dyn_cast<CompressedSection>(&Sec)) {
246*0fca6ea1SDimitry Andric       if (*CType == DebugCompressionType::None)
247*0fca6ea1SDimitry Andric         ToReplace.emplace_back(
248*0fca6ea1SDimitry Andric             &Sec, [=] { return &addSection<DecompressedSection>(*CS); });
249*0fca6ea1SDimitry Andric     } else if (*CType != DebugCompressionType::None) {
250*0fca6ea1SDimitry Andric       ToReplace.emplace_back(&Sec, [=, S = &Sec] {
251*0fca6ea1SDimitry Andric         return &addSection<CompressedSection>(
252*0fca6ea1SDimitry Andric             CompressedSection(*S, *CType, Is64Bits));
253*0fca6ea1SDimitry Andric       });
254*0fca6ea1SDimitry Andric     }
25581ad6265SDimitry Andric   }
25681ad6265SDimitry Andric 
257*0fca6ea1SDimitry Andric   DenseMap<SectionBase *, SectionBase *> FromTo;
258*0fca6ea1SDimitry Andric   for (auto [S, Func] : ToReplace)
259*0fca6ea1SDimitry Andric     FromTo[S] = Func();
260*0fca6ea1SDimitry Andric   return replaceSections(FromTo);
26181ad6265SDimitry Andric }
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric static bool isAArch64MappingSymbol(const Symbol &Sym) {
26481ad6265SDimitry Andric   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
26581ad6265SDimitry Andric       Sym.getShndx() == SHN_UNDEF)
26681ad6265SDimitry Andric     return false;
26781ad6265SDimitry Andric   StringRef Name = Sym.Name;
26881ad6265SDimitry Andric   if (!Name.consume_front("$x") && !Name.consume_front("$d"))
26981ad6265SDimitry Andric     return false;
2705f757f3fSDimitry Andric   return Name.empty() || Name.starts_with(".");
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric 
27381ad6265SDimitry Andric static bool isArmMappingSymbol(const Symbol &Sym) {
27481ad6265SDimitry Andric   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
27581ad6265SDimitry Andric       Sym.getShndx() == SHN_UNDEF)
27681ad6265SDimitry Andric     return false;
27781ad6265SDimitry Andric   StringRef Name = Sym.Name;
27881ad6265SDimitry Andric   if (!Name.consume_front("$a") && !Name.consume_front("$d") &&
27981ad6265SDimitry Andric       !Name.consume_front("$t"))
28081ad6265SDimitry Andric     return false;
2815f757f3fSDimitry Andric   return Name.empty() || Name.starts_with(".");
28281ad6265SDimitry Andric }
28381ad6265SDimitry Andric 
28481ad6265SDimitry Andric // Check if the symbol should be preserved because it is required by ABI.
28581ad6265SDimitry Andric static bool isRequiredByABISymbol(const Object &Obj, const Symbol &Sym) {
28681ad6265SDimitry Andric   switch (Obj.Machine) {
28781ad6265SDimitry Andric   case EM_AARCH64:
28881ad6265SDimitry Andric     // Mapping symbols should be preserved for a relocatable object file.
28981ad6265SDimitry Andric     return Obj.isRelocatable() && isAArch64MappingSymbol(Sym);
29081ad6265SDimitry Andric   case EM_ARM:
29181ad6265SDimitry Andric     // Mapping symbols should be preserved for a relocatable object file.
29281ad6265SDimitry Andric     return Obj.isRelocatable() && isArmMappingSymbol(Sym);
29381ad6265SDimitry Andric   default:
29481ad6265SDimitry Andric     return false;
29581ad6265SDimitry Andric   }
29681ad6265SDimitry Andric }
29781ad6265SDimitry Andric 
29881ad6265SDimitry Andric static bool isUnneededSymbol(const Symbol &Sym) {
29981ad6265SDimitry Andric   return !Sym.Referenced &&
30081ad6265SDimitry Andric          (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
30181ad6265SDimitry Andric          Sym.Type != STT_SECTION;
30281ad6265SDimitry Andric }
30381ad6265SDimitry Andric 
30481ad6265SDimitry Andric static Error updateAndRemoveSymbols(const CommonConfig &Config,
30581ad6265SDimitry Andric                                     const ELFConfig &ELFConfig, Object &Obj) {
30681ad6265SDimitry Andric   // TODO: update or remove symbols only if there is an option that affects
30781ad6265SDimitry Andric   // them.
30881ad6265SDimitry Andric   if (!Obj.SymbolTable)
30981ad6265SDimitry Andric     return Error::success();
31081ad6265SDimitry Andric 
31181ad6265SDimitry Andric   Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
312*0fca6ea1SDimitry Andric     if (Config.SymbolsToSkip.matches(Sym.Name))
313*0fca6ea1SDimitry Andric       return;
314*0fca6ea1SDimitry Andric 
31581ad6265SDimitry Andric     // Common and undefined symbols don't make sense as local symbols, and can
31681ad6265SDimitry Andric     // even cause crashes if we localize those, so skip them.
31781ad6265SDimitry Andric     if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
31881ad6265SDimitry Andric         ((ELFConfig.LocalizeHidden &&
31981ad6265SDimitry Andric           (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
32081ad6265SDimitry Andric          Config.SymbolsToLocalize.matches(Sym.Name)))
32181ad6265SDimitry Andric       Sym.Binding = STB_LOCAL;
32281ad6265SDimitry Andric 
323*0fca6ea1SDimitry Andric     for (auto &[Matcher, Visibility] : ELFConfig.SymbolsToSetVisibility)
324*0fca6ea1SDimitry Andric       if (Matcher.matches(Sym.Name))
325*0fca6ea1SDimitry Andric         Sym.Visibility = Visibility;
326*0fca6ea1SDimitry Andric 
32781ad6265SDimitry Andric     // Note: these two globalize flags have very similar names but different
32881ad6265SDimitry Andric     // meanings:
32981ad6265SDimitry Andric     //
33081ad6265SDimitry Andric     // --globalize-symbol: promote a symbol to global
33181ad6265SDimitry Andric     // --keep-global-symbol: all symbols except for these should be made local
33281ad6265SDimitry Andric     //
33381ad6265SDimitry Andric     // If --globalize-symbol is specified for a given symbol, it will be
33481ad6265SDimitry Andric     // global in the output file even if it is not included via
33581ad6265SDimitry Andric     // --keep-global-symbol. Because of that, make sure to check
33681ad6265SDimitry Andric     // --globalize-symbol second.
33781ad6265SDimitry Andric     if (!Config.SymbolsToKeepGlobal.empty() &&
33881ad6265SDimitry Andric         !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
33981ad6265SDimitry Andric         Sym.getShndx() != SHN_UNDEF)
34081ad6265SDimitry Andric       Sym.Binding = STB_LOCAL;
34181ad6265SDimitry Andric 
34281ad6265SDimitry Andric     if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
34381ad6265SDimitry Andric         Sym.getShndx() != SHN_UNDEF)
34481ad6265SDimitry Andric       Sym.Binding = STB_GLOBAL;
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric     // SymbolsToWeaken applies to both STB_GLOBAL and STB_GNU_UNIQUE.
34781ad6265SDimitry Andric     if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding != STB_LOCAL)
34881ad6265SDimitry Andric       Sym.Binding = STB_WEAK;
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric     if (Config.Weaken && Sym.Binding != STB_LOCAL &&
35181ad6265SDimitry Andric         Sym.getShndx() != SHN_UNDEF)
35281ad6265SDimitry Andric       Sym.Binding = STB_WEAK;
35381ad6265SDimitry Andric 
35481ad6265SDimitry Andric     const auto I = Config.SymbolsToRename.find(Sym.Name);
35581ad6265SDimitry Andric     if (I != Config.SymbolsToRename.end())
35681ad6265SDimitry Andric       Sym.Name = std::string(I->getValue());
35781ad6265SDimitry Andric 
358*0fca6ea1SDimitry Andric     if (!Config.SymbolsPrefixRemove.empty() && Sym.Type != STT_SECTION)
359*0fca6ea1SDimitry Andric       if (Sym.Name.compare(0, Config.SymbolsPrefixRemove.size(),
360*0fca6ea1SDimitry Andric                            Config.SymbolsPrefixRemove) == 0)
361*0fca6ea1SDimitry Andric         Sym.Name = Sym.Name.substr(Config.SymbolsPrefixRemove.size());
362*0fca6ea1SDimitry Andric 
36381ad6265SDimitry Andric     if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
36481ad6265SDimitry Andric       Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
36581ad6265SDimitry Andric   });
36681ad6265SDimitry Andric 
36781ad6265SDimitry Andric   // The purpose of this loop is to mark symbols referenced by sections
36881ad6265SDimitry Andric   // (like GroupSection or RelocationSection). This way, we know which
36981ad6265SDimitry Andric   // symbols are still 'needed' and which are not.
37081ad6265SDimitry Andric   if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
37181ad6265SDimitry Andric       !Config.OnlySection.empty()) {
37281ad6265SDimitry Andric     for (SectionBase &Sec : Obj.sections())
37381ad6265SDimitry Andric       Sec.markSymbols();
37481ad6265SDimitry Andric   }
37581ad6265SDimitry Andric 
37681ad6265SDimitry Andric   auto RemoveSymbolsPred = [&](const Symbol &Sym) {
37781ad6265SDimitry Andric     if (Config.SymbolsToKeep.matches(Sym.Name) ||
37881ad6265SDimitry Andric         (ELFConfig.KeepFileSymbols && Sym.Type == STT_FILE))
37981ad6265SDimitry Andric       return false;
38081ad6265SDimitry Andric 
38181ad6265SDimitry Andric     if (Config.SymbolsToRemove.matches(Sym.Name))
38281ad6265SDimitry Andric       return true;
38381ad6265SDimitry Andric 
38481ad6265SDimitry Andric     if (Config.StripAll || Config.StripAllGNU)
38581ad6265SDimitry Andric       return true;
38681ad6265SDimitry Andric 
38781ad6265SDimitry Andric     if (isRequiredByABISymbol(Obj, Sym))
38881ad6265SDimitry Andric       return false;
38981ad6265SDimitry Andric 
39081ad6265SDimitry Andric     if (Config.StripDebug && Sym.Type == STT_FILE)
39181ad6265SDimitry Andric       return true;
39281ad6265SDimitry Andric 
39381ad6265SDimitry Andric     if ((Config.DiscardMode == DiscardType::All ||
39481ad6265SDimitry Andric          (Config.DiscardMode == DiscardType::Locals &&
3955f757f3fSDimitry Andric           StringRef(Sym.Name).starts_with(".L"))) &&
39681ad6265SDimitry Andric         Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
39781ad6265SDimitry Andric         Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
39881ad6265SDimitry Andric       return true;
39981ad6265SDimitry Andric 
40081ad6265SDimitry Andric     if ((Config.StripUnneeded ||
40181ad6265SDimitry Andric          Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
40281ad6265SDimitry Andric         (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
40381ad6265SDimitry Andric       return true;
40481ad6265SDimitry Andric 
40581ad6265SDimitry Andric     // We want to remove undefined symbols if all references have been stripped.
40681ad6265SDimitry Andric     if (!Config.OnlySection.empty() && !Sym.Referenced &&
40781ad6265SDimitry Andric         Sym.getShndx() == SHN_UNDEF)
40881ad6265SDimitry Andric       return true;
40981ad6265SDimitry Andric 
41081ad6265SDimitry Andric     return false;
41181ad6265SDimitry Andric   };
41281ad6265SDimitry Andric 
41381ad6265SDimitry Andric   return Obj.removeSymbols(RemoveSymbolsPred);
41481ad6265SDimitry Andric }
41581ad6265SDimitry Andric 
41681ad6265SDimitry Andric static Error replaceAndRemoveSections(const CommonConfig &Config,
41781ad6265SDimitry Andric                                       const ELFConfig &ELFConfig, Object &Obj) {
41881ad6265SDimitry Andric   SectionPred RemovePred = [](const SectionBase &) { return false; };
41981ad6265SDimitry Andric 
42081ad6265SDimitry Andric   // Removes:
42181ad6265SDimitry Andric   if (!Config.ToRemove.empty()) {
42281ad6265SDimitry Andric     RemovePred = [&Config](const SectionBase &Sec) {
42381ad6265SDimitry Andric       return Config.ToRemove.matches(Sec.Name);
42481ad6265SDimitry Andric     };
42581ad6265SDimitry Andric   }
42681ad6265SDimitry Andric 
42781ad6265SDimitry Andric   if (Config.StripDWO)
42881ad6265SDimitry Andric     RemovePred = [RemovePred](const SectionBase &Sec) {
42981ad6265SDimitry Andric       return isDWOSection(Sec) || RemovePred(Sec);
43081ad6265SDimitry Andric     };
43181ad6265SDimitry Andric 
43281ad6265SDimitry Andric   if (Config.ExtractDWO)
43381ad6265SDimitry Andric     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
43481ad6265SDimitry Andric       return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
43581ad6265SDimitry Andric     };
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric   if (Config.StripAllGNU)
43881ad6265SDimitry Andric     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
43981ad6265SDimitry Andric       if (RemovePred(Sec))
44081ad6265SDimitry Andric         return true;
44181ad6265SDimitry Andric       if ((Sec.Flags & SHF_ALLOC) != 0)
44281ad6265SDimitry Andric         return false;
44381ad6265SDimitry Andric       if (&Sec == Obj.SectionNames)
44481ad6265SDimitry Andric         return false;
44581ad6265SDimitry Andric       switch (Sec.Type) {
44681ad6265SDimitry Andric       case SHT_SYMTAB:
44781ad6265SDimitry Andric       case SHT_REL:
44881ad6265SDimitry Andric       case SHT_RELA:
44981ad6265SDimitry Andric       case SHT_STRTAB:
45081ad6265SDimitry Andric         return true;
45181ad6265SDimitry Andric       }
45281ad6265SDimitry Andric       return isDebugSection(Sec);
45381ad6265SDimitry Andric     };
45481ad6265SDimitry Andric 
45581ad6265SDimitry Andric   if (Config.StripSections) {
45681ad6265SDimitry Andric     RemovePred = [RemovePred](const SectionBase &Sec) {
45781ad6265SDimitry Andric       return RemovePred(Sec) || Sec.ParentSegment == nullptr;
45881ad6265SDimitry Andric     };
45981ad6265SDimitry Andric   }
46081ad6265SDimitry Andric 
46181ad6265SDimitry Andric   if (Config.StripDebug || Config.StripUnneeded) {
46281ad6265SDimitry Andric     RemovePred = [RemovePred](const SectionBase &Sec) {
46381ad6265SDimitry Andric       return RemovePred(Sec) || isDebugSection(Sec);
46481ad6265SDimitry Andric     };
46581ad6265SDimitry Andric   }
46681ad6265SDimitry Andric 
46781ad6265SDimitry Andric   if (Config.StripNonAlloc)
46881ad6265SDimitry Andric     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
46981ad6265SDimitry Andric       if (RemovePred(Sec))
47081ad6265SDimitry Andric         return true;
47181ad6265SDimitry Andric       if (&Sec == Obj.SectionNames)
47281ad6265SDimitry Andric         return false;
47381ad6265SDimitry Andric       return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
47481ad6265SDimitry Andric     };
47581ad6265SDimitry Andric 
47681ad6265SDimitry Andric   if (Config.StripAll)
47781ad6265SDimitry Andric     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
47881ad6265SDimitry Andric       if (RemovePred(Sec))
47981ad6265SDimitry Andric         return true;
48081ad6265SDimitry Andric       if (&Sec == Obj.SectionNames)
48181ad6265SDimitry Andric         return false;
4825f757f3fSDimitry Andric       if (StringRef(Sec.Name).starts_with(".gnu.warning"))
48381ad6265SDimitry Andric         return false;
484*0fca6ea1SDimitry Andric       if (StringRef(Sec.Name).starts_with(".gnu_debuglink"))
485*0fca6ea1SDimitry Andric         return false;
48681ad6265SDimitry Andric       // We keep the .ARM.attribute section to maintain compatibility
48781ad6265SDimitry Andric       // with Debian derived distributions. This is a bug in their
48881ad6265SDimitry Andric       // patchset as documented here:
48981ad6265SDimitry Andric       // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
49081ad6265SDimitry Andric       if (Sec.Type == SHT_ARM_ATTRIBUTES)
49181ad6265SDimitry Andric         return false;
49281ad6265SDimitry Andric       if (Sec.ParentSegment != nullptr)
49381ad6265SDimitry Andric         return false;
49481ad6265SDimitry Andric       return (Sec.Flags & SHF_ALLOC) == 0;
49581ad6265SDimitry Andric     };
49681ad6265SDimitry Andric 
49781ad6265SDimitry Andric   if (Config.ExtractPartition || Config.ExtractMainPartition) {
49881ad6265SDimitry Andric     RemovePred = [RemovePred](const SectionBase &Sec) {
49981ad6265SDimitry Andric       if (RemovePred(Sec))
50081ad6265SDimitry Andric         return true;
50181ad6265SDimitry Andric       if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
50281ad6265SDimitry Andric         return true;
50381ad6265SDimitry Andric       return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
50481ad6265SDimitry Andric     };
50581ad6265SDimitry Andric   }
50681ad6265SDimitry Andric 
50781ad6265SDimitry Andric   // Explicit copies:
50881ad6265SDimitry Andric   if (!Config.OnlySection.empty()) {
50981ad6265SDimitry Andric     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
51081ad6265SDimitry Andric       // Explicitly keep these sections regardless of previous removes.
51181ad6265SDimitry Andric       if (Config.OnlySection.matches(Sec.Name))
51281ad6265SDimitry Andric         return false;
51381ad6265SDimitry Andric 
51481ad6265SDimitry Andric       // Allow all implicit removes.
51581ad6265SDimitry Andric       if (RemovePred(Sec))
51681ad6265SDimitry Andric         return true;
51781ad6265SDimitry Andric 
51881ad6265SDimitry Andric       // Keep special sections.
51981ad6265SDimitry Andric       if (Obj.SectionNames == &Sec)
52081ad6265SDimitry Andric         return false;
52181ad6265SDimitry Andric       if (Obj.SymbolTable == &Sec ||
52281ad6265SDimitry Andric           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
52381ad6265SDimitry Andric         return false;
52481ad6265SDimitry Andric 
52581ad6265SDimitry Andric       // Remove everything else.
52681ad6265SDimitry Andric       return true;
52781ad6265SDimitry Andric     };
52881ad6265SDimitry Andric   }
52981ad6265SDimitry Andric 
53081ad6265SDimitry Andric   if (!Config.KeepSection.empty()) {
53181ad6265SDimitry Andric     RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
53281ad6265SDimitry Andric       // Explicitly keep these sections regardless of previous removes.
53381ad6265SDimitry Andric       if (Config.KeepSection.matches(Sec.Name))
53481ad6265SDimitry Andric         return false;
53581ad6265SDimitry Andric       // Otherwise defer to RemovePred.
53681ad6265SDimitry Andric       return RemovePred(Sec);
53781ad6265SDimitry Andric     };
53881ad6265SDimitry Andric   }
53981ad6265SDimitry Andric 
54081ad6265SDimitry Andric   // This has to be the last predicate assignment.
54181ad6265SDimitry Andric   // If the option --keep-symbol has been specified
54281ad6265SDimitry Andric   // and at least one of those symbols is present
54381ad6265SDimitry Andric   // (equivalently, the updated symbol table is not empty)
54481ad6265SDimitry Andric   // the symbol table and the string table should not be removed.
54581ad6265SDimitry Andric   if ((!Config.SymbolsToKeep.empty() || ELFConfig.KeepFileSymbols) &&
54681ad6265SDimitry Andric       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
54781ad6265SDimitry Andric     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
54881ad6265SDimitry Andric       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
54981ad6265SDimitry Andric         return false;
55081ad6265SDimitry Andric       return RemovePred(Sec);
55181ad6265SDimitry Andric     };
55281ad6265SDimitry Andric   }
55381ad6265SDimitry Andric 
55481ad6265SDimitry Andric   if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))
55581ad6265SDimitry Andric     return E;
55681ad6265SDimitry Andric 
557*0fca6ea1SDimitry Andric   if (Error E = Obj.compressOrDecompressSections(Config))
558*0fca6ea1SDimitry Andric     return E;
55981ad6265SDimitry Andric 
56081ad6265SDimitry Andric   return Error::success();
56181ad6265SDimitry Andric }
56281ad6265SDimitry Andric 
56381ad6265SDimitry Andric // Add symbol to the Object symbol table with the specified properties.
56481ad6265SDimitry Andric static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
56581ad6265SDimitry Andric                       uint8_t DefaultVisibility) {
56681ad6265SDimitry Andric   SectionBase *Sec = Obj.findSection(SymInfo.SectionName);
56781ad6265SDimitry Andric   uint64_t Value = Sec ? Sec->Addr + SymInfo.Value : SymInfo.Value;
56881ad6265SDimitry Andric 
56981ad6265SDimitry Andric   uint8_t Bind = ELF::STB_GLOBAL;
57081ad6265SDimitry Andric   uint8_t Type = ELF::STT_NOTYPE;
57181ad6265SDimitry Andric   uint8_t Visibility = DefaultVisibility;
57281ad6265SDimitry Andric 
57381ad6265SDimitry Andric   for (SymbolFlag FlagValue : SymInfo.Flags)
57481ad6265SDimitry Andric     switch (FlagValue) {
57581ad6265SDimitry Andric     case SymbolFlag::Global:
57681ad6265SDimitry Andric       Bind = ELF::STB_GLOBAL;
57781ad6265SDimitry Andric       break;
57881ad6265SDimitry Andric     case SymbolFlag::Local:
57981ad6265SDimitry Andric       Bind = ELF::STB_LOCAL;
58081ad6265SDimitry Andric       break;
58181ad6265SDimitry Andric     case SymbolFlag::Weak:
58281ad6265SDimitry Andric       Bind = ELF::STB_WEAK;
58381ad6265SDimitry Andric       break;
58481ad6265SDimitry Andric     case SymbolFlag::Default:
58581ad6265SDimitry Andric       Visibility = ELF::STV_DEFAULT;
58681ad6265SDimitry Andric       break;
58781ad6265SDimitry Andric     case SymbolFlag::Hidden:
58881ad6265SDimitry Andric       Visibility = ELF::STV_HIDDEN;
58981ad6265SDimitry Andric       break;
59081ad6265SDimitry Andric     case SymbolFlag::Protected:
59181ad6265SDimitry Andric       Visibility = ELF::STV_PROTECTED;
59281ad6265SDimitry Andric       break;
59381ad6265SDimitry Andric     case SymbolFlag::File:
59481ad6265SDimitry Andric       Type = ELF::STT_FILE;
59581ad6265SDimitry Andric       break;
59681ad6265SDimitry Andric     case SymbolFlag::Section:
59781ad6265SDimitry Andric       Type = ELF::STT_SECTION;
59881ad6265SDimitry Andric       break;
59981ad6265SDimitry Andric     case SymbolFlag::Object:
60081ad6265SDimitry Andric       Type = ELF::STT_OBJECT;
60181ad6265SDimitry Andric       break;
60281ad6265SDimitry Andric     case SymbolFlag::Function:
60381ad6265SDimitry Andric       Type = ELF::STT_FUNC;
60481ad6265SDimitry Andric       break;
60581ad6265SDimitry Andric     case SymbolFlag::IndirectFunction:
60681ad6265SDimitry Andric       Type = ELF::STT_GNU_IFUNC;
60781ad6265SDimitry Andric       break;
60881ad6265SDimitry Andric     default: /* Other flag values are ignored for ELF. */
60981ad6265SDimitry Andric       break;
61081ad6265SDimitry Andric     };
61181ad6265SDimitry Andric 
61281ad6265SDimitry Andric   Obj.SymbolTable->addSymbol(
61381ad6265SDimitry Andric       SymInfo.SymbolName, Bind, Type, Sec, Value, Visibility,
61481ad6265SDimitry Andric       Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
61581ad6265SDimitry Andric }
61681ad6265SDimitry Andric 
61781ad6265SDimitry Andric static Error
61881ad6265SDimitry Andric handleUserSection(const NewSectionInfo &NewSection,
61981ad6265SDimitry Andric                   function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
62081ad6265SDimitry Andric   ArrayRef<uint8_t> Data(reinterpret_cast<const uint8_t *>(
62181ad6265SDimitry Andric                              NewSection.SectionData->getBufferStart()),
62281ad6265SDimitry Andric                          NewSection.SectionData->getBufferSize());
62381ad6265SDimitry Andric   return F(NewSection.SectionName, Data);
62481ad6265SDimitry Andric }
62581ad6265SDimitry Andric 
626*0fca6ea1SDimitry Andric static Error verifyNoteSection(StringRef Name, endianness Endianness,
627*0fca6ea1SDimitry Andric                                ArrayRef<uint8_t> Data) {
628*0fca6ea1SDimitry Andric   // An ELF note has the following structure:
629*0fca6ea1SDimitry Andric   // Name Size: 4 bytes (integer)
630*0fca6ea1SDimitry Andric   // Desc Size: 4 bytes (integer)
631*0fca6ea1SDimitry Andric   // Type     : 4 bytes
632*0fca6ea1SDimitry Andric   // Name     : variable size, padded to a 4 byte boundary
633*0fca6ea1SDimitry Andric   // Desc     : variable size, padded to a 4 byte boundary
634*0fca6ea1SDimitry Andric 
635*0fca6ea1SDimitry Andric   if (Data.empty())
636*0fca6ea1SDimitry Andric     return Error::success();
637*0fca6ea1SDimitry Andric 
638*0fca6ea1SDimitry Andric   if (Data.size() < 12) {
639*0fca6ea1SDimitry Andric     std::string msg;
640*0fca6ea1SDimitry Andric     raw_string_ostream(msg)
641*0fca6ea1SDimitry Andric         << Name << " data must be either empty or at least 12 bytes long";
642*0fca6ea1SDimitry Andric     return createStringError(errc::invalid_argument, msg);
643*0fca6ea1SDimitry Andric   }
644*0fca6ea1SDimitry Andric   if (Data.size() % 4 != 0) {
645*0fca6ea1SDimitry Andric     std::string msg;
646*0fca6ea1SDimitry Andric     raw_string_ostream(msg)
647*0fca6ea1SDimitry Andric         << Name << " data size must be a  multiple of 4 bytes";
648*0fca6ea1SDimitry Andric     return createStringError(errc::invalid_argument, msg);
649*0fca6ea1SDimitry Andric   }
650*0fca6ea1SDimitry Andric   ArrayRef<uint8_t> NameSize = Data.slice(0, 4);
651*0fca6ea1SDimitry Andric   ArrayRef<uint8_t> DescSize = Data.slice(4, 4);
652*0fca6ea1SDimitry Andric 
653*0fca6ea1SDimitry Andric   uint32_t NameSizeValue = support::endian::read32(NameSize.data(), Endianness);
654*0fca6ea1SDimitry Andric   uint32_t DescSizeValue = support::endian::read32(DescSize.data(), Endianness);
655*0fca6ea1SDimitry Andric 
656*0fca6ea1SDimitry Andric   uint64_t ExpectedDataSize =
657*0fca6ea1SDimitry Andric       /*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 +
658*0fca6ea1SDimitry Andric       /*Name=*/alignTo(NameSizeValue, 4) +
659*0fca6ea1SDimitry Andric       /*Desc=*/alignTo(DescSizeValue, 4);
660*0fca6ea1SDimitry Andric   uint64_t ActualDataSize = Data.size();
661*0fca6ea1SDimitry Andric   if (ActualDataSize != ExpectedDataSize) {
662*0fca6ea1SDimitry Andric     std::string msg;
663*0fca6ea1SDimitry Andric     raw_string_ostream(msg)
664*0fca6ea1SDimitry Andric         << Name
665*0fca6ea1SDimitry Andric         << " data size is incompatible with the content of "
666*0fca6ea1SDimitry Andric            "the name and description size fields:"
667*0fca6ea1SDimitry Andric         << " expecting " << ExpectedDataSize << ", found " << ActualDataSize;
668*0fca6ea1SDimitry Andric     return createStringError(errc::invalid_argument, msg);
669*0fca6ea1SDimitry Andric   }
670*0fca6ea1SDimitry Andric 
671*0fca6ea1SDimitry Andric   return Error::success();
672*0fca6ea1SDimitry Andric }
673*0fca6ea1SDimitry Andric 
67481ad6265SDimitry Andric // This function handles the high level operations of GNU objcopy including
67581ad6265SDimitry Andric // handling command line options. It's important to outline certain properties
67681ad6265SDimitry Andric // we expect to hold of the command line operations. Any operation that "keeps"
67781ad6265SDimitry Andric // should keep regardless of a remove. Additionally any removal should respect
67881ad6265SDimitry Andric // any previous removals. Lastly whether or not something is removed shouldn't
67981ad6265SDimitry Andric // depend a) on the order the options occur in or b) on some opaque priority
68081ad6265SDimitry Andric // system. The only priority is that keeps/copies overrule removes.
68181ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
682*0fca6ea1SDimitry Andric                         ElfType OutputElfType, Object &Obj) {
68381ad6265SDimitry Andric   if (Config.OutputArch) {
684bdd1243dSDimitry Andric     Obj.Machine = Config.OutputArch->EMachine;
685bdd1243dSDimitry Andric     Obj.OSABI = Config.OutputArch->OSABI;
68681ad6265SDimitry Andric   }
68781ad6265SDimitry Andric 
68881ad6265SDimitry Andric   if (!Config.SplitDWO.empty() && Config.ExtractDWO) {
68981ad6265SDimitry Andric     return Obj.removeSections(
69081ad6265SDimitry Andric         ELFConfig.AllowBrokenLinks,
69181ad6265SDimitry Andric         [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); });
69281ad6265SDimitry Andric   }
69381ad6265SDimitry Andric 
69481ad6265SDimitry Andric   // Dump sections before add/remove for compatibility with GNU objcopy.
69581ad6265SDimitry Andric   for (StringRef Flag : Config.DumpSection) {
69681ad6265SDimitry Andric     StringRef SectionName;
69781ad6265SDimitry Andric     StringRef FileName;
69881ad6265SDimitry Andric     std::tie(SectionName, FileName) = Flag.split('=');
69981ad6265SDimitry Andric     if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
70081ad6265SDimitry Andric       return E;
70181ad6265SDimitry Andric   }
70281ad6265SDimitry Andric 
70381ad6265SDimitry Andric   // It is important to remove the sections first. For example, we want to
70481ad6265SDimitry Andric   // remove the relocation sections before removing the symbols. That allows
70581ad6265SDimitry Andric   // us to avoid reporting the inappropriate errors about removing symbols
70681ad6265SDimitry Andric   // named in relocations.
70781ad6265SDimitry Andric   if (Error E = replaceAndRemoveSections(Config, ELFConfig, Obj))
70881ad6265SDimitry Andric     return E;
70981ad6265SDimitry Andric 
71081ad6265SDimitry Andric   if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj))
71181ad6265SDimitry Andric     return E;
71281ad6265SDimitry Andric 
713753f127fSDimitry Andric   if (!Config.SetSectionAlignment.empty()) {
714753f127fSDimitry Andric     for (SectionBase &Sec : Obj.sections()) {
715753f127fSDimitry Andric       auto I = Config.SetSectionAlignment.find(Sec.Name);
716753f127fSDimitry Andric       if (I != Config.SetSectionAlignment.end())
717753f127fSDimitry Andric         Sec.Align = I->second;
718753f127fSDimitry Andric     }
719753f127fSDimitry Andric   }
720753f127fSDimitry Andric 
721*0fca6ea1SDimitry Andric   if (Config.ChangeSectionLMAValAll != 0) {
722*0fca6ea1SDimitry Andric     for (Segment &Seg : Obj.segments()) {
723*0fca6ea1SDimitry Andric       if (Seg.FileSize > 0) {
724*0fca6ea1SDimitry Andric         if (Config.ChangeSectionLMAValAll > 0 &&
725*0fca6ea1SDimitry Andric             Seg.PAddr > std::numeric_limits<uint64_t>::max() -
726*0fca6ea1SDimitry Andric                             Config.ChangeSectionLMAValAll) {
727*0fca6ea1SDimitry Andric           return createStringError(
728*0fca6ea1SDimitry Andric               errc::invalid_argument,
729*0fca6ea1SDimitry Andric               "address 0x" + Twine::utohexstr(Seg.PAddr) +
730*0fca6ea1SDimitry Andric                   " cannot be increased by 0x" +
731*0fca6ea1SDimitry Andric                   Twine::utohexstr(Config.ChangeSectionLMAValAll) +
732*0fca6ea1SDimitry Andric                   ". The result would overflow");
733*0fca6ea1SDimitry Andric         } else if (Config.ChangeSectionLMAValAll < 0 &&
734*0fca6ea1SDimitry Andric                    Seg.PAddr < std::numeric_limits<uint64_t>::min() -
735*0fca6ea1SDimitry Andric                                    Config.ChangeSectionLMAValAll) {
736*0fca6ea1SDimitry Andric           return createStringError(
737*0fca6ea1SDimitry Andric               errc::invalid_argument,
738*0fca6ea1SDimitry Andric               "address 0x" + Twine::utohexstr(Seg.PAddr) +
739*0fca6ea1SDimitry Andric                   " cannot be decreased by 0x" +
740*0fca6ea1SDimitry Andric                   Twine::utohexstr(std::abs(Config.ChangeSectionLMAValAll)) +
741*0fca6ea1SDimitry Andric                   ". The result would underflow");
742*0fca6ea1SDimitry Andric         }
743*0fca6ea1SDimitry Andric         Seg.PAddr += Config.ChangeSectionLMAValAll;
744*0fca6ea1SDimitry Andric       }
745*0fca6ea1SDimitry Andric     }
746*0fca6ea1SDimitry Andric   }
747*0fca6ea1SDimitry Andric 
748753f127fSDimitry Andric   if (Config.OnlyKeepDebug)
749753f127fSDimitry Andric     for (auto &Sec : Obj.sections())
750753f127fSDimitry Andric       if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
751753f127fSDimitry Andric         Sec.Type = SHT_NOBITS;
752753f127fSDimitry Andric 
753*0fca6ea1SDimitry Andric   endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE
754*0fca6ea1SDimitry Andric                      ? endianness::little
755*0fca6ea1SDimitry Andric                      : endianness::big;
756*0fca6ea1SDimitry Andric 
757753f127fSDimitry Andric   for (const NewSectionInfo &AddedSection : Config.AddSection) {
758*0fca6ea1SDimitry Andric     auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {
759753f127fSDimitry Andric       OwnedDataSection &NewSection =
760753f127fSDimitry Andric           Obj.addSection<OwnedDataSection>(Name, Data);
761*0fca6ea1SDimitry Andric       if (Name.starts_with(".note") && Name != ".note.GNU-stack") {
762753f127fSDimitry Andric         NewSection.Type = SHT_NOTE;
763*0fca6ea1SDimitry Andric         if (ELFConfig.VerifyNoteSections)
764*0fca6ea1SDimitry Andric           return verifyNoteSection(Name, E, Data);
765*0fca6ea1SDimitry Andric       }
766753f127fSDimitry Andric       return Error::success();
767753f127fSDimitry Andric     };
768753f127fSDimitry Andric     if (Error E = handleUserSection(AddedSection, AddSection))
769753f127fSDimitry Andric       return E;
770753f127fSDimitry Andric   }
771753f127fSDimitry Andric 
772753f127fSDimitry Andric   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
773753f127fSDimitry Andric     auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
774753f127fSDimitry Andric       return Obj.updateSection(Name, Data);
775753f127fSDimitry Andric     };
776753f127fSDimitry Andric     if (Error E = handleUserSection(NewSection, UpdateSection))
777753f127fSDimitry Andric       return E;
778753f127fSDimitry Andric   }
779753f127fSDimitry Andric 
780753f127fSDimitry Andric   if (!Config.AddGnuDebugLink.empty())
781753f127fSDimitry Andric     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
782753f127fSDimitry Andric                                         Config.GnuDebugLinkCRC32);
783753f127fSDimitry Andric 
784753f127fSDimitry Andric   // If the symbol table was previously removed, we need to create a new one
785753f127fSDimitry Andric   // before adding new symbols.
786753f127fSDimitry Andric   if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty())
787753f127fSDimitry Andric     if (Error E = Obj.addNewSymbolTable())
788753f127fSDimitry Andric       return E;
789753f127fSDimitry Andric 
790753f127fSDimitry Andric   for (const NewSymbolInfo &SI : Config.SymbolsToAdd)
791753f127fSDimitry Andric     addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);
792753f127fSDimitry Andric 
793753f127fSDimitry Andric   // --set-section-{flags,type} work with sections added by --add-section.
794753f127fSDimitry Andric   if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {
795753f127fSDimitry Andric     for (auto &Sec : Obj.sections()) {
796753f127fSDimitry Andric       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
797753f127fSDimitry Andric       if (Iter != Config.SetSectionFlags.end()) {
798753f127fSDimitry Andric         const SectionFlagsUpdate &SFU = Iter->second;
7995f757f3fSDimitry Andric         if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))
8005f757f3fSDimitry Andric           return E;
801753f127fSDimitry Andric       }
802753f127fSDimitry Andric       auto It2 = Config.SetSectionType.find(Sec.Name);
803753f127fSDimitry Andric       if (It2 != Config.SetSectionType.end())
80406c3fb27SDimitry Andric         setSectionType(Sec, It2->second);
805753f127fSDimitry Andric     }
806753f127fSDimitry Andric   }
807753f127fSDimitry Andric 
80881ad6265SDimitry Andric   if (!Config.SectionsToRename.empty()) {
80981ad6265SDimitry Andric     std::vector<RelocationSectionBase *> RelocSections;
81081ad6265SDimitry Andric     DenseSet<SectionBase *> RenamedSections;
81181ad6265SDimitry Andric     for (SectionBase &Sec : Obj.sections()) {
81281ad6265SDimitry Andric       auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec);
81381ad6265SDimitry Andric       const auto Iter = Config.SectionsToRename.find(Sec.Name);
81481ad6265SDimitry Andric       if (Iter != Config.SectionsToRename.end()) {
81581ad6265SDimitry Andric         const SectionRename &SR = Iter->second;
81681ad6265SDimitry Andric         Sec.Name = std::string(SR.NewName);
8175f757f3fSDimitry Andric         if (SR.NewFlags) {
8185f757f3fSDimitry Andric           if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))
8195f757f3fSDimitry Andric             return E;
8205f757f3fSDimitry Andric         }
82181ad6265SDimitry Andric         RenamedSections.insert(&Sec);
82281ad6265SDimitry Andric       } else if (RelocSec && !(Sec.Flags & SHF_ALLOC))
82381ad6265SDimitry Andric         // Postpone processing relocation sections which are not specified in
82481ad6265SDimitry Andric         // their explicit '--rename-section' commands until after their target
82581ad6265SDimitry Andric         // sections are renamed.
82681ad6265SDimitry Andric         // Dynamic relocation sections (i.e. ones with SHF_ALLOC) should be
82781ad6265SDimitry Andric         // renamed only explicitly. Otherwise, renaming, for example, '.got.plt'
82881ad6265SDimitry Andric         // would affect '.rela.plt', which is not desirable.
82981ad6265SDimitry Andric         RelocSections.push_back(RelocSec);
83081ad6265SDimitry Andric     }
83181ad6265SDimitry Andric 
83281ad6265SDimitry Andric     // Rename relocation sections according to their target sections.
83381ad6265SDimitry Andric     for (RelocationSectionBase *RelocSec : RelocSections) {
83481ad6265SDimitry Andric       auto Iter = RenamedSections.find(RelocSec->getSection());
83581ad6265SDimitry Andric       if (Iter != RenamedSections.end())
83681ad6265SDimitry Andric         RelocSec->Name = (RelocSec->getNamePrefix() + (*Iter)->Name).str();
83781ad6265SDimitry Andric     }
83881ad6265SDimitry Andric   }
83981ad6265SDimitry Andric 
84081ad6265SDimitry Andric   // Add a prefix to allocated sections and their relocation sections. This
84181ad6265SDimitry Andric   // should be done after renaming the section by Config.SectionToRename to
84281ad6265SDimitry Andric   // imitate the GNU objcopy behavior.
84381ad6265SDimitry Andric   if (!Config.AllocSectionsPrefix.empty()) {
84481ad6265SDimitry Andric     DenseSet<SectionBase *> PrefixedSections;
84581ad6265SDimitry Andric     for (SectionBase &Sec : Obj.sections()) {
84681ad6265SDimitry Andric       if (Sec.Flags & SHF_ALLOC) {
84781ad6265SDimitry Andric         Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
84881ad6265SDimitry Andric         PrefixedSections.insert(&Sec);
84981ad6265SDimitry Andric       } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
85081ad6265SDimitry Andric         // Rename relocation sections associated to the allocated sections.
85181ad6265SDimitry Andric         // For example, if we rename .text to .prefix.text, we also rename
85281ad6265SDimitry Andric         // .rel.text to .rel.prefix.text.
85381ad6265SDimitry Andric         //
85481ad6265SDimitry Andric         // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
85581ad6265SDimitry Andric         // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
85681ad6265SDimitry Andric         // .rela.prefix.plt since GNU objcopy does so.
85781ad6265SDimitry Andric         const SectionBase *TargetSec = RelocSec->getSection();
85881ad6265SDimitry Andric         if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
85981ad6265SDimitry Andric           // If the relocation section comes *after* the target section, we
86081ad6265SDimitry Andric           // don't add Config.AllocSectionsPrefix because we've already added
86181ad6265SDimitry Andric           // the prefix to TargetSec->Name. Otherwise, if the relocation
86281ad6265SDimitry Andric           // section comes *before* the target section, we add the prefix.
86381ad6265SDimitry Andric           if (PrefixedSections.count(TargetSec))
86481ad6265SDimitry Andric             Sec.Name = (RelocSec->getNamePrefix() + TargetSec->Name).str();
86581ad6265SDimitry Andric           else
86681ad6265SDimitry Andric             Sec.Name = (RelocSec->getNamePrefix() + Config.AllocSectionsPrefix +
86781ad6265SDimitry Andric                         TargetSec->Name)
86881ad6265SDimitry Andric                            .str();
86981ad6265SDimitry Andric         }
87081ad6265SDimitry Andric       }
87181ad6265SDimitry Andric     }
87281ad6265SDimitry Andric   }
87381ad6265SDimitry Andric 
87481ad6265SDimitry Andric   if (ELFConfig.EntryExpr)
87581ad6265SDimitry Andric     Obj.Entry = ELFConfig.EntryExpr(Obj.Entry);
87681ad6265SDimitry Andric   return Error::success();
87781ad6265SDimitry Andric }
87881ad6265SDimitry Andric 
87981ad6265SDimitry Andric static Error writeOutput(const CommonConfig &Config, Object &Obj,
88081ad6265SDimitry Andric                          raw_ostream &Out, ElfType OutputElfType) {
88181ad6265SDimitry Andric   std::unique_ptr<Writer> Writer =
88281ad6265SDimitry Andric       createWriter(Config, Obj, Out, OutputElfType);
88381ad6265SDimitry Andric   if (Error E = Writer->finalize())
88481ad6265SDimitry Andric     return E;
88581ad6265SDimitry Andric   return Writer->write();
88681ad6265SDimitry Andric }
88781ad6265SDimitry Andric 
88881ad6265SDimitry Andric Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
88981ad6265SDimitry Andric                                          const ELFConfig &ELFConfig,
89081ad6265SDimitry Andric                                          MemoryBuffer &In, raw_ostream &Out) {
89181ad6265SDimitry Andric   IHexReader Reader(&In);
89281ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
89381ad6265SDimitry Andric   if (!Obj)
89481ad6265SDimitry Andric     return Obj.takeError();
89581ad6265SDimitry Andric 
89681ad6265SDimitry Andric   const ElfType OutputElfType =
89781ad6265SDimitry Andric       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
898*0fca6ea1SDimitry Andric   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
89981ad6265SDimitry Andric     return E;
90081ad6265SDimitry Andric   return writeOutput(Config, **Obj, Out, OutputElfType);
90181ad6265SDimitry Andric }
90281ad6265SDimitry Andric 
90381ad6265SDimitry Andric Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
90481ad6265SDimitry Andric                                               const ELFConfig &ELFConfig,
90581ad6265SDimitry Andric                                               MemoryBuffer &In,
90681ad6265SDimitry Andric                                               raw_ostream &Out) {
90781ad6265SDimitry Andric   BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);
90881ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
90981ad6265SDimitry Andric   if (!Obj)
91081ad6265SDimitry Andric     return Obj.takeError();
91181ad6265SDimitry Andric 
91281ad6265SDimitry Andric   // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
91381ad6265SDimitry Andric   // (-B<arch>).
91481ad6265SDimitry Andric   const ElfType OutputElfType =
91581ad6265SDimitry Andric       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
916*0fca6ea1SDimitry Andric   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
91781ad6265SDimitry Andric     return E;
91881ad6265SDimitry Andric   return writeOutput(Config, **Obj, Out, OutputElfType);
91981ad6265SDimitry Andric }
92081ad6265SDimitry Andric 
92181ad6265SDimitry Andric Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
92281ad6265SDimitry Andric                                            const ELFConfig &ELFConfig,
92381ad6265SDimitry Andric                                            object::ELFObjectFileBase &In,
92481ad6265SDimitry Andric                                            raw_ostream &Out) {
92581ad6265SDimitry Andric   ELFReader Reader(&In, Config.ExtractPartition);
92681ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> Obj =
92781ad6265SDimitry Andric       Reader.create(!Config.SymbolsToAdd.empty());
92881ad6265SDimitry Andric   if (!Obj)
92981ad6265SDimitry Andric     return Obj.takeError();
93081ad6265SDimitry Andric   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
931bdd1243dSDimitry Andric   const ElfType OutputElfType = Config.OutputArch
932bdd1243dSDimitry Andric                                     ? getOutputElfType(*Config.OutputArch)
93381ad6265SDimitry Andric                                     : getOutputElfType(In);
93481ad6265SDimitry Andric 
935*0fca6ea1SDimitry Andric   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
93681ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
93781ad6265SDimitry Andric 
93881ad6265SDimitry Andric   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
93981ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
94081ad6265SDimitry Andric 
94181ad6265SDimitry Andric   return Error::success();
94281ad6265SDimitry Andric }
943