xref: /llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (revision 10772807ab72ce2b68d76816f8753219b2acbac3)
1f75da0c8SAlexey Lapshin //===- ELFObjcopy.cpp -----------------------------------------------------===//
2f75da0c8SAlexey Lapshin //
3f75da0c8SAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f75da0c8SAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
5f75da0c8SAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f75da0c8SAlexey Lapshin //
7f75da0c8SAlexey Lapshin //===----------------------------------------------------------------------===//
8f75da0c8SAlexey Lapshin 
9f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/ELF/ELFObjcopy.h"
1025d7b4fbSAlexey Lapshin #include "ELFObject.h"
11f75da0c8SAlexey Lapshin #include "llvm/ADT/BitmaskEnum.h"
12f75da0c8SAlexey Lapshin #include "llvm/ADT/DenseSet.h"
13f75da0c8SAlexey Lapshin #include "llvm/ADT/SmallVector.h"
14f75da0c8SAlexey Lapshin #include "llvm/ADT/StringRef.h"
15f75da0c8SAlexey Lapshin #include "llvm/ADT/Twine.h"
16f75da0c8SAlexey Lapshin #include "llvm/BinaryFormat/ELF.h"
17f75da0c8SAlexey Lapshin #include "llvm/MC/MCTargetOptions.h"
18f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/CommonConfig.h"
19f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/ELF/ELFConfig.h"
20f75da0c8SAlexey Lapshin #include "llvm/Object/Binary.h"
21f75da0c8SAlexey Lapshin #include "llvm/Object/ELFObjectFile.h"
22f75da0c8SAlexey Lapshin #include "llvm/Object/ELFTypes.h"
23f75da0c8SAlexey Lapshin #include "llvm/Object/Error.h"
24f75da0c8SAlexey Lapshin #include "llvm/Option/Option.h"
25f75da0c8SAlexey Lapshin #include "llvm/Support/Casting.h"
26f75da0c8SAlexey Lapshin #include "llvm/Support/Compression.h"
27f75da0c8SAlexey Lapshin #include "llvm/Support/Errc.h"
28f75da0c8SAlexey Lapshin #include "llvm/Support/Error.h"
29f75da0c8SAlexey Lapshin #include "llvm/Support/ErrorHandling.h"
30f75da0c8SAlexey Lapshin #include "llvm/Support/Memory.h"
31f75da0c8SAlexey Lapshin #include "llvm/Support/raw_ostream.h"
32f75da0c8SAlexey Lapshin #include <algorithm>
33f75da0c8SAlexey Lapshin #include <cassert>
34f75da0c8SAlexey Lapshin #include <cstdlib>
35f75da0c8SAlexey Lapshin #include <functional>
36f75da0c8SAlexey Lapshin #include <memory>
37f75da0c8SAlexey Lapshin #include <string>
38f75da0c8SAlexey Lapshin #include <system_error>
39f75da0c8SAlexey Lapshin #include <utility>
40f75da0c8SAlexey Lapshin 
41f75da0c8SAlexey Lapshin using namespace llvm;
42f75da0c8SAlexey Lapshin using namespace llvm::ELF;
43f75da0c8SAlexey Lapshin using namespace llvm::objcopy;
44f75da0c8SAlexey Lapshin using namespace llvm::objcopy::elf;
45f75da0c8SAlexey Lapshin using namespace llvm::object;
46f75da0c8SAlexey Lapshin 
47f75da0c8SAlexey Lapshin using SectionPred = std::function<bool(const SectionBase &Sec)>;
48f75da0c8SAlexey Lapshin 
49f75da0c8SAlexey Lapshin static bool isDebugSection(const SectionBase &Sec) {
50586ecdf2SKazu Hirata   return StringRef(Sec.Name).starts_with(".debug") || Sec.Name == ".gdb_index";
51f75da0c8SAlexey Lapshin }
52f75da0c8SAlexey Lapshin 
53f75da0c8SAlexey Lapshin static bool isDWOSection(const SectionBase &Sec) {
54586ecdf2SKazu Hirata   return StringRef(Sec.Name).ends_with(".dwo");
55f75da0c8SAlexey Lapshin }
56f75da0c8SAlexey Lapshin 
57f75da0c8SAlexey Lapshin static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
58f75da0c8SAlexey Lapshin   // We can't remove the section header string table.
59f75da0c8SAlexey Lapshin   if (&Sec == Obj.SectionNames)
60f75da0c8SAlexey Lapshin     return false;
61f75da0c8SAlexey Lapshin   // Short of keeping the string table we want to keep everything that is a DWO
62f75da0c8SAlexey Lapshin   // section and remove everything else.
63f75da0c8SAlexey Lapshin   return !isDWOSection(Sec);
64f75da0c8SAlexey Lapshin }
65f75da0c8SAlexey Lapshin 
666f1395a1SThomas Köppe static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,
676f1395a1SThomas Köppe                                          uint16_t EMachine) {
68f75da0c8SAlexey Lapshin   uint64_t NewFlags = 0;
69f75da0c8SAlexey Lapshin   if (AllFlags & SectionFlag::SecAlloc)
70f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_ALLOC;
71f75da0c8SAlexey Lapshin   if (!(AllFlags & SectionFlag::SecReadonly))
72f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_WRITE;
73f75da0c8SAlexey Lapshin   if (AllFlags & SectionFlag::SecCode)
74f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_EXECINSTR;
75f75da0c8SAlexey Lapshin   if (AllFlags & SectionFlag::SecMerge)
76f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_MERGE;
77f75da0c8SAlexey Lapshin   if (AllFlags & SectionFlag::SecStrings)
78f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_STRINGS;
79f75da0c8SAlexey Lapshin   if (AllFlags & SectionFlag::SecExclude)
80f75da0c8SAlexey Lapshin     NewFlags |= ELF::SHF_EXCLUDE;
816f1395a1SThomas Köppe   if (AllFlags & SectionFlag::SecLarge) {
826f1395a1SThomas Köppe     if (EMachine != EM_X86_64)
836f1395a1SThomas Köppe       return createStringError(errc::invalid_argument,
846f1395a1SThomas Köppe                                "section flag SHF_X86_64_LARGE can only be used "
856f1395a1SThomas Köppe                                "with x86_64 architecture");
866f1395a1SThomas Köppe     NewFlags |= ELF::SHF_X86_64_LARGE;
876f1395a1SThomas Köppe   }
88f75da0c8SAlexey Lapshin   return NewFlags;
89f75da0c8SAlexey Lapshin }
90f75da0c8SAlexey Lapshin 
91f75da0c8SAlexey Lapshin static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
926f1395a1SThomas Köppe                                             uint64_t NewFlags,
936f1395a1SThomas Köppe                                             uint16_t EMachine) {
94f75da0c8SAlexey Lapshin   // Preserve some flags which should not be dropped when setting flags.
95f75da0c8SAlexey Lapshin   // Also, preserve anything OS/processor dependant.
96f75da0c8SAlexey Lapshin   const uint64_t PreserveMask =
97f75da0c8SAlexey Lapshin       (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
98f75da0c8SAlexey Lapshin        ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
99f75da0c8SAlexey Lapshin        ELF::SHF_INFO_LINK) &
1006f1395a1SThomas Köppe       ~ELF::SHF_EXCLUDE &
101336b7a25SMikael Holmen       ~(EMachine == EM_X86_64 ? (uint64_t)ELF::SHF_X86_64_LARGE : 0UL);
102f75da0c8SAlexey Lapshin   return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
103f75da0c8SAlexey Lapshin }
104f75da0c8SAlexey Lapshin 
105c973123fSAlexey Karyakin static void setSectionType(SectionBase &Sec, uint64_t Type) {
106c973123fSAlexey Karyakin   // If Sec's type is changed from SHT_NOBITS due to --set-section-flags,
107c973123fSAlexey Karyakin   // Offset may not be aligned. Align it to max(Align, 1).
108c973123fSAlexey Karyakin   if (Sec.Type == ELF::SHT_NOBITS && Type != ELF::SHT_NOBITS)
109c973123fSAlexey Karyakin     Sec.Offset = alignTo(Sec.Offset, std::max(Sec.Align, uint64_t(1)));
110c973123fSAlexey Karyakin   Sec.Type = Type;
111c973123fSAlexey Karyakin }
112c973123fSAlexey Karyakin 
1136f1395a1SThomas Köppe static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,
1146f1395a1SThomas Köppe                                     uint16_t EMachine) {
1156f1395a1SThomas Köppe   Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);
1166f1395a1SThomas Köppe   if (!NewFlags)
1176f1395a1SThomas Köppe     return NewFlags.takeError();
1186f1395a1SThomas Köppe   Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);
119f75da0c8SAlexey Lapshin 
120f75da0c8SAlexey Lapshin   // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
121f75da0c8SAlexey Lapshin   // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
122f75da0c8SAlexey Lapshin   // non-ALLOC SHT_NOBITS sections do not make much sense.
123f75da0c8SAlexey Lapshin   if (Sec.Type == SHT_NOBITS &&
124f75da0c8SAlexey Lapshin       (!(Sec.Flags & ELF::SHF_ALLOC) ||
125f75da0c8SAlexey Lapshin        Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
126c973123fSAlexey Karyakin     setSectionType(Sec, ELF::SHT_PROGBITS);
1276f1395a1SThomas Köppe 
1286f1395a1SThomas Köppe   return Error::success();
129f75da0c8SAlexey Lapshin }
130f75da0c8SAlexey Lapshin 
131f75da0c8SAlexey Lapshin static ElfType getOutputElfType(const Binary &Bin) {
132f75da0c8SAlexey Lapshin   // Infer output ELF type from the input ELF object
133f75da0c8SAlexey Lapshin   if (isa<ELFObjectFile<ELF32LE>>(Bin))
134f75da0c8SAlexey Lapshin     return ELFT_ELF32LE;
135f75da0c8SAlexey Lapshin   if (isa<ELFObjectFile<ELF64LE>>(Bin))
136f75da0c8SAlexey Lapshin     return ELFT_ELF64LE;
137f75da0c8SAlexey Lapshin   if (isa<ELFObjectFile<ELF32BE>>(Bin))
138f75da0c8SAlexey Lapshin     return ELFT_ELF32BE;
139f75da0c8SAlexey Lapshin   if (isa<ELFObjectFile<ELF64BE>>(Bin))
140f75da0c8SAlexey Lapshin     return ELFT_ELF64BE;
141f75da0c8SAlexey Lapshin   llvm_unreachable("Invalid ELFType");
142f75da0c8SAlexey Lapshin }
143f75da0c8SAlexey Lapshin 
144f75da0c8SAlexey Lapshin static ElfType getOutputElfType(const MachineInfo &MI) {
145f75da0c8SAlexey Lapshin   // Infer output ELF type from the binary arch specified
146f75da0c8SAlexey Lapshin   if (MI.Is64Bit)
147f75da0c8SAlexey Lapshin     return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
148f75da0c8SAlexey Lapshin   else
149f75da0c8SAlexey Lapshin     return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
150f75da0c8SAlexey Lapshin }
151f75da0c8SAlexey Lapshin 
152f75da0c8SAlexey Lapshin static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,
153f75da0c8SAlexey Lapshin                                                Object &Obj, raw_ostream &Out,
154f75da0c8SAlexey Lapshin                                                ElfType OutputElfType) {
155f75da0c8SAlexey Lapshin   // Depending on the initial ELFT and OutputFormat we need a different Writer.
156f75da0c8SAlexey Lapshin   switch (OutputElfType) {
157f75da0c8SAlexey Lapshin   case ELFT_ELF32LE:
158f75da0c8SAlexey Lapshin     return std::make_unique<ELFWriter<ELF32LE>>(Obj, Out, !Config.StripSections,
159f75da0c8SAlexey Lapshin                                                 Config.OnlyKeepDebug);
160f75da0c8SAlexey Lapshin   case ELFT_ELF64LE:
161f75da0c8SAlexey Lapshin     return std::make_unique<ELFWriter<ELF64LE>>(Obj, Out, !Config.StripSections,
162f75da0c8SAlexey Lapshin                                                 Config.OnlyKeepDebug);
163f75da0c8SAlexey Lapshin   case ELFT_ELF32BE:
164f75da0c8SAlexey Lapshin     return std::make_unique<ELFWriter<ELF32BE>>(Obj, Out, !Config.StripSections,
165f75da0c8SAlexey Lapshin                                                 Config.OnlyKeepDebug);
166f75da0c8SAlexey Lapshin   case ELFT_ELF64BE:
167f75da0c8SAlexey Lapshin     return std::make_unique<ELFWriter<ELF64BE>>(Obj, Out, !Config.StripSections,
168f75da0c8SAlexey Lapshin                                                 Config.OnlyKeepDebug);
169f75da0c8SAlexey Lapshin   }
170f75da0c8SAlexey Lapshin   llvm_unreachable("Invalid output format");
171f75da0c8SAlexey Lapshin }
172f75da0c8SAlexey Lapshin 
173f75da0c8SAlexey Lapshin static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
174f75da0c8SAlexey Lapshin                                             Object &Obj, raw_ostream &Out,
175f75da0c8SAlexey Lapshin                                             ElfType OutputElfType) {
176f75da0c8SAlexey Lapshin   switch (Config.OutputFormat) {
177f75da0c8SAlexey Lapshin   case FileFormat::Binary:
1784070dffdSquic-akaryaki     return std::make_unique<BinaryWriter>(Obj, Out, Config);
179f75da0c8SAlexey Lapshin   case FileFormat::IHex:
1807ddc3205Squic-areg     return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);
1817ddc3205Squic-areg   case FileFormat::SREC:
1827ddc3205Squic-areg     return std::make_unique<SRECWriter>(Obj, Out, Config.OutputFilename);
183f75da0c8SAlexey Lapshin   default:
184f75da0c8SAlexey Lapshin     return createELFWriter(Config, Obj, Out, OutputElfType);
185f75da0c8SAlexey Lapshin   }
186f75da0c8SAlexey Lapshin }
187f75da0c8SAlexey Lapshin 
188f75da0c8SAlexey Lapshin static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
189f75da0c8SAlexey Lapshin                                Object &Obj) {
190f75da0c8SAlexey Lapshin   for (auto &Sec : Obj.sections()) {
191f75da0c8SAlexey Lapshin     if (Sec.Name == SecName) {
192f75da0c8SAlexey Lapshin       if (Sec.Type == SHT_NOBITS)
193f75da0c8SAlexey Lapshin         return createStringError(object_error::parse_failed,
194f75da0c8SAlexey Lapshin                                  "cannot dump section '%s': it has no contents",
195f75da0c8SAlexey Lapshin                                  SecName.str().c_str());
196f75da0c8SAlexey Lapshin       Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
197f75da0c8SAlexey Lapshin           FileOutputBuffer::create(Filename, Sec.OriginalData.size());
198f75da0c8SAlexey Lapshin       if (!BufferOrErr)
199f75da0c8SAlexey Lapshin         return BufferOrErr.takeError();
200f75da0c8SAlexey Lapshin       std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
201f75da0c8SAlexey Lapshin       std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
202f75da0c8SAlexey Lapshin                 Buf->getBufferStart());
203f75da0c8SAlexey Lapshin       if (Error E = Buf->commit())
204f75da0c8SAlexey Lapshin         return E;
205f75da0c8SAlexey Lapshin       return Error::success();
206f75da0c8SAlexey Lapshin     }
207f75da0c8SAlexey Lapshin   }
208f75da0c8SAlexey Lapshin   return createStringError(object_error::parse_failed, "section '%s' not found",
209f75da0c8SAlexey Lapshin                            SecName.str().c_str());
210f75da0c8SAlexey Lapshin }
211f75da0c8SAlexey Lapshin 
212122d368bSFangrui Song Error Object::compressOrDecompressSections(const CommonConfig &Config) {
21307942987SFangrui Song   // Build a list of sections we are going to replace.
21407942987SFangrui Song   // We can't call `addSection` while iterating over sections,
215f75da0c8SAlexey Lapshin   // because it would mutate the sections array.
216122d368bSFangrui Song   SmallVector<std::pair<SectionBase *, std::function<SectionBase *()>>, 0>
217122d368bSFangrui Song       ToReplace;
218122d368bSFangrui Song   for (SectionBase &Sec : sections()) {
21907942987SFangrui Song     std::optional<DebugCompressionType> CType;
22007942987SFangrui Song     for (auto &[Matcher, T] : Config.compressSections)
22107942987SFangrui Song       if (Matcher.matches(Sec.Name))
22207942987SFangrui Song         CType = T;
22307942987SFangrui Song     // Handle --compress-debug-sections and --decompress-debug-sections, which
22407942987SFangrui Song     // apply to non-ALLOC debug sections.
22507942987SFangrui Song     if (!(Sec.Flags & SHF_ALLOC) && StringRef(Sec.Name).starts_with(".debug")) {
22607942987SFangrui Song       if (Config.CompressionType != DebugCompressionType::None)
22707942987SFangrui Song         CType = Config.CompressionType;
22807942987SFangrui Song       else if (Config.DecompressDebugSections)
22907942987SFangrui Song         CType = DebugCompressionType::None;
23007942987SFangrui Song     }
23107942987SFangrui Song     if (!CType)
232122d368bSFangrui Song       continue;
23307942987SFangrui Song 
23407942987SFangrui Song     if (Sec.ParentSegment)
23507942987SFangrui Song       return createStringError(
23607942987SFangrui Song           errc::invalid_argument,
23707942987SFangrui Song           "section '" + Sec.Name +
23807942987SFangrui Song               "' within a segment cannot be (de)compressed");
23907942987SFangrui Song 
240122d368bSFangrui Song     if (auto *CS = dyn_cast<CompressedSection>(&Sec)) {
24107942987SFangrui Song       if (*CType == DebugCompressionType::None)
242122d368bSFangrui Song         ToReplace.emplace_back(
243122d368bSFangrui Song             &Sec, [=] { return &addSection<DecompressedSection>(*CS); });
24407942987SFangrui Song     } else if (*CType != DebugCompressionType::None) {
24507942987SFangrui Song       ToReplace.emplace_back(&Sec, [=, S = &Sec] {
246122d368bSFangrui Song         return &addSection<CompressedSection>(
24707942987SFangrui Song             CompressedSection(*S, *CType, Is64Bits));
248122d368bSFangrui Song       });
249122d368bSFangrui Song     }
250f75da0c8SAlexey Lapshin   }
251f75da0c8SAlexey Lapshin 
252122d368bSFangrui Song   DenseMap<SectionBase *, SectionBase *> FromTo;
253122d368bSFangrui Song   for (auto [S, Func] : ToReplace)
254122d368bSFangrui Song     FromTo[S] = Func();
255122d368bSFangrui Song   return replaceSections(FromTo);
256f75da0c8SAlexey Lapshin }
257f75da0c8SAlexey Lapshin 
258f75da0c8SAlexey Lapshin static bool isAArch64MappingSymbol(const Symbol &Sym) {
259f75da0c8SAlexey Lapshin   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
260f75da0c8SAlexey Lapshin       Sym.getShndx() == SHN_UNDEF)
261f75da0c8SAlexey Lapshin     return false;
262f75da0c8SAlexey Lapshin   StringRef Name = Sym.Name;
263f75da0c8SAlexey Lapshin   if (!Name.consume_front("$x") && !Name.consume_front("$d"))
264f75da0c8SAlexey Lapshin     return false;
265586ecdf2SKazu Hirata   return Name.empty() || Name.starts_with(".");
266f75da0c8SAlexey Lapshin }
267f75da0c8SAlexey Lapshin 
268f75da0c8SAlexey Lapshin static bool isArmMappingSymbol(const Symbol &Sym) {
269f75da0c8SAlexey Lapshin   if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||
270f75da0c8SAlexey Lapshin       Sym.getShndx() == SHN_UNDEF)
271f75da0c8SAlexey Lapshin     return false;
272f75da0c8SAlexey Lapshin   StringRef Name = Sym.Name;
273f75da0c8SAlexey Lapshin   if (!Name.consume_front("$a") && !Name.consume_front("$d") &&
274f75da0c8SAlexey Lapshin       !Name.consume_front("$t"))
275f75da0c8SAlexey Lapshin     return false;
276586ecdf2SKazu Hirata   return Name.empty() || Name.starts_with(".");
277f75da0c8SAlexey Lapshin }
278f75da0c8SAlexey Lapshin 
279f75da0c8SAlexey Lapshin // Check if the symbol should be preserved because it is required by ABI.
280f75da0c8SAlexey Lapshin static bool isRequiredByABISymbol(const Object &Obj, const Symbol &Sym) {
281f75da0c8SAlexey Lapshin   switch (Obj.Machine) {
282f75da0c8SAlexey Lapshin   case EM_AARCH64:
283f75da0c8SAlexey Lapshin     // Mapping symbols should be preserved for a relocatable object file.
284f75da0c8SAlexey Lapshin     return Obj.isRelocatable() && isAArch64MappingSymbol(Sym);
285f75da0c8SAlexey Lapshin   case EM_ARM:
286f75da0c8SAlexey Lapshin     // Mapping symbols should be preserved for a relocatable object file.
287f75da0c8SAlexey Lapshin     return Obj.isRelocatable() && isArmMappingSymbol(Sym);
288f75da0c8SAlexey Lapshin   default:
289f75da0c8SAlexey Lapshin     return false;
290f75da0c8SAlexey Lapshin   }
291f75da0c8SAlexey Lapshin }
292f75da0c8SAlexey Lapshin 
293f75da0c8SAlexey Lapshin static bool isUnneededSymbol(const Symbol &Sym) {
294f75da0c8SAlexey Lapshin   return !Sym.Referenced &&
295f75da0c8SAlexey Lapshin          (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
296f75da0c8SAlexey Lapshin          Sym.Type != STT_SECTION;
297f75da0c8SAlexey Lapshin }
298f75da0c8SAlexey Lapshin 
299f75da0c8SAlexey Lapshin static Error updateAndRemoveSymbols(const CommonConfig &Config,
300f75da0c8SAlexey Lapshin                                     const ELFConfig &ELFConfig, Object &Obj) {
301f75da0c8SAlexey Lapshin   // TODO: update or remove symbols only if there is an option that affects
302f75da0c8SAlexey Lapshin   // them.
303f75da0c8SAlexey Lapshin   if (!Obj.SymbolTable)
304f75da0c8SAlexey Lapshin     return Error::success();
305f75da0c8SAlexey Lapshin 
306f75da0c8SAlexey Lapshin   Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
3074946cc37SIlia Kuklin     if (Config.SymbolsToSkip.matches(Sym.Name))
3084946cc37SIlia Kuklin       return;
3094946cc37SIlia Kuklin 
310f75da0c8SAlexey Lapshin     // Common and undefined symbols don't make sense as local symbols, and can
311f75da0c8SAlexey Lapshin     // even cause crashes if we localize those, so skip them.
312f75da0c8SAlexey Lapshin     if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
313f75da0c8SAlexey Lapshin         ((ELFConfig.LocalizeHidden &&
314f75da0c8SAlexey Lapshin           (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
315f75da0c8SAlexey Lapshin          Config.SymbolsToLocalize.matches(Sym.Name)))
316f75da0c8SAlexey Lapshin       Sym.Binding = STB_LOCAL;
317f75da0c8SAlexey Lapshin 
31807d8a457SIlia Kuklin     for (auto &[Matcher, Visibility] : ELFConfig.SymbolsToSetVisibility)
31907d8a457SIlia Kuklin       if (Matcher.matches(Sym.Name))
32007d8a457SIlia Kuklin         Sym.Visibility = Visibility;
32107d8a457SIlia Kuklin 
322f75da0c8SAlexey Lapshin     // Note: these two globalize flags have very similar names but different
323f75da0c8SAlexey Lapshin     // meanings:
324f75da0c8SAlexey Lapshin     //
325f75da0c8SAlexey Lapshin     // --globalize-symbol: promote a symbol to global
326f75da0c8SAlexey Lapshin     // --keep-global-symbol: all symbols except for these should be made local
327f75da0c8SAlexey Lapshin     //
328f75da0c8SAlexey Lapshin     // If --globalize-symbol is specified for a given symbol, it will be
329f75da0c8SAlexey Lapshin     // global in the output file even if it is not included via
330f75da0c8SAlexey Lapshin     // --keep-global-symbol. Because of that, make sure to check
331f75da0c8SAlexey Lapshin     // --globalize-symbol second.
332f75da0c8SAlexey Lapshin     if (!Config.SymbolsToKeepGlobal.empty() &&
333f75da0c8SAlexey Lapshin         !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
334f75da0c8SAlexey Lapshin         Sym.getShndx() != SHN_UNDEF)
335f75da0c8SAlexey Lapshin       Sym.Binding = STB_LOCAL;
336f75da0c8SAlexey Lapshin 
337f75da0c8SAlexey Lapshin     if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
338f75da0c8SAlexey Lapshin         Sym.getShndx() != SHN_UNDEF)
339f75da0c8SAlexey Lapshin       Sym.Binding = STB_GLOBAL;
340f75da0c8SAlexey Lapshin 
34130718f3aSFangrui Song     // SymbolsToWeaken applies to both STB_GLOBAL and STB_GNU_UNIQUE.
34230718f3aSFangrui Song     if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding != STB_LOCAL)
343f75da0c8SAlexey Lapshin       Sym.Binding = STB_WEAK;
344f75da0c8SAlexey Lapshin 
34530718f3aSFangrui Song     if (Config.Weaken && Sym.Binding != STB_LOCAL &&
346f75da0c8SAlexey Lapshin         Sym.getShndx() != SHN_UNDEF)
347f75da0c8SAlexey Lapshin       Sym.Binding = STB_WEAK;
348f75da0c8SAlexey Lapshin 
349f75da0c8SAlexey Lapshin     const auto I = Config.SymbolsToRename.find(Sym.Name);
350f75da0c8SAlexey Lapshin     if (I != Config.SymbolsToRename.end())
351f75da0c8SAlexey Lapshin       Sym.Name = std::string(I->getValue());
352f75da0c8SAlexey Lapshin 
3531b87ebceSYi Kong     if (!Config.SymbolsPrefixRemove.empty() && Sym.Type != STT_SECTION)
3541b87ebceSYi Kong       if (Sym.Name.compare(0, Config.SymbolsPrefixRemove.size(),
3551b87ebceSYi Kong                            Config.SymbolsPrefixRemove) == 0)
3561b87ebceSYi Kong         Sym.Name = Sym.Name.substr(Config.SymbolsPrefixRemove.size());
3571b87ebceSYi Kong 
358f75da0c8SAlexey Lapshin     if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
359f75da0c8SAlexey Lapshin       Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
360f75da0c8SAlexey Lapshin   });
361f75da0c8SAlexey Lapshin 
362f75da0c8SAlexey Lapshin   // The purpose of this loop is to mark symbols referenced by sections
363f75da0c8SAlexey Lapshin   // (like GroupSection or RelocationSection). This way, we know which
364f75da0c8SAlexey Lapshin   // symbols are still 'needed' and which are not.
365f75da0c8SAlexey Lapshin   if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
366f75da0c8SAlexey Lapshin       !Config.OnlySection.empty()) {
367f75da0c8SAlexey Lapshin     for (SectionBase &Sec : Obj.sections())
368f75da0c8SAlexey Lapshin       Sec.markSymbols();
369f75da0c8SAlexey Lapshin   }
370f75da0c8SAlexey Lapshin 
371f75da0c8SAlexey Lapshin   auto RemoveSymbolsPred = [&](const Symbol &Sym) {
372f75da0c8SAlexey Lapshin     if (Config.SymbolsToKeep.matches(Sym.Name) ||
373f75da0c8SAlexey Lapshin         (ELFConfig.KeepFileSymbols && Sym.Type == STT_FILE))
374f75da0c8SAlexey Lapshin       return false;
375f75da0c8SAlexey Lapshin 
376f75da0c8SAlexey Lapshin     if (Config.SymbolsToRemove.matches(Sym.Name))
377f75da0c8SAlexey Lapshin       return true;
378f75da0c8SAlexey Lapshin 
379f75da0c8SAlexey Lapshin     if (Config.StripAll || Config.StripAllGNU)
380f75da0c8SAlexey Lapshin       return true;
381f75da0c8SAlexey Lapshin 
382f75da0c8SAlexey Lapshin     if (isRequiredByABISymbol(Obj, Sym))
383f75da0c8SAlexey Lapshin       return false;
384f75da0c8SAlexey Lapshin 
385f75da0c8SAlexey Lapshin     if (Config.StripDebug && Sym.Type == STT_FILE)
386f75da0c8SAlexey Lapshin       return true;
387f75da0c8SAlexey Lapshin 
388f75da0c8SAlexey Lapshin     if ((Config.DiscardMode == DiscardType::All ||
389f75da0c8SAlexey Lapshin          (Config.DiscardMode == DiscardType::Locals &&
390586ecdf2SKazu Hirata           StringRef(Sym.Name).starts_with(".L"))) &&
391f75da0c8SAlexey Lapshin         Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
392f75da0c8SAlexey Lapshin         Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
393f75da0c8SAlexey Lapshin       return true;
394f75da0c8SAlexey Lapshin 
395f75da0c8SAlexey Lapshin     if ((Config.StripUnneeded ||
396f75da0c8SAlexey Lapshin          Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
397f75da0c8SAlexey Lapshin         (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
398f75da0c8SAlexey Lapshin       return true;
399f75da0c8SAlexey Lapshin 
400f75da0c8SAlexey Lapshin     // We want to remove undefined symbols if all references have been stripped.
401f75da0c8SAlexey Lapshin     if (!Config.OnlySection.empty() && !Sym.Referenced &&
402f75da0c8SAlexey Lapshin         Sym.getShndx() == SHN_UNDEF)
403f75da0c8SAlexey Lapshin       return true;
404f75da0c8SAlexey Lapshin 
405f75da0c8SAlexey Lapshin     return false;
406f75da0c8SAlexey Lapshin   };
407f75da0c8SAlexey Lapshin 
408f75da0c8SAlexey Lapshin   return Obj.removeSymbols(RemoveSymbolsPred);
409f75da0c8SAlexey Lapshin }
410f75da0c8SAlexey Lapshin 
411f75da0c8SAlexey Lapshin static Error replaceAndRemoveSections(const CommonConfig &Config,
412f75da0c8SAlexey Lapshin                                       const ELFConfig &ELFConfig, Object &Obj) {
413f75da0c8SAlexey Lapshin   SectionPred RemovePred = [](const SectionBase &) { return false; };
414f75da0c8SAlexey Lapshin 
415f75da0c8SAlexey Lapshin   // Removes:
416f75da0c8SAlexey Lapshin   if (!Config.ToRemove.empty()) {
417f75da0c8SAlexey Lapshin     RemovePred = [&Config](const SectionBase &Sec) {
418f75da0c8SAlexey Lapshin       return Config.ToRemove.matches(Sec.Name);
419f75da0c8SAlexey Lapshin     };
420f75da0c8SAlexey Lapshin   }
421f75da0c8SAlexey Lapshin 
422f75da0c8SAlexey Lapshin   if (Config.StripDWO)
423f75da0c8SAlexey Lapshin     RemovePred = [RemovePred](const SectionBase &Sec) {
424f75da0c8SAlexey Lapshin       return isDWOSection(Sec) || RemovePred(Sec);
425f75da0c8SAlexey Lapshin     };
426f75da0c8SAlexey Lapshin 
427f75da0c8SAlexey Lapshin   if (Config.ExtractDWO)
428f75da0c8SAlexey Lapshin     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
429f75da0c8SAlexey Lapshin       return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
430f75da0c8SAlexey Lapshin     };
431f75da0c8SAlexey Lapshin 
432f75da0c8SAlexey Lapshin   if (Config.StripAllGNU)
433f75da0c8SAlexey Lapshin     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
434f75da0c8SAlexey Lapshin       if (RemovePred(Sec))
435f75da0c8SAlexey Lapshin         return true;
436f75da0c8SAlexey Lapshin       if ((Sec.Flags & SHF_ALLOC) != 0)
437f75da0c8SAlexey Lapshin         return false;
438f75da0c8SAlexey Lapshin       if (&Sec == Obj.SectionNames)
439f75da0c8SAlexey Lapshin         return false;
440f75da0c8SAlexey Lapshin       switch (Sec.Type) {
441f75da0c8SAlexey Lapshin       case SHT_SYMTAB:
442f75da0c8SAlexey Lapshin       case SHT_REL:
443f75da0c8SAlexey Lapshin       case SHT_RELA:
444f75da0c8SAlexey Lapshin       case SHT_STRTAB:
445f75da0c8SAlexey Lapshin         return true;
446f75da0c8SAlexey Lapshin       }
447f75da0c8SAlexey Lapshin       return isDebugSection(Sec);
448f75da0c8SAlexey Lapshin     };
449f75da0c8SAlexey Lapshin 
450f75da0c8SAlexey Lapshin   if (Config.StripSections) {
451f75da0c8SAlexey Lapshin     RemovePred = [RemovePred](const SectionBase &Sec) {
452f75da0c8SAlexey Lapshin       return RemovePred(Sec) || Sec.ParentSegment == nullptr;
453f75da0c8SAlexey Lapshin     };
454f75da0c8SAlexey Lapshin   }
455f75da0c8SAlexey Lapshin 
456f75da0c8SAlexey Lapshin   if (Config.StripDebug || Config.StripUnneeded) {
457f75da0c8SAlexey Lapshin     RemovePred = [RemovePred](const SectionBase &Sec) {
458f75da0c8SAlexey Lapshin       return RemovePred(Sec) || isDebugSection(Sec);
459f75da0c8SAlexey Lapshin     };
460f75da0c8SAlexey Lapshin   }
461f75da0c8SAlexey Lapshin 
462f75da0c8SAlexey Lapshin   if (Config.StripNonAlloc)
463f75da0c8SAlexey Lapshin     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
464f75da0c8SAlexey Lapshin       if (RemovePred(Sec))
465f75da0c8SAlexey Lapshin         return true;
466f75da0c8SAlexey Lapshin       if (&Sec == Obj.SectionNames)
467f75da0c8SAlexey Lapshin         return false;
468f75da0c8SAlexey Lapshin       return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
469f75da0c8SAlexey Lapshin     };
470f75da0c8SAlexey Lapshin 
471f75da0c8SAlexey Lapshin   if (Config.StripAll)
472f75da0c8SAlexey Lapshin     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
473f75da0c8SAlexey Lapshin       if (RemovePred(Sec))
474f75da0c8SAlexey Lapshin         return true;
475f75da0c8SAlexey Lapshin       if (&Sec == Obj.SectionNames)
476f75da0c8SAlexey Lapshin         return false;
477586ecdf2SKazu Hirata       if (StringRef(Sec.Name).starts_with(".gnu.warning"))
478f75da0c8SAlexey Lapshin         return false;
47911ca56eaSFelix Kellenbenz       if (StringRef(Sec.Name).starts_with(".gnu_debuglink"))
48011ca56eaSFelix Kellenbenz         return false;
481f75da0c8SAlexey Lapshin       // We keep the .ARM.attribute section to maintain compatibility
482f75da0c8SAlexey Lapshin       // with Debian derived distributions. This is a bug in their
483f75da0c8SAlexey Lapshin       // patchset as documented here:
484f75da0c8SAlexey Lapshin       // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
485f75da0c8SAlexey Lapshin       if (Sec.Type == SHT_ARM_ATTRIBUTES)
486f75da0c8SAlexey Lapshin         return false;
487f75da0c8SAlexey Lapshin       if (Sec.ParentSegment != nullptr)
488f75da0c8SAlexey Lapshin         return false;
489f75da0c8SAlexey Lapshin       return (Sec.Flags & SHF_ALLOC) == 0;
490f75da0c8SAlexey Lapshin     };
491f75da0c8SAlexey Lapshin 
492f75da0c8SAlexey Lapshin   if (Config.ExtractPartition || Config.ExtractMainPartition) {
493f75da0c8SAlexey Lapshin     RemovePred = [RemovePred](const SectionBase &Sec) {
494f75da0c8SAlexey Lapshin       if (RemovePred(Sec))
495f75da0c8SAlexey Lapshin         return true;
496f75da0c8SAlexey Lapshin       if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
497f75da0c8SAlexey Lapshin         return true;
498f75da0c8SAlexey Lapshin       return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
499f75da0c8SAlexey Lapshin     };
500f75da0c8SAlexey Lapshin   }
501f75da0c8SAlexey Lapshin 
502f75da0c8SAlexey Lapshin   // Explicit copies:
503f75da0c8SAlexey Lapshin   if (!Config.OnlySection.empty()) {
504f75da0c8SAlexey Lapshin     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
505f75da0c8SAlexey Lapshin       // Explicitly keep these sections regardless of previous removes.
506f75da0c8SAlexey Lapshin       if (Config.OnlySection.matches(Sec.Name))
507f75da0c8SAlexey Lapshin         return false;
508f75da0c8SAlexey Lapshin 
509f75da0c8SAlexey Lapshin       // Allow all implicit removes.
510f75da0c8SAlexey Lapshin       if (RemovePred(Sec))
511f75da0c8SAlexey Lapshin         return true;
512f75da0c8SAlexey Lapshin 
513f75da0c8SAlexey Lapshin       // Keep special sections.
514f75da0c8SAlexey Lapshin       if (Obj.SectionNames == &Sec)
515f75da0c8SAlexey Lapshin         return false;
516f75da0c8SAlexey Lapshin       if (Obj.SymbolTable == &Sec ||
517f75da0c8SAlexey Lapshin           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
518f75da0c8SAlexey Lapshin         return false;
519f75da0c8SAlexey Lapshin 
520f75da0c8SAlexey Lapshin       // Remove everything else.
521f75da0c8SAlexey Lapshin       return true;
522f75da0c8SAlexey Lapshin     };
523f75da0c8SAlexey Lapshin   }
524f75da0c8SAlexey Lapshin 
525f75da0c8SAlexey Lapshin   if (!Config.KeepSection.empty()) {
526f75da0c8SAlexey Lapshin     RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
527f75da0c8SAlexey Lapshin       // Explicitly keep these sections regardless of previous removes.
528f75da0c8SAlexey Lapshin       if (Config.KeepSection.matches(Sec.Name))
529f75da0c8SAlexey Lapshin         return false;
530f75da0c8SAlexey Lapshin       // Otherwise defer to RemovePred.
531f75da0c8SAlexey Lapshin       return RemovePred(Sec);
532f75da0c8SAlexey Lapshin     };
533f75da0c8SAlexey Lapshin   }
534f75da0c8SAlexey Lapshin 
535f75da0c8SAlexey Lapshin   // This has to be the last predicate assignment.
536f75da0c8SAlexey Lapshin   // If the option --keep-symbol has been specified
537f75da0c8SAlexey Lapshin   // and at least one of those symbols is present
538f75da0c8SAlexey Lapshin   // (equivalently, the updated symbol table is not empty)
539f75da0c8SAlexey Lapshin   // the symbol table and the string table should not be removed.
540f75da0c8SAlexey Lapshin   if ((!Config.SymbolsToKeep.empty() || ELFConfig.KeepFileSymbols) &&
541f75da0c8SAlexey Lapshin       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
542f75da0c8SAlexey Lapshin     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
543f75da0c8SAlexey Lapshin       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
544f75da0c8SAlexey Lapshin         return false;
545f75da0c8SAlexey Lapshin       return RemovePred(Sec);
546f75da0c8SAlexey Lapshin     };
547f75da0c8SAlexey Lapshin   }
548f75da0c8SAlexey Lapshin 
549f75da0c8SAlexey Lapshin   if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))
550f75da0c8SAlexey Lapshin     return E;
551f75da0c8SAlexey Lapshin 
552122d368bSFangrui Song   if (Error E = Obj.compressOrDecompressSections(Config))
553122d368bSFangrui Song     return E;
554f75da0c8SAlexey Lapshin 
555f75da0c8SAlexey Lapshin   return Error::success();
556f75da0c8SAlexey Lapshin }
557f75da0c8SAlexey Lapshin 
558f75da0c8SAlexey Lapshin // Add symbol to the Object symbol table with the specified properties.
559f75da0c8SAlexey Lapshin static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
560f75da0c8SAlexey Lapshin                       uint8_t DefaultVisibility) {
561f75da0c8SAlexey Lapshin   SectionBase *Sec = Obj.findSection(SymInfo.SectionName);
562f75da0c8SAlexey Lapshin   uint64_t Value = Sec ? Sec->Addr + SymInfo.Value : SymInfo.Value;
563f75da0c8SAlexey Lapshin 
564f75da0c8SAlexey Lapshin   uint8_t Bind = ELF::STB_GLOBAL;
565f75da0c8SAlexey Lapshin   uint8_t Type = ELF::STT_NOTYPE;
566f75da0c8SAlexey Lapshin   uint8_t Visibility = DefaultVisibility;
567f75da0c8SAlexey Lapshin 
568f75da0c8SAlexey Lapshin   for (SymbolFlag FlagValue : SymInfo.Flags)
569f75da0c8SAlexey Lapshin     switch (FlagValue) {
570f75da0c8SAlexey Lapshin     case SymbolFlag::Global:
571f75da0c8SAlexey Lapshin       Bind = ELF::STB_GLOBAL;
572f75da0c8SAlexey Lapshin       break;
573f75da0c8SAlexey Lapshin     case SymbolFlag::Local:
574f75da0c8SAlexey Lapshin       Bind = ELF::STB_LOCAL;
575f75da0c8SAlexey Lapshin       break;
576f75da0c8SAlexey Lapshin     case SymbolFlag::Weak:
577f75da0c8SAlexey Lapshin       Bind = ELF::STB_WEAK;
578f75da0c8SAlexey Lapshin       break;
579f75da0c8SAlexey Lapshin     case SymbolFlag::Default:
580f75da0c8SAlexey Lapshin       Visibility = ELF::STV_DEFAULT;
581f75da0c8SAlexey Lapshin       break;
582f75da0c8SAlexey Lapshin     case SymbolFlag::Hidden:
583f75da0c8SAlexey Lapshin       Visibility = ELF::STV_HIDDEN;
584f75da0c8SAlexey Lapshin       break;
585f75da0c8SAlexey Lapshin     case SymbolFlag::Protected:
586f75da0c8SAlexey Lapshin       Visibility = ELF::STV_PROTECTED;
587f75da0c8SAlexey Lapshin       break;
588f75da0c8SAlexey Lapshin     case SymbolFlag::File:
589f75da0c8SAlexey Lapshin       Type = ELF::STT_FILE;
590f75da0c8SAlexey Lapshin       break;
591f75da0c8SAlexey Lapshin     case SymbolFlag::Section:
592f75da0c8SAlexey Lapshin       Type = ELF::STT_SECTION;
593f75da0c8SAlexey Lapshin       break;
594f75da0c8SAlexey Lapshin     case SymbolFlag::Object:
595f75da0c8SAlexey Lapshin       Type = ELF::STT_OBJECT;
596f75da0c8SAlexey Lapshin       break;
597f75da0c8SAlexey Lapshin     case SymbolFlag::Function:
598f75da0c8SAlexey Lapshin       Type = ELF::STT_FUNC;
599f75da0c8SAlexey Lapshin       break;
600f75da0c8SAlexey Lapshin     case SymbolFlag::IndirectFunction:
601f75da0c8SAlexey Lapshin       Type = ELF::STT_GNU_IFUNC;
602f75da0c8SAlexey Lapshin       break;
603f75da0c8SAlexey Lapshin     default: /* Other flag values are ignored for ELF. */
604f75da0c8SAlexey Lapshin       break;
605f75da0c8SAlexey Lapshin     };
606f75da0c8SAlexey Lapshin 
607f75da0c8SAlexey Lapshin   Obj.SymbolTable->addSymbol(
608f75da0c8SAlexey Lapshin       SymInfo.SymbolName, Bind, Type, Sec, Value, Visibility,
609f75da0c8SAlexey Lapshin       Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
610f75da0c8SAlexey Lapshin }
611f75da0c8SAlexey Lapshin 
612*10772807SIgor Kudrin namespace {
613*10772807SIgor Kudrin struct RemoveNoteDetail {
614*10772807SIgor Kudrin   struct DeletedRange {
615*10772807SIgor Kudrin     uint64_t OldFrom;
616*10772807SIgor Kudrin     uint64_t OldTo;
617*10772807SIgor Kudrin   };
618*10772807SIgor Kudrin 
619*10772807SIgor Kudrin   template <class ELFT>
620*10772807SIgor Kudrin   static std::vector<DeletedRange>
621*10772807SIgor Kudrin   findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
622*10772807SIgor Kudrin                     ArrayRef<RemoveNoteInfo> NotesToRemove);
623*10772807SIgor Kudrin   static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
624*10772807SIgor Kudrin                                          ArrayRef<DeletedRange> ToRemove);
625*10772807SIgor Kudrin };
626*10772807SIgor Kudrin } // namespace
627*10772807SIgor Kudrin 
628*10772807SIgor Kudrin template <class ELFT>
629*10772807SIgor Kudrin std::vector<RemoveNoteDetail::DeletedRange>
630*10772807SIgor Kudrin RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
631*10772807SIgor Kudrin                                     ArrayRef<RemoveNoteInfo> NotesToRemove) {
632*10772807SIgor Kudrin   using Elf_Nhdr = typename ELFT::Nhdr;
633*10772807SIgor Kudrin   using Elf_Note = typename ELFT::Note;
634*10772807SIgor Kudrin   std::vector<DeletedRange> ToRemove;
635*10772807SIgor Kudrin   uint64_t CurPos = 0;
636*10772807SIgor Kudrin   while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {
637*10772807SIgor Kudrin     auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);
638*10772807SIgor Kudrin     size_t FullSize = Nhdr->getSize(Align);
639*10772807SIgor Kudrin     if (CurPos + FullSize > Data.size())
640*10772807SIgor Kudrin       break;
641*10772807SIgor Kudrin     Elf_Note Note(*Nhdr);
642*10772807SIgor Kudrin     bool ShouldRemove =
643*10772807SIgor Kudrin         llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) {
644*10772807SIgor Kudrin           return NoteInfo.TypeId == Note.getType() &&
645*10772807SIgor Kudrin                  (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
646*10772807SIgor Kudrin         });
647*10772807SIgor Kudrin     if (ShouldRemove)
648*10772807SIgor Kudrin       ToRemove.push_back({CurPos, CurPos + FullSize});
649*10772807SIgor Kudrin     CurPos += FullSize;
650*10772807SIgor Kudrin   }
651*10772807SIgor Kudrin   return ToRemove;
652*10772807SIgor Kudrin }
653*10772807SIgor Kudrin 
654*10772807SIgor Kudrin std::vector<uint8_t>
655*10772807SIgor Kudrin RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
656*10772807SIgor Kudrin                              ArrayRef<DeletedRange> ToRemove) {
657*10772807SIgor Kudrin   std::vector<uint8_t> NewData;
658*10772807SIgor Kudrin   NewData.reserve(OldData.size());
659*10772807SIgor Kudrin   uint64_t CurPos = 0;
660*10772807SIgor Kudrin   for (const DeletedRange &RemRange : ToRemove) {
661*10772807SIgor Kudrin     if (CurPos < RemRange.OldFrom) {
662*10772807SIgor Kudrin       auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
663*10772807SIgor Kudrin       NewData.insert(NewData.end(), Slice.begin(), Slice.end());
664*10772807SIgor Kudrin     }
665*10772807SIgor Kudrin     CurPos = RemRange.OldTo;
666*10772807SIgor Kudrin   }
667*10772807SIgor Kudrin   if (CurPos < OldData.size()) {
668*10772807SIgor Kudrin     auto Slice = OldData.slice(CurPos);
669*10772807SIgor Kudrin     NewData.insert(NewData.end(), Slice.begin(), Slice.end());
670*10772807SIgor Kudrin   }
671*10772807SIgor Kudrin   return NewData;
672*10772807SIgor Kudrin }
673*10772807SIgor Kudrin 
674*10772807SIgor Kudrin static Error removeNotes(Object &Obj, endianness Endianness,
675*10772807SIgor Kudrin                          ArrayRef<RemoveNoteInfo> NotesToRemove,
676*10772807SIgor Kudrin                          function_ref<Error(Error)> ErrorCallback) {
677*10772807SIgor Kudrin   // TODO: Support note segments.
678*10772807SIgor Kudrin   if (ErrorCallback) {
679*10772807SIgor Kudrin     for (Segment &Seg : Obj.segments()) {
680*10772807SIgor Kudrin       if (Seg.Type == PT_NOTE) {
681*10772807SIgor Kudrin         if (Error E = ErrorCallback(createStringError(
682*10772807SIgor Kudrin                 errc::not_supported, "note segments are not supported")))
683*10772807SIgor Kudrin           return E;
684*10772807SIgor Kudrin         break;
685*10772807SIgor Kudrin       }
686*10772807SIgor Kudrin     }
687*10772807SIgor Kudrin   }
688*10772807SIgor Kudrin   for (auto &Sec : Obj.sections()) {
689*10772807SIgor Kudrin     if (Sec.Type != SHT_NOTE || !Sec.hasContents())
690*10772807SIgor Kudrin       continue;
691*10772807SIgor Kudrin     // TODO: Support note sections in segments.
692*10772807SIgor Kudrin     if (Sec.ParentSegment) {
693*10772807SIgor Kudrin       if (ErrorCallback)
694*10772807SIgor Kudrin         if (Error E = ErrorCallback(createStringError(
695*10772807SIgor Kudrin                 errc::not_supported,
696*10772807SIgor Kudrin                 "cannot remove note(s) from " + Sec.Name +
697*10772807SIgor Kudrin                     ": sections in segments are not supported")))
698*10772807SIgor Kudrin           return E;
699*10772807SIgor Kudrin       continue;
700*10772807SIgor Kudrin     }
701*10772807SIgor Kudrin     ArrayRef<uint8_t> OldData = Sec.getContents();
702*10772807SIgor Kudrin     size_t Align = std::max<size_t>(4, Sec.Align);
703*10772807SIgor Kudrin     // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
704*10772807SIgor Kudrin     // header, so the parsers are the same.
705*10772807SIgor Kudrin     auto ToRemove = (Endianness == endianness::little)
706*10772807SIgor Kudrin                         ? RemoveNoteDetail::findNotesToRemove<ELF64LE>(
707*10772807SIgor Kudrin                               OldData, Align, NotesToRemove)
708*10772807SIgor Kudrin                         : RemoveNoteDetail::findNotesToRemove<ELF64BE>(
709*10772807SIgor Kudrin                               OldData, Align, NotesToRemove);
710*10772807SIgor Kudrin     if (!ToRemove.empty()) {
711*10772807SIgor Kudrin       if (Error E = Obj.updateSectionData(
712*10772807SIgor Kudrin               Sec, RemoveNoteDetail::updateData(OldData, ToRemove)))
713*10772807SIgor Kudrin         return E;
714*10772807SIgor Kudrin     }
715*10772807SIgor Kudrin   }
716*10772807SIgor Kudrin   return Error::success();
717*10772807SIgor Kudrin }
718*10772807SIgor Kudrin 
719f75da0c8SAlexey Lapshin static Error
720a6f3fedcSAlexey Lapshin handleUserSection(const NewSectionInfo &NewSection,
721f75da0c8SAlexey Lapshin                   function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
722a6f3fedcSAlexey Lapshin   ArrayRef<uint8_t> Data(reinterpret_cast<const uint8_t *>(
723a6f3fedcSAlexey Lapshin                              NewSection.SectionData->getBufferStart()),
724a6f3fedcSAlexey Lapshin                          NewSection.SectionData->getBufferSize());
725a6f3fedcSAlexey Lapshin   return F(NewSection.SectionName, Data);
726f75da0c8SAlexey Lapshin }
727f75da0c8SAlexey Lapshin 
728fb5a38bbSserge-sans-paille static Error verifyNoteSection(StringRef Name, endianness Endianness,
729fb5a38bbSserge-sans-paille                                ArrayRef<uint8_t> Data) {
730fb5a38bbSserge-sans-paille   // An ELF note has the following structure:
731fb5a38bbSserge-sans-paille   // Name Size: 4 bytes (integer)
732fb5a38bbSserge-sans-paille   // Desc Size: 4 bytes (integer)
733fb5a38bbSserge-sans-paille   // Type     : 4 bytes
734fb5a38bbSserge-sans-paille   // Name     : variable size, padded to a 4 byte boundary
735fb5a38bbSserge-sans-paille   // Desc     : variable size, padded to a 4 byte boundary
736fb5a38bbSserge-sans-paille 
737fb5a38bbSserge-sans-paille   if (Data.empty())
738fb5a38bbSserge-sans-paille     return Error::success();
739fb5a38bbSserge-sans-paille 
740fb5a38bbSserge-sans-paille   if (Data.size() < 12) {
741fb5a38bbSserge-sans-paille     std::string msg;
742fb5a38bbSserge-sans-paille     raw_string_ostream(msg)
743fb5a38bbSserge-sans-paille         << Name << " data must be either empty or at least 12 bytes long";
744fb5a38bbSserge-sans-paille     return createStringError(errc::invalid_argument, msg);
745fb5a38bbSserge-sans-paille   }
746fb5a38bbSserge-sans-paille   if (Data.size() % 4 != 0) {
747fb5a38bbSserge-sans-paille     std::string msg;
748fb5a38bbSserge-sans-paille     raw_string_ostream(msg)
749fb5a38bbSserge-sans-paille         << Name << " data size must be a  multiple of 4 bytes";
750fb5a38bbSserge-sans-paille     return createStringError(errc::invalid_argument, msg);
751fb5a38bbSserge-sans-paille   }
752fb5a38bbSserge-sans-paille   ArrayRef<uint8_t> NameSize = Data.slice(0, 4);
753fb5a38bbSserge-sans-paille   ArrayRef<uint8_t> DescSize = Data.slice(4, 4);
754fb5a38bbSserge-sans-paille 
755fb5a38bbSserge-sans-paille   uint32_t NameSizeValue = support::endian::read32(NameSize.data(), Endianness);
756fb5a38bbSserge-sans-paille   uint32_t DescSizeValue = support::endian::read32(DescSize.data(), Endianness);
757fb5a38bbSserge-sans-paille 
758fb5a38bbSserge-sans-paille   uint64_t ExpectedDataSize =
759fb5a38bbSserge-sans-paille       /*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 +
760fb5a38bbSserge-sans-paille       /*Name=*/alignTo(NameSizeValue, 4) +
761fb5a38bbSserge-sans-paille       /*Desc=*/alignTo(DescSizeValue, 4);
762fb5a38bbSserge-sans-paille   uint64_t ActualDataSize = Data.size();
763fb5a38bbSserge-sans-paille   if (ActualDataSize != ExpectedDataSize) {
764fb5a38bbSserge-sans-paille     std::string msg;
765fb5a38bbSserge-sans-paille     raw_string_ostream(msg)
766fb5a38bbSserge-sans-paille         << Name
767fb5a38bbSserge-sans-paille         << " data size is incompatible with the content of "
768fb5a38bbSserge-sans-paille            "the name and description size fields:"
769fb5a38bbSserge-sans-paille         << " expecting " << ExpectedDataSize << ", found " << ActualDataSize;
770fb5a38bbSserge-sans-paille     return createStringError(errc::invalid_argument, msg);
771fb5a38bbSserge-sans-paille   }
772fb5a38bbSserge-sans-paille 
773fb5a38bbSserge-sans-paille   return Error::success();
774fb5a38bbSserge-sans-paille }
775fb5a38bbSserge-sans-paille 
776f75da0c8SAlexey Lapshin // This function handles the high level operations of GNU objcopy including
777f75da0c8SAlexey Lapshin // handling command line options. It's important to outline certain properties
778f75da0c8SAlexey Lapshin // we expect to hold of the command line operations. Any operation that "keeps"
779f75da0c8SAlexey Lapshin // should keep regardless of a remove. Additionally any removal should respect
780f75da0c8SAlexey Lapshin // any previous removals. Lastly whether or not something is removed shouldn't
781f75da0c8SAlexey Lapshin // depend a) on the order the options occur in or b) on some opaque priority
782f75da0c8SAlexey Lapshin // system. The only priority is that keeps/copies overrule removes.
783f75da0c8SAlexey Lapshin static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
784fb5a38bbSserge-sans-paille                         ElfType OutputElfType, Object &Obj) {
785f75da0c8SAlexey Lapshin   if (Config.OutputArch) {
78667ba5c50SFangrui Song     Obj.Machine = Config.OutputArch->EMachine;
78767ba5c50SFangrui Song     Obj.OSABI = Config.OutputArch->OSABI;
788f75da0c8SAlexey Lapshin   }
789f75da0c8SAlexey Lapshin 
790f75da0c8SAlexey Lapshin   if (!Config.SplitDWO.empty() && Config.ExtractDWO) {
791f75da0c8SAlexey Lapshin     return Obj.removeSections(
792f75da0c8SAlexey Lapshin         ELFConfig.AllowBrokenLinks,
793f75da0c8SAlexey Lapshin         [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); });
794f75da0c8SAlexey Lapshin   }
795f75da0c8SAlexey Lapshin 
796f75da0c8SAlexey Lapshin   // Dump sections before add/remove for compatibility with GNU objcopy.
797f75da0c8SAlexey Lapshin   for (StringRef Flag : Config.DumpSection) {
798f75da0c8SAlexey Lapshin     StringRef SectionName;
799f75da0c8SAlexey Lapshin     StringRef FileName;
800f75da0c8SAlexey Lapshin     std::tie(SectionName, FileName) = Flag.split('=');
801f75da0c8SAlexey Lapshin     if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
802f75da0c8SAlexey Lapshin       return E;
803f75da0c8SAlexey Lapshin   }
804f75da0c8SAlexey Lapshin 
805f75da0c8SAlexey Lapshin   // It is important to remove the sections first. For example, we want to
806f75da0c8SAlexey Lapshin   // remove the relocation sections before removing the symbols. That allows
807f75da0c8SAlexey Lapshin   // us to avoid reporting the inappropriate errors about removing symbols
808f75da0c8SAlexey Lapshin   // named in relocations.
809f75da0c8SAlexey Lapshin   if (Error E = replaceAndRemoveSections(Config, ELFConfig, Obj))
810f75da0c8SAlexey Lapshin     return E;
811f75da0c8SAlexey Lapshin 
812f75da0c8SAlexey Lapshin   if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj))
813f75da0c8SAlexey Lapshin     return E;
814f75da0c8SAlexey Lapshin 
8157c03b7d6SFangrui Song   if (!Config.SetSectionAlignment.empty()) {
8167c03b7d6SFangrui Song     for (SectionBase &Sec : Obj.sections()) {
8177c03b7d6SFangrui Song       auto I = Config.SetSectionAlignment.find(Sec.Name);
8187c03b7d6SFangrui Song       if (I != Config.SetSectionAlignment.end())
8197c03b7d6SFangrui Song         Sec.Align = I->second;
8207c03b7d6SFangrui Song     }
8217c03b7d6SFangrui Song   }
8227c03b7d6SFangrui Song 
82333200363SEleanor Bonnici   if (Config.ChangeSectionLMAValAll != 0) {
82433200363SEleanor Bonnici     for (Segment &Seg : Obj.segments()) {
82533200363SEleanor Bonnici       if (Seg.FileSize > 0) {
82633200363SEleanor Bonnici         if (Config.ChangeSectionLMAValAll > 0 &&
82733200363SEleanor Bonnici             Seg.PAddr > std::numeric_limits<uint64_t>::max() -
82833200363SEleanor Bonnici                             Config.ChangeSectionLMAValAll) {
82933200363SEleanor Bonnici           return createStringError(
83033200363SEleanor Bonnici               errc::invalid_argument,
83133200363SEleanor Bonnici               "address 0x" + Twine::utohexstr(Seg.PAddr) +
83233200363SEleanor Bonnici                   " cannot be increased by 0x" +
83333200363SEleanor Bonnici                   Twine::utohexstr(Config.ChangeSectionLMAValAll) +
83433200363SEleanor Bonnici                   ". The result would overflow");
83533200363SEleanor Bonnici         } else if (Config.ChangeSectionLMAValAll < 0 &&
83633200363SEleanor Bonnici                    Seg.PAddr < std::numeric_limits<uint64_t>::min() -
83733200363SEleanor Bonnici                                    Config.ChangeSectionLMAValAll) {
83833200363SEleanor Bonnici           return createStringError(
83933200363SEleanor Bonnici               errc::invalid_argument,
84033200363SEleanor Bonnici               "address 0x" + Twine::utohexstr(Seg.PAddr) +
84133200363SEleanor Bonnici                   " cannot be decreased by 0x" +
84233200363SEleanor Bonnici                   Twine::utohexstr(std::abs(Config.ChangeSectionLMAValAll)) +
84333200363SEleanor Bonnici                   ". The result would underflow");
84433200363SEleanor Bonnici         }
84533200363SEleanor Bonnici         Seg.PAddr += Config.ChangeSectionLMAValAll;
84633200363SEleanor Bonnici       }
84733200363SEleanor Bonnici     }
84833200363SEleanor Bonnici   }
84933200363SEleanor Bonnici 
8502b2f4ae0SEleanor Bonnici   if (!Config.ChangeSectionAddress.empty()) {
8512b2f4ae0SEleanor Bonnici     if (Obj.Type != ELF::ET_REL)
8522b2f4ae0SEleanor Bonnici       return createStringError(
8532b2f4ae0SEleanor Bonnici           object_error::invalid_file_type,
8542b2f4ae0SEleanor Bonnici           "cannot change section address in a non-relocatable file");
8552b2f4ae0SEleanor Bonnici 
8562b2f4ae0SEleanor Bonnici     StringMap<AddressUpdate> SectionsToUpdateAddress;
8572b2f4ae0SEleanor Bonnici     for (const SectionPatternAddressUpdate &PatternUpdate :
8582b2f4ae0SEleanor Bonnici          make_range(Config.ChangeSectionAddress.rbegin(),
8592b2f4ae0SEleanor Bonnici                     Config.ChangeSectionAddress.rend())) {
8602b2f4ae0SEleanor Bonnici       for (SectionBase &Sec : Obj.sections()) {
8612b2f4ae0SEleanor Bonnici         if (PatternUpdate.SectionPattern.matches(Sec.Name) &&
8622b2f4ae0SEleanor Bonnici             SectionsToUpdateAddress.try_emplace(Sec.Name, PatternUpdate.Update)
8632b2f4ae0SEleanor Bonnici                 .second) {
8642b2f4ae0SEleanor Bonnici           if (PatternUpdate.Update.Kind == AdjustKind::Subtract &&
8652b2f4ae0SEleanor Bonnici               Sec.Addr < PatternUpdate.Update.Value) {
8662b2f4ae0SEleanor Bonnici             return createStringError(
8672b2f4ae0SEleanor Bonnici                 errc::invalid_argument,
8682b2f4ae0SEleanor Bonnici                 "address 0x" + Twine::utohexstr(Sec.Addr) +
8692b2f4ae0SEleanor Bonnici                     " cannot be decreased by 0x" +
8702b2f4ae0SEleanor Bonnici                     Twine::utohexstr(PatternUpdate.Update.Value) +
8712b2f4ae0SEleanor Bonnici                     ". The result would underflow");
8722b2f4ae0SEleanor Bonnici           }
8732b2f4ae0SEleanor Bonnici           if (PatternUpdate.Update.Kind == AdjustKind::Add &&
8742b2f4ae0SEleanor Bonnici               Sec.Addr > std::numeric_limits<uint64_t>::max() -
8752b2f4ae0SEleanor Bonnici                              PatternUpdate.Update.Value) {
8762b2f4ae0SEleanor Bonnici             return createStringError(
8772b2f4ae0SEleanor Bonnici                 errc::invalid_argument,
8782b2f4ae0SEleanor Bonnici                 "address 0x" + Twine::utohexstr(Sec.Addr) +
8792b2f4ae0SEleanor Bonnici                     " cannot be increased by 0x" +
8802b2f4ae0SEleanor Bonnici                     Twine::utohexstr(PatternUpdate.Update.Value) +
8812b2f4ae0SEleanor Bonnici                     ". The result would overflow");
8822b2f4ae0SEleanor Bonnici           }
8832b2f4ae0SEleanor Bonnici 
8842b2f4ae0SEleanor Bonnici           switch (PatternUpdate.Update.Kind) {
8852b2f4ae0SEleanor Bonnici           case (AdjustKind::Set):
8862b2f4ae0SEleanor Bonnici             Sec.Addr = PatternUpdate.Update.Value;
8872b2f4ae0SEleanor Bonnici             break;
8882b2f4ae0SEleanor Bonnici           case (AdjustKind::Subtract):
8892b2f4ae0SEleanor Bonnici             Sec.Addr -= PatternUpdate.Update.Value;
8902b2f4ae0SEleanor Bonnici             break;
8912b2f4ae0SEleanor Bonnici           case (AdjustKind::Add):
8922b2f4ae0SEleanor Bonnici             Sec.Addr += PatternUpdate.Update.Value;
8932b2f4ae0SEleanor Bonnici             break;
8942b2f4ae0SEleanor Bonnici           }
8952b2f4ae0SEleanor Bonnici         }
8962b2f4ae0SEleanor Bonnici       }
8972b2f4ae0SEleanor Bonnici     }
8982b2f4ae0SEleanor Bonnici   }
8992b2f4ae0SEleanor Bonnici 
9007c03b7d6SFangrui Song   if (Config.OnlyKeepDebug)
9017c03b7d6SFangrui Song     for (auto &Sec : Obj.sections())
9027c03b7d6SFangrui Song       if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
9037c03b7d6SFangrui Song         Sec.Type = SHT_NOBITS;
9047c03b7d6SFangrui Song 
905fb5a38bbSserge-sans-paille   endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE
906fb5a38bbSserge-sans-paille                      ? endianness::little
907fb5a38bbSserge-sans-paille                      : endianness::big;
908fb5a38bbSserge-sans-paille 
909*10772807SIgor Kudrin   if (!ELFConfig.NotesToRemove.empty()) {
910*10772807SIgor Kudrin     if (Error Err =
911*10772807SIgor Kudrin             removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))
912*10772807SIgor Kudrin       return Err;
913*10772807SIgor Kudrin   }
914*10772807SIgor Kudrin 
9157c03b7d6SFangrui Song   for (const NewSectionInfo &AddedSection : Config.AddSection) {
916fb5a38bbSserge-sans-paille     auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {
9177c03b7d6SFangrui Song       OwnedDataSection &NewSection =
9187c03b7d6SFangrui Song           Obj.addSection<OwnedDataSection>(Name, Data);
919fb5a38bbSserge-sans-paille       if (Name.starts_with(".note") && Name != ".note.GNU-stack") {
9207c03b7d6SFangrui Song         NewSection.Type = SHT_NOTE;
921fb5a38bbSserge-sans-paille         if (ELFConfig.VerifyNoteSections)
922fb5a38bbSserge-sans-paille           return verifyNoteSection(Name, E, Data);
923fb5a38bbSserge-sans-paille       }
9247c03b7d6SFangrui Song       return Error::success();
9257c03b7d6SFangrui Song     };
9267c03b7d6SFangrui Song     if (Error E = handleUserSection(AddedSection, AddSection))
9277c03b7d6SFangrui Song       return E;
9287c03b7d6SFangrui Song   }
9297c03b7d6SFangrui Song 
9307c03b7d6SFangrui Song   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
9317c03b7d6SFangrui Song     auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
9327c03b7d6SFangrui Song       return Obj.updateSection(Name, Data);
9337c03b7d6SFangrui Song     };
9347c03b7d6SFangrui Song     if (Error E = handleUserSection(NewSection, UpdateSection))
9357c03b7d6SFangrui Song       return E;
9367c03b7d6SFangrui Song   }
9377c03b7d6SFangrui Song 
9387c03b7d6SFangrui Song   if (!Config.AddGnuDebugLink.empty())
9397c03b7d6SFangrui Song     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
9407c03b7d6SFangrui Song                                         Config.GnuDebugLinkCRC32);
9417c03b7d6SFangrui Song 
9427c03b7d6SFangrui Song   // If the symbol table was previously removed, we need to create a new one
9437c03b7d6SFangrui Song   // before adding new symbols.
9447c03b7d6SFangrui Song   if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty())
9457c03b7d6SFangrui Song     if (Error E = Obj.addNewSymbolTable())
9467c03b7d6SFangrui Song       return E;
9477c03b7d6SFangrui Song 
9487c03b7d6SFangrui Song   for (const NewSymbolInfo &SI : Config.SymbolsToAdd)
9497c03b7d6SFangrui Song     addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);
9507c03b7d6SFangrui Song 
951b28412d5SFangrui Song   // --set-section-{flags,type} work with sections added by --add-section.
952b28412d5SFangrui Song   if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {
9537c03b7d6SFangrui Song     for (auto &Sec : Obj.sections()) {
9547c03b7d6SFangrui Song       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
9557c03b7d6SFangrui Song       if (Iter != Config.SetSectionFlags.end()) {
9567c03b7d6SFangrui Song         const SectionFlagsUpdate &SFU = Iter->second;
9576f1395a1SThomas Köppe         if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))
9586f1395a1SThomas Köppe           return E;
9597c03b7d6SFangrui Song       }
960b28412d5SFangrui Song       auto It2 = Config.SetSectionType.find(Sec.Name);
961b28412d5SFangrui Song       if (It2 != Config.SetSectionType.end())
962c973123fSAlexey Karyakin         setSectionType(Sec, It2->second);
9637c03b7d6SFangrui Song     }
9647c03b7d6SFangrui Song   }
9657c03b7d6SFangrui Song 
966f75da0c8SAlexey Lapshin   if (!Config.SectionsToRename.empty()) {
967f75da0c8SAlexey Lapshin     std::vector<RelocationSectionBase *> RelocSections;
968f75da0c8SAlexey Lapshin     DenseSet<SectionBase *> RenamedSections;
969f75da0c8SAlexey Lapshin     for (SectionBase &Sec : Obj.sections()) {
970f75da0c8SAlexey Lapshin       auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec);
971f75da0c8SAlexey Lapshin       const auto Iter = Config.SectionsToRename.find(Sec.Name);
972f75da0c8SAlexey Lapshin       if (Iter != Config.SectionsToRename.end()) {
973f75da0c8SAlexey Lapshin         const SectionRename &SR = Iter->second;
974f75da0c8SAlexey Lapshin         Sec.Name = std::string(SR.NewName);
9756f1395a1SThomas Köppe         if (SR.NewFlags) {
9766f1395a1SThomas Köppe           if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))
9776f1395a1SThomas Köppe             return E;
9786f1395a1SThomas Köppe         }
979f75da0c8SAlexey Lapshin         RenamedSections.insert(&Sec);
980f75da0c8SAlexey Lapshin       } else if (RelocSec && !(Sec.Flags & SHF_ALLOC))
981f75da0c8SAlexey Lapshin         // Postpone processing relocation sections which are not specified in
982f75da0c8SAlexey Lapshin         // their explicit '--rename-section' commands until after their target
983f75da0c8SAlexey Lapshin         // sections are renamed.
984f75da0c8SAlexey Lapshin         // Dynamic relocation sections (i.e. ones with SHF_ALLOC) should be
985f75da0c8SAlexey Lapshin         // renamed only explicitly. Otherwise, renaming, for example, '.got.plt'
986f75da0c8SAlexey Lapshin         // would affect '.rela.plt', which is not desirable.
987f75da0c8SAlexey Lapshin         RelocSections.push_back(RelocSec);
988f75da0c8SAlexey Lapshin     }
989f75da0c8SAlexey Lapshin 
990f75da0c8SAlexey Lapshin     // Rename relocation sections according to their target sections.
991f75da0c8SAlexey Lapshin     for (RelocationSectionBase *RelocSec : RelocSections) {
992f75da0c8SAlexey Lapshin       auto Iter = RenamedSections.find(RelocSec->getSection());
993f75da0c8SAlexey Lapshin       if (Iter != RenamedSections.end())
994f75da0c8SAlexey Lapshin         RelocSec->Name = (RelocSec->getNamePrefix() + (*Iter)->Name).str();
995f75da0c8SAlexey Lapshin     }
996f75da0c8SAlexey Lapshin   }
997f75da0c8SAlexey Lapshin 
998f75da0c8SAlexey Lapshin   // Add a prefix to allocated sections and their relocation sections. This
999f75da0c8SAlexey Lapshin   // should be done after renaming the section by Config.SectionToRename to
1000f75da0c8SAlexey Lapshin   // imitate the GNU objcopy behavior.
1001f75da0c8SAlexey Lapshin   if (!Config.AllocSectionsPrefix.empty()) {
1002f75da0c8SAlexey Lapshin     DenseSet<SectionBase *> PrefixedSections;
1003f75da0c8SAlexey Lapshin     for (SectionBase &Sec : Obj.sections()) {
1004f75da0c8SAlexey Lapshin       if (Sec.Flags & SHF_ALLOC) {
1005f75da0c8SAlexey Lapshin         Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
1006f75da0c8SAlexey Lapshin         PrefixedSections.insert(&Sec);
1007f75da0c8SAlexey Lapshin       } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
1008f75da0c8SAlexey Lapshin         // Rename relocation sections associated to the allocated sections.
1009f75da0c8SAlexey Lapshin         // For example, if we rename .text to .prefix.text, we also rename
1010f75da0c8SAlexey Lapshin         // .rel.text to .rel.prefix.text.
1011f75da0c8SAlexey Lapshin         //
1012f75da0c8SAlexey Lapshin         // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
1013f75da0c8SAlexey Lapshin         // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
1014f75da0c8SAlexey Lapshin         // .rela.prefix.plt since GNU objcopy does so.
1015f75da0c8SAlexey Lapshin         const SectionBase *TargetSec = RelocSec->getSection();
1016f75da0c8SAlexey Lapshin         if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
1017f75da0c8SAlexey Lapshin           // If the relocation section comes *after* the target section, we
1018f75da0c8SAlexey Lapshin           // don't add Config.AllocSectionsPrefix because we've already added
1019f75da0c8SAlexey Lapshin           // the prefix to TargetSec->Name. Otherwise, if the relocation
1020f75da0c8SAlexey Lapshin           // section comes *before* the target section, we add the prefix.
1021f75da0c8SAlexey Lapshin           if (PrefixedSections.count(TargetSec))
1022f75da0c8SAlexey Lapshin             Sec.Name = (RelocSec->getNamePrefix() + TargetSec->Name).str();
1023f75da0c8SAlexey Lapshin           else
1024f75da0c8SAlexey Lapshin             Sec.Name = (RelocSec->getNamePrefix() + Config.AllocSectionsPrefix +
1025f75da0c8SAlexey Lapshin                         TargetSec->Name)
1026f75da0c8SAlexey Lapshin                            .str();
1027f75da0c8SAlexey Lapshin         }
1028f75da0c8SAlexey Lapshin       }
1029f75da0c8SAlexey Lapshin     }
1030f75da0c8SAlexey Lapshin   }
1031f75da0c8SAlexey Lapshin 
1032f75da0c8SAlexey Lapshin   if (ELFConfig.EntryExpr)
1033f75da0c8SAlexey Lapshin     Obj.Entry = ELFConfig.EntryExpr(Obj.Entry);
1034f75da0c8SAlexey Lapshin   return Error::success();
1035f75da0c8SAlexey Lapshin }
1036f75da0c8SAlexey Lapshin 
1037f75da0c8SAlexey Lapshin static Error writeOutput(const CommonConfig &Config, Object &Obj,
1038f75da0c8SAlexey Lapshin                          raw_ostream &Out, ElfType OutputElfType) {
1039f75da0c8SAlexey Lapshin   std::unique_ptr<Writer> Writer =
1040f75da0c8SAlexey Lapshin       createWriter(Config, Obj, Out, OutputElfType);
1041f75da0c8SAlexey Lapshin   if (Error E = Writer->finalize())
1042f75da0c8SAlexey Lapshin     return E;
1043f75da0c8SAlexey Lapshin   return Writer->write();
1044f75da0c8SAlexey Lapshin }
1045f75da0c8SAlexey Lapshin 
1046f75da0c8SAlexey Lapshin Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
1047f75da0c8SAlexey Lapshin                                          const ELFConfig &ELFConfig,
1048f75da0c8SAlexey Lapshin                                          MemoryBuffer &In, raw_ostream &Out) {
1049f75da0c8SAlexey Lapshin   IHexReader Reader(&In);
1050f75da0c8SAlexey Lapshin   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
1051f75da0c8SAlexey Lapshin   if (!Obj)
1052f75da0c8SAlexey Lapshin     return Obj.takeError();
1053f75da0c8SAlexey Lapshin 
1054f75da0c8SAlexey Lapshin   const ElfType OutputElfType =
1055129b531cSKazu Hirata       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
1056fb5a38bbSserge-sans-paille   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1057f75da0c8SAlexey Lapshin     return E;
1058f75da0c8SAlexey Lapshin   return writeOutput(Config, **Obj, Out, OutputElfType);
1059f75da0c8SAlexey Lapshin }
1060f75da0c8SAlexey Lapshin 
1061f75da0c8SAlexey Lapshin Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
1062f75da0c8SAlexey Lapshin                                               const ELFConfig &ELFConfig,
1063f75da0c8SAlexey Lapshin                                               MemoryBuffer &In,
1064f75da0c8SAlexey Lapshin                                               raw_ostream &Out) {
1065f75da0c8SAlexey Lapshin   BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);
1066f75da0c8SAlexey Lapshin   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
1067f75da0c8SAlexey Lapshin   if (!Obj)
1068f75da0c8SAlexey Lapshin     return Obj.takeError();
1069f75da0c8SAlexey Lapshin 
1070f75da0c8SAlexey Lapshin   // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
1071f75da0c8SAlexey Lapshin   // (-B<arch>).
1072f75da0c8SAlexey Lapshin   const ElfType OutputElfType =
1073129b531cSKazu Hirata       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
1074fb5a38bbSserge-sans-paille   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1075f75da0c8SAlexey Lapshin     return E;
1076f75da0c8SAlexey Lapshin   return writeOutput(Config, **Obj, Out, OutputElfType);
1077f75da0c8SAlexey Lapshin }
1078f75da0c8SAlexey Lapshin 
1079f75da0c8SAlexey Lapshin Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
1080f75da0c8SAlexey Lapshin                                            const ELFConfig &ELFConfig,
1081f75da0c8SAlexey Lapshin                                            object::ELFObjectFileBase &In,
1082f75da0c8SAlexey Lapshin                                            raw_ostream &Out) {
1083f75da0c8SAlexey Lapshin   ELFReader Reader(&In, Config.ExtractPartition);
1084f75da0c8SAlexey Lapshin   Expected<std::unique_ptr<Object>> Obj =
1085f75da0c8SAlexey Lapshin       Reader.create(!Config.SymbolsToAdd.empty());
1086f75da0c8SAlexey Lapshin   if (!Obj)
1087f75da0c8SAlexey Lapshin     return Obj.takeError();
1088f75da0c8SAlexey Lapshin   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
108967ba5c50SFangrui Song   const ElfType OutputElfType = Config.OutputArch
109067ba5c50SFangrui Song                                     ? getOutputElfType(*Config.OutputArch)
1091f75da0c8SAlexey Lapshin                                     : getOutputElfType(In);
1092f75da0c8SAlexey Lapshin 
1093fb5a38bbSserge-sans-paille   if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
1094f75da0c8SAlexey Lapshin     return createFileError(Config.InputFilename, std::move(E));
1095f75da0c8SAlexey Lapshin 
1096f75da0c8SAlexey Lapshin   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
1097f75da0c8SAlexey Lapshin     return createFileError(Config.InputFilename, std::move(E));
1098f75da0c8SAlexey Lapshin 
1099f75da0c8SAlexey Lapshin   return Error::success();
1100f75da0c8SAlexey Lapshin }
1101