xref: /llvm-project/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp (revision 334a5766d7591bfaadf6990b3d8568c9688e22a5)
1f75da0c8SAlexey Lapshin //===- MachOObjcopy.cpp -----------------------------------------*- C++ -*-===//
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/MachO/MachOObjcopy.h"
10f75da0c8SAlexey Lapshin #include "Archive.h"
11f75da0c8SAlexey Lapshin #include "MachOReader.h"
12f75da0c8SAlexey Lapshin #include "MachOWriter.h"
13f75da0c8SAlexey Lapshin #include "llvm/ADT/DenseSet.h"
14f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/CommonConfig.h"
15f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/MachO/MachOConfig.h"
16f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/MultiFormatConfig.h"
17f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/ObjCopy.h"
18f75da0c8SAlexey Lapshin #include "llvm/Object/ArchiveWriter.h"
19f75da0c8SAlexey Lapshin #include "llvm/Object/MachOUniversal.h"
20f75da0c8SAlexey Lapshin #include "llvm/Object/MachOUniversalWriter.h"
21f75da0c8SAlexey Lapshin #include "llvm/Support/Errc.h"
22f75da0c8SAlexey Lapshin #include "llvm/Support/Error.h"
23f75da0c8SAlexey Lapshin #include "llvm/Support/FileOutputBuffer.h"
24f75da0c8SAlexey Lapshin #include "llvm/Support/Path.h"
25f75da0c8SAlexey Lapshin #include "llvm/Support/SmallVectorMemoryBuffer.h"
26f75da0c8SAlexey Lapshin 
27f75da0c8SAlexey Lapshin using namespace llvm;
28f75da0c8SAlexey Lapshin using namespace llvm::objcopy;
29f75da0c8SAlexey Lapshin using namespace llvm::objcopy::macho;
30f75da0c8SAlexey Lapshin using namespace llvm::object;
31f75da0c8SAlexey Lapshin 
32f75da0c8SAlexey Lapshin using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
33f75da0c8SAlexey Lapshin using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
34f75da0c8SAlexey Lapshin 
35f75da0c8SAlexey Lapshin #ifndef NDEBUG
36f75da0c8SAlexey Lapshin static bool isLoadCommandWithPayloadString(const LoadCommand &LC) {
37f75da0c8SAlexey Lapshin   // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
38f75da0c8SAlexey Lapshin   // LC_LAZY_LOAD_DYLIB
39f75da0c8SAlexey Lapshin   return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH ||
40f75da0c8SAlexey Lapshin          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB ||
41f75da0c8SAlexey Lapshin          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB ||
42f75da0c8SAlexey Lapshin          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB;
43f75da0c8SAlexey Lapshin }
44f75da0c8SAlexey Lapshin #endif
45f75da0c8SAlexey Lapshin 
46f75da0c8SAlexey Lapshin static StringRef getPayloadString(const LoadCommand &LC) {
47f75da0c8SAlexey Lapshin   assert(isLoadCommandWithPayloadString(LC) &&
48f75da0c8SAlexey Lapshin          "unsupported load command encountered");
49f75da0c8SAlexey Lapshin 
50f75da0c8SAlexey Lapshin   return StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
51f75da0c8SAlexey Lapshin                    LC.Payload.size())
52f75da0c8SAlexey Lapshin       .rtrim('\0');
53f75da0c8SAlexey Lapshin }
54f75da0c8SAlexey Lapshin 
55f75da0c8SAlexey Lapshin static Error removeSections(const CommonConfig &Config, Object &Obj) {
56f75da0c8SAlexey Lapshin   SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
57f75da0c8SAlexey Lapshin     return false;
58f75da0c8SAlexey Lapshin   };
59f75da0c8SAlexey Lapshin 
60f75da0c8SAlexey Lapshin   if (!Config.ToRemove.empty()) {
61f75da0c8SAlexey Lapshin     RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) {
62f75da0c8SAlexey Lapshin       return Config.ToRemove.matches(Sec->CanonicalName);
63f75da0c8SAlexey Lapshin     };
64f75da0c8SAlexey Lapshin   }
65f75da0c8SAlexey Lapshin 
66f75da0c8SAlexey Lapshin   if (Config.StripAll || Config.StripDebug) {
67f75da0c8SAlexey Lapshin     // Remove all debug sections.
68f75da0c8SAlexey Lapshin     RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) {
69f75da0c8SAlexey Lapshin       if (Sec->Segname == "__DWARF")
70f75da0c8SAlexey Lapshin         return true;
71f75da0c8SAlexey Lapshin 
72f75da0c8SAlexey Lapshin       return RemovePred(Sec);
73f75da0c8SAlexey Lapshin     };
74f75da0c8SAlexey Lapshin   }
75f75da0c8SAlexey Lapshin 
76f75da0c8SAlexey Lapshin   if (!Config.OnlySection.empty()) {
77f75da0c8SAlexey Lapshin     // Overwrite RemovePred because --only-section takes priority.
78f75da0c8SAlexey Lapshin     RemovePred = [&Config](const std::unique_ptr<Section> &Sec) {
79f75da0c8SAlexey Lapshin       return !Config.OnlySection.matches(Sec->CanonicalName);
80f75da0c8SAlexey Lapshin     };
81f75da0c8SAlexey Lapshin   }
82f75da0c8SAlexey Lapshin 
83f75da0c8SAlexey Lapshin   return Obj.removeSections(RemovePred);
84f75da0c8SAlexey Lapshin }
85f75da0c8SAlexey Lapshin 
86f75da0c8SAlexey Lapshin static void markSymbols(const CommonConfig &, Object &Obj) {
87f75da0c8SAlexey Lapshin   // Symbols referenced from the indirect symbol table must not be removed.
88f75da0c8SAlexey Lapshin   for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
89f75da0c8SAlexey Lapshin     if (ISE.Symbol)
90f75da0c8SAlexey Lapshin       (*ISE.Symbol)->Referenced = true;
91f75da0c8SAlexey Lapshin }
92f75da0c8SAlexey Lapshin 
93f75da0c8SAlexey Lapshin static void updateAndRemoveSymbols(const CommonConfig &Config,
94f75da0c8SAlexey Lapshin                                    const MachOConfig &MachOConfig,
95f75da0c8SAlexey Lapshin                                    Object &Obj) {
96*334a5766SRichard Dzenis   Obj.SymTable.updateSymbols([&](SymbolEntry &Sym) {
97*334a5766SRichard Dzenis     if (Config.SymbolsToSkip.matches(Sym.Name))
98*334a5766SRichard Dzenis       return;
99*334a5766SRichard Dzenis 
100*334a5766SRichard Dzenis     if (!Sym.isUndefinedSymbol() && Config.SymbolsToLocalize.matches(Sym.Name))
101*334a5766SRichard Dzenis       Sym.n_type &= ~MachO::N_EXT;
102*334a5766SRichard Dzenis 
103*334a5766SRichard Dzenis     // Note: these two globalize flags have very similar names but different
104*334a5766SRichard Dzenis     // meanings:
105*334a5766SRichard Dzenis     //
106*334a5766SRichard Dzenis     // --globalize-symbol: promote a symbol to global
107*334a5766SRichard Dzenis     // --keep-global-symbol: all symbols except for these should be made local
108*334a5766SRichard Dzenis     //
109*334a5766SRichard Dzenis     // If --globalize-symbol is specified for a given symbol, it will be
110*334a5766SRichard Dzenis     // global in the output file even if it is not included via
111*334a5766SRichard Dzenis     // --keep-global-symbol. Because of that, make sure to check
112*334a5766SRichard Dzenis     // --globalize-symbol second.
113*334a5766SRichard Dzenis     if (!Sym.isUndefinedSymbol() && !Config.SymbolsToKeepGlobal.empty() &&
114*334a5766SRichard Dzenis         !Config.SymbolsToKeepGlobal.matches(Sym.Name))
115*334a5766SRichard Dzenis       Sym.n_type &= ~MachO::N_EXT;
116*334a5766SRichard Dzenis 
117*334a5766SRichard Dzenis     if (!Sym.isUndefinedSymbol() && Config.SymbolsToGlobalize.matches(Sym.Name))
118*334a5766SRichard Dzenis       Sym.n_type |= MachO::N_EXT;
119*334a5766SRichard Dzenis 
120*334a5766SRichard Dzenis     if (Sym.isExternalSymbol() && !Sym.isUndefinedSymbol() &&
1210807846aSDan Zimmerman         (Config.Weaken || Config.SymbolsToWeaken.matches(Sym.Name)))
122*334a5766SRichard Dzenis       Sym.n_desc |= MachO::N_WEAK_DEF;
1230807846aSDan Zimmerman 
124f75da0c8SAlexey Lapshin     auto I = Config.SymbolsToRename.find(Sym.Name);
125f75da0c8SAlexey Lapshin     if (I != Config.SymbolsToRename.end())
126f75da0c8SAlexey Lapshin       Sym.Name = std::string(I->getValue());
127*334a5766SRichard Dzenis   });
128f75da0c8SAlexey Lapshin 
129a6f3fedcSAlexey Lapshin   auto RemovePred = [&Config, &MachOConfig,
130f75da0c8SAlexey Lapshin                      &Obj](const std::unique_ptr<SymbolEntry> &N) {
131f75da0c8SAlexey Lapshin     if (N->Referenced)
132f75da0c8SAlexey Lapshin       return false;
133f75da0c8SAlexey Lapshin     if (MachOConfig.KeepUndefined && N->isUndefinedSymbol())
134f75da0c8SAlexey Lapshin       return false;
135f75da0c8SAlexey Lapshin     if (N->n_desc & MachO::REFERENCED_DYNAMICALLY)
136f75da0c8SAlexey Lapshin       return false;
137f75da0c8SAlexey Lapshin     if (Config.StripAll)
138f75da0c8SAlexey Lapshin       return true;
139f75da0c8SAlexey Lapshin     if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
140f75da0c8SAlexey Lapshin       return true;
141f75da0c8SAlexey Lapshin     // This behavior is consistent with cctools' strip.
14257dc16fbSMike Hommey     if (Config.StripDebug && (N->n_type & MachO::N_STAB))
14357dc16fbSMike Hommey       return true;
14457dc16fbSMike Hommey     // This behavior is consistent with cctools' strip.
145f75da0c8SAlexey Lapshin     if (MachOConfig.StripSwiftSymbols &&
146f75da0c8SAlexey Lapshin         (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion &&
147f75da0c8SAlexey Lapshin         *Obj.SwiftVersion && N->isSwiftSymbol())
148f75da0c8SAlexey Lapshin       return true;
149f75da0c8SAlexey Lapshin     return false;
150f75da0c8SAlexey Lapshin   };
151f75da0c8SAlexey Lapshin 
152f75da0c8SAlexey Lapshin   Obj.SymTable.removeSymbols(RemovePred);
153f75da0c8SAlexey Lapshin }
154f75da0c8SAlexey Lapshin 
155f75da0c8SAlexey Lapshin template <typename LCType>
156f75da0c8SAlexey Lapshin static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
157f75da0c8SAlexey Lapshin   assert(isLoadCommandWithPayloadString(LC) &&
158f75da0c8SAlexey Lapshin          "unsupported load command encountered");
159f75da0c8SAlexey Lapshin 
160f75da0c8SAlexey Lapshin   uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
161f75da0c8SAlexey Lapshin 
162f75da0c8SAlexey Lapshin   LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
163f75da0c8SAlexey Lapshin   LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
164f75da0c8SAlexey Lapshin   std::copy(S.begin(), S.end(), LC.Payload.begin());
165f75da0c8SAlexey Lapshin }
166f75da0c8SAlexey Lapshin 
167f75da0c8SAlexey Lapshin static LoadCommand buildRPathLoadCommand(StringRef Path) {
168f75da0c8SAlexey Lapshin   LoadCommand LC;
169f75da0c8SAlexey Lapshin   MachO::rpath_command RPathLC;
170f75da0c8SAlexey Lapshin   RPathLC.cmd = MachO::LC_RPATH;
171f75da0c8SAlexey Lapshin   RPathLC.path = sizeof(MachO::rpath_command);
172f75da0c8SAlexey Lapshin   RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
173f75da0c8SAlexey Lapshin   LC.MachOLoadCommand.rpath_command_data = RPathLC;
174f75da0c8SAlexey Lapshin   LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
175f75da0c8SAlexey Lapshin   std::copy(Path.begin(), Path.end(), LC.Payload.begin());
176f75da0c8SAlexey Lapshin   return LC;
177f75da0c8SAlexey Lapshin }
178f75da0c8SAlexey Lapshin 
179f75da0c8SAlexey Lapshin static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) {
180f75da0c8SAlexey Lapshin   // Remove RPaths.
181f75da0c8SAlexey Lapshin   DenseSet<StringRef> RPathsToRemove(MachOConfig.RPathsToRemove.begin(),
182f75da0c8SAlexey Lapshin                                      MachOConfig.RPathsToRemove.end());
183f75da0c8SAlexey Lapshin 
184f75da0c8SAlexey Lapshin   LoadCommandPred RemovePred = [&RPathsToRemove,
185f75da0c8SAlexey Lapshin                                 &MachOConfig](const LoadCommand &LC) {
186f75da0c8SAlexey Lapshin     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
187f75da0c8SAlexey Lapshin       // When removing all RPaths we don't need to care
188f75da0c8SAlexey Lapshin       // about what it contains
189f75da0c8SAlexey Lapshin       if (MachOConfig.RemoveAllRpaths)
190f75da0c8SAlexey Lapshin         return true;
191f75da0c8SAlexey Lapshin 
192f75da0c8SAlexey Lapshin       StringRef RPath = getPayloadString(LC);
193f75da0c8SAlexey Lapshin       if (RPathsToRemove.count(RPath)) {
194f75da0c8SAlexey Lapshin         RPathsToRemove.erase(RPath);
195f75da0c8SAlexey Lapshin         return true;
196f75da0c8SAlexey Lapshin       }
197f75da0c8SAlexey Lapshin     }
198f75da0c8SAlexey Lapshin     return false;
199f75da0c8SAlexey Lapshin   };
200f75da0c8SAlexey Lapshin 
201f75da0c8SAlexey Lapshin   if (Error E = Obj.removeLoadCommands(RemovePred))
202f75da0c8SAlexey Lapshin     return E;
203f75da0c8SAlexey Lapshin 
204f75da0c8SAlexey Lapshin   // Emit an error if the Mach-O binary does not contain an rpath path name
205f75da0c8SAlexey Lapshin   // specified in -delete_rpath.
206f75da0c8SAlexey Lapshin   for (StringRef RPath : MachOConfig.RPathsToRemove) {
207f75da0c8SAlexey Lapshin     if (RPathsToRemove.count(RPath))
208f75da0c8SAlexey Lapshin       return createStringError(errc::invalid_argument,
209f75da0c8SAlexey Lapshin                                "no LC_RPATH load command with path: %s",
210f75da0c8SAlexey Lapshin                                RPath.str().c_str());
211f75da0c8SAlexey Lapshin   }
212f75da0c8SAlexey Lapshin 
213f75da0c8SAlexey Lapshin   DenseSet<StringRef> RPaths;
214f75da0c8SAlexey Lapshin 
215f75da0c8SAlexey Lapshin   // Get all existing RPaths.
216f75da0c8SAlexey Lapshin   for (LoadCommand &LC : Obj.LoadCommands) {
217f75da0c8SAlexey Lapshin     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
218f75da0c8SAlexey Lapshin       RPaths.insert(getPayloadString(LC));
219f75da0c8SAlexey Lapshin   }
220f75da0c8SAlexey Lapshin 
221f75da0c8SAlexey Lapshin   // Throw errors for invalid RPaths.
222f75da0c8SAlexey Lapshin   for (const auto &OldNew : MachOConfig.RPathsToUpdate) {
223f75da0c8SAlexey Lapshin     StringRef Old = OldNew.getFirst();
224f75da0c8SAlexey Lapshin     StringRef New = OldNew.getSecond();
225f75da0c8SAlexey Lapshin     if (!RPaths.contains(Old))
226f75da0c8SAlexey Lapshin       return createStringError(errc::invalid_argument,
227f75da0c8SAlexey Lapshin                                "no LC_RPATH load command with path: " + Old);
228f75da0c8SAlexey Lapshin     if (RPaths.contains(New))
229f75da0c8SAlexey Lapshin       return createStringError(errc::invalid_argument,
230f75da0c8SAlexey Lapshin                                "rpath '" + New +
231f75da0c8SAlexey Lapshin                                    "' would create a duplicate load command");
232f75da0c8SAlexey Lapshin   }
233f75da0c8SAlexey Lapshin 
234f75da0c8SAlexey Lapshin   // Update load commands.
235f75da0c8SAlexey Lapshin   for (LoadCommand &LC : Obj.LoadCommands) {
236f75da0c8SAlexey Lapshin     switch (LC.MachOLoadCommand.load_command_data.cmd) {
237f75da0c8SAlexey Lapshin     case MachO::LC_ID_DYLIB:
238f75da0c8SAlexey Lapshin       if (MachOConfig.SharedLibId)
239f75da0c8SAlexey Lapshin         updateLoadCommandPayloadString<MachO::dylib_command>(
240f75da0c8SAlexey Lapshin             LC, *MachOConfig.SharedLibId);
241f75da0c8SAlexey Lapshin       break;
242f75da0c8SAlexey Lapshin 
243f75da0c8SAlexey Lapshin     case MachO::LC_RPATH: {
244f75da0c8SAlexey Lapshin       StringRef RPath = getPayloadString(LC);
245f75da0c8SAlexey Lapshin       StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath);
246f75da0c8SAlexey Lapshin       if (!NewRPath.empty())
247f75da0c8SAlexey Lapshin         updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
248f75da0c8SAlexey Lapshin       break;
249f75da0c8SAlexey Lapshin     }
250f75da0c8SAlexey Lapshin 
251f75da0c8SAlexey Lapshin     // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
252f75da0c8SAlexey Lapshin     // here once llvm-objcopy supports them.
253f75da0c8SAlexey Lapshin     case MachO::LC_LOAD_DYLIB:
254f75da0c8SAlexey Lapshin     case MachO::LC_LOAD_WEAK_DYLIB:
255f75da0c8SAlexey Lapshin       StringRef InstallName = getPayloadString(LC);
256f75da0c8SAlexey Lapshin       StringRef NewInstallName =
257f75da0c8SAlexey Lapshin           MachOConfig.InstallNamesToUpdate.lookup(InstallName);
258f75da0c8SAlexey Lapshin       if (!NewInstallName.empty())
259f75da0c8SAlexey Lapshin         updateLoadCommandPayloadString<MachO::dylib_command>(LC,
260f75da0c8SAlexey Lapshin                                                              NewInstallName);
261f75da0c8SAlexey Lapshin       break;
262f75da0c8SAlexey Lapshin     }
263f75da0c8SAlexey Lapshin   }
264f75da0c8SAlexey Lapshin 
265f75da0c8SAlexey Lapshin   // Add new RPaths.
266f75da0c8SAlexey Lapshin   for (StringRef RPath : MachOConfig.RPathToAdd) {
267f75da0c8SAlexey Lapshin     if (RPaths.contains(RPath))
268f75da0c8SAlexey Lapshin       return createStringError(errc::invalid_argument,
269f75da0c8SAlexey Lapshin                                "rpath '" + RPath +
270f75da0c8SAlexey Lapshin                                    "' would create a duplicate load command");
271f75da0c8SAlexey Lapshin     RPaths.insert(RPath);
272f75da0c8SAlexey Lapshin     Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
273f75da0c8SAlexey Lapshin   }
274f75da0c8SAlexey Lapshin 
275f75da0c8SAlexey Lapshin   for (StringRef RPath : MachOConfig.RPathToPrepend) {
276f75da0c8SAlexey Lapshin     if (RPaths.contains(RPath))
277f75da0c8SAlexey Lapshin       return createStringError(errc::invalid_argument,
278f75da0c8SAlexey Lapshin                                "rpath '" + RPath +
279f75da0c8SAlexey Lapshin                                    "' would create a duplicate load command");
280f75da0c8SAlexey Lapshin 
281f75da0c8SAlexey Lapshin     RPaths.insert(RPath);
282f75da0c8SAlexey Lapshin     Obj.LoadCommands.insert(Obj.LoadCommands.begin(),
283f75da0c8SAlexey Lapshin                             buildRPathLoadCommand(RPath));
284f75da0c8SAlexey Lapshin   }
285f75da0c8SAlexey Lapshin 
286f75da0c8SAlexey Lapshin   // Unlike appending rpaths, the indexes of subsequent load commands must
287f75da0c8SAlexey Lapshin   // be recalculated after prepending one.
288f75da0c8SAlexey Lapshin   if (!MachOConfig.RPathToPrepend.empty())
289f75da0c8SAlexey Lapshin     Obj.updateLoadCommandIndexes();
290f75da0c8SAlexey Lapshin 
29159172194SRichard Howell   // Remove any empty segments if required.
29259172194SRichard Howell   if (!MachOConfig.EmptySegmentsToRemove.empty()) {
29359172194SRichard Howell     auto RemovePred = [&MachOConfig](const LoadCommand &LC) {
29459172194SRichard Howell       if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 ||
29559172194SRichard Howell           LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) {
29659172194SRichard Howell         return LC.Sections.empty() &&
2977a47ee51SKazu Hirata                MachOConfig.EmptySegmentsToRemove.contains(*LC.getSegmentName());
29859172194SRichard Howell       }
29959172194SRichard Howell       return false;
30059172194SRichard Howell     };
30159172194SRichard Howell     if (Error E = Obj.removeLoadCommands(RemovePred))
30259172194SRichard Howell       return E;
30359172194SRichard Howell   }
30459172194SRichard Howell 
305f75da0c8SAlexey Lapshin   return Error::success();
306f75da0c8SAlexey Lapshin }
307f75da0c8SAlexey Lapshin 
308f75da0c8SAlexey Lapshin static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
309f75da0c8SAlexey Lapshin                                Object &Obj) {
310f75da0c8SAlexey Lapshin   for (LoadCommand &LC : Obj.LoadCommands)
311f75da0c8SAlexey Lapshin     for (const std::unique_ptr<Section> &Sec : LC.Sections) {
312f75da0c8SAlexey Lapshin       if (Sec->CanonicalName == SecName) {
313f75da0c8SAlexey Lapshin         Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
314f75da0c8SAlexey Lapshin             FileOutputBuffer::create(Filename, Sec->Content.size());
315f75da0c8SAlexey Lapshin         if (!BufferOrErr)
316f75da0c8SAlexey Lapshin           return BufferOrErr.takeError();
317f75da0c8SAlexey Lapshin         std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
318f75da0c8SAlexey Lapshin         llvm::copy(Sec->Content, Buf->getBufferStart());
319f75da0c8SAlexey Lapshin 
320f75da0c8SAlexey Lapshin         if (Error E = Buf->commit())
321f75da0c8SAlexey Lapshin           return E;
322f75da0c8SAlexey Lapshin         return Error::success();
323f75da0c8SAlexey Lapshin       }
324f75da0c8SAlexey Lapshin     }
325f75da0c8SAlexey Lapshin 
326f75da0c8SAlexey Lapshin   return createStringError(object_error::parse_failed, "section '%s' not found",
327f75da0c8SAlexey Lapshin                            SecName.str().c_str());
328f75da0c8SAlexey Lapshin }
329f75da0c8SAlexey Lapshin 
330a6f3fedcSAlexey Lapshin static Error addSection(const NewSectionInfo &NewSection, Object &Obj) {
331a6f3fedcSAlexey Lapshin   std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(',');
332f75da0c8SAlexey Lapshin   StringRef TargetSegName = Pair.first;
333f75da0c8SAlexey Lapshin   Section Sec(TargetSegName, Pair.second);
334a6f3fedcSAlexey Lapshin   Sec.Content =
335a6f3fedcSAlexey Lapshin       Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer());
336f75da0c8SAlexey Lapshin   Sec.Size = Sec.Content.size();
337f75da0c8SAlexey Lapshin 
338f75da0c8SAlexey Lapshin   // Add the a section into an existing segment.
339f75da0c8SAlexey Lapshin   for (LoadCommand &LC : Obj.LoadCommands) {
340ec941432SFangrui Song     std::optional<StringRef> SegName = LC.getSegmentName();
341f75da0c8SAlexey Lapshin     if (SegName && SegName == TargetSegName) {
342f75da0c8SAlexey Lapshin       uint64_t Addr = *LC.getSegmentVMAddr();
343f75da0c8SAlexey Lapshin       for (const std::unique_ptr<Section> &S : LC.Sections)
344f75da0c8SAlexey Lapshin         Addr = std::max(Addr, S->Addr + S->Size);
345f75da0c8SAlexey Lapshin       LC.Sections.push_back(std::make_unique<Section>(Sec));
346f75da0c8SAlexey Lapshin       LC.Sections.back()->Addr = Addr;
347f75da0c8SAlexey Lapshin       return Error::success();
348f75da0c8SAlexey Lapshin     }
349f75da0c8SAlexey Lapshin   }
350f75da0c8SAlexey Lapshin 
351f75da0c8SAlexey Lapshin   // There's no segment named TargetSegName. Create a new load command and
352f75da0c8SAlexey Lapshin   // Insert a new section into it.
353f75da0c8SAlexey Lapshin   LoadCommand &NewSegment =
354f75da0c8SAlexey Lapshin       Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
355f75da0c8SAlexey Lapshin   NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
356f75da0c8SAlexey Lapshin   NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
357f75da0c8SAlexey Lapshin   return Error::success();
358f75da0c8SAlexey Lapshin }
359f75da0c8SAlexey Lapshin 
360f75da0c8SAlexey Lapshin static Expected<Section &> findSection(StringRef SecName, Object &O) {
361f75da0c8SAlexey Lapshin   StringRef SegName;
362f75da0c8SAlexey Lapshin   std::tie(SegName, SecName) = SecName.split(",");
363f75da0c8SAlexey Lapshin   auto FoundSeg =
364f75da0c8SAlexey Lapshin       llvm::find_if(O.LoadCommands, [SegName](const LoadCommand &LC) {
365f75da0c8SAlexey Lapshin         return LC.getSegmentName() == SegName;
366f75da0c8SAlexey Lapshin       });
367f75da0c8SAlexey Lapshin   if (FoundSeg == O.LoadCommands.end())
368f75da0c8SAlexey Lapshin     return createStringError(errc::invalid_argument,
369f75da0c8SAlexey Lapshin                              "could not find segment with name '%s'",
370f75da0c8SAlexey Lapshin                              SegName.str().c_str());
371f75da0c8SAlexey Lapshin   auto FoundSec = llvm::find_if(FoundSeg->Sections,
372f75da0c8SAlexey Lapshin                                 [SecName](const std::unique_ptr<Section> &Sec) {
373f75da0c8SAlexey Lapshin                                   return Sec->Sectname == SecName;
374f75da0c8SAlexey Lapshin                                 });
375f75da0c8SAlexey Lapshin   if (FoundSec == FoundSeg->Sections.end())
376f75da0c8SAlexey Lapshin     return createStringError(errc::invalid_argument,
377f75da0c8SAlexey Lapshin                              "could not find section with name '%s'",
378f75da0c8SAlexey Lapshin                              SecName.str().c_str());
379f75da0c8SAlexey Lapshin 
380f75da0c8SAlexey Lapshin   assert(FoundSec->get()->CanonicalName == (SegName + "," + SecName).str());
381d22f050eSGregory Alfonso   return **FoundSec;
382f75da0c8SAlexey Lapshin }
383f75da0c8SAlexey Lapshin 
384a6f3fedcSAlexey Lapshin static Error updateSection(const NewSectionInfo &NewSection, Object &O) {
385a6f3fedcSAlexey Lapshin   Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O);
386f75da0c8SAlexey Lapshin 
387f75da0c8SAlexey Lapshin   if (!SecToUpdateOrErr)
388f75da0c8SAlexey Lapshin     return SecToUpdateOrErr.takeError();
389f75da0c8SAlexey Lapshin   Section &Sec = *SecToUpdateOrErr;
390f75da0c8SAlexey Lapshin 
391a6f3fedcSAlexey Lapshin   if (NewSection.SectionData->getBufferSize() > Sec.Size)
392f75da0c8SAlexey Lapshin     return createStringError(
393f75da0c8SAlexey Lapshin         errc::invalid_argument,
394f75da0c8SAlexey Lapshin         "new section cannot be larger than previous section");
395a6f3fedcSAlexey Lapshin   Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer());
396f75da0c8SAlexey Lapshin   Sec.Size = Sec.Content.size();
397f75da0c8SAlexey Lapshin   return Error::success();
398f75da0c8SAlexey Lapshin }
399f75da0c8SAlexey Lapshin 
400f75da0c8SAlexey Lapshin // isValidMachOCannonicalName returns success if Name is a MachO cannonical name
401f75da0c8SAlexey Lapshin // ("<segment>,<section>") and lengths of both segment and section names are
402f75da0c8SAlexey Lapshin // valid.
403f75da0c8SAlexey Lapshin static Error isValidMachOCannonicalName(StringRef Name) {
404f75da0c8SAlexey Lapshin   if (Name.count(',') != 1)
405f75da0c8SAlexey Lapshin     return createStringError(errc::invalid_argument,
406f75da0c8SAlexey Lapshin                              "invalid section name '%s' (should be formatted "
407f75da0c8SAlexey Lapshin                              "as '<segment name>,<section name>')",
408f75da0c8SAlexey Lapshin                              Name.str().c_str());
409f75da0c8SAlexey Lapshin 
410f75da0c8SAlexey Lapshin   std::pair<StringRef, StringRef> Pair = Name.split(',');
411f75da0c8SAlexey Lapshin   if (Pair.first.size() > 16)
412f75da0c8SAlexey Lapshin     return createStringError(errc::invalid_argument,
413f75da0c8SAlexey Lapshin                              "too long segment name: '%s'",
414f75da0c8SAlexey Lapshin                              Pair.first.str().c_str());
415f75da0c8SAlexey Lapshin   if (Pair.second.size() > 16)
416f75da0c8SAlexey Lapshin     return createStringError(errc::invalid_argument,
417f75da0c8SAlexey Lapshin                              "too long section name: '%s'",
418f75da0c8SAlexey Lapshin                              Pair.second.str().c_str());
419f75da0c8SAlexey Lapshin   return Error::success();
420f75da0c8SAlexey Lapshin }
421f75da0c8SAlexey Lapshin 
422f75da0c8SAlexey Lapshin static Error handleArgs(const CommonConfig &Config,
423f75da0c8SAlexey Lapshin                         const MachOConfig &MachOConfig, Object &Obj) {
424f75da0c8SAlexey Lapshin   // Dump sections before add/remove for compatibility with GNU objcopy.
425f75da0c8SAlexey Lapshin   for (StringRef Flag : Config.DumpSection) {
426f75da0c8SAlexey Lapshin     StringRef SectionName;
427f75da0c8SAlexey Lapshin     StringRef FileName;
428f75da0c8SAlexey Lapshin     std::tie(SectionName, FileName) = Flag.split('=');
429f75da0c8SAlexey Lapshin     if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
430f75da0c8SAlexey Lapshin       return E;
431f75da0c8SAlexey Lapshin   }
432f75da0c8SAlexey Lapshin 
433f75da0c8SAlexey Lapshin   if (Error E = removeSections(Config, Obj))
434f75da0c8SAlexey Lapshin     return E;
435f75da0c8SAlexey Lapshin 
436f75da0c8SAlexey Lapshin   // Mark symbols to determine which symbols are still needed.
437f75da0c8SAlexey Lapshin   if (Config.StripAll)
438f75da0c8SAlexey Lapshin     markSymbols(Config, Obj);
439f75da0c8SAlexey Lapshin 
440f75da0c8SAlexey Lapshin   updateAndRemoveSymbols(Config, MachOConfig, Obj);
441f75da0c8SAlexey Lapshin 
442f75da0c8SAlexey Lapshin   if (Config.StripAll)
443f75da0c8SAlexey Lapshin     for (LoadCommand &LC : Obj.LoadCommands)
444f75da0c8SAlexey Lapshin       for (std::unique_ptr<Section> &Sec : LC.Sections)
445f75da0c8SAlexey Lapshin         Sec->Relocations.clear();
446f75da0c8SAlexey Lapshin 
447a6f3fedcSAlexey Lapshin   for (const NewSectionInfo &NewSection : Config.AddSection) {
448a6f3fedcSAlexey Lapshin     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
449f75da0c8SAlexey Lapshin       return E;
450a6f3fedcSAlexey Lapshin     if (Error E = addSection(NewSection, Obj))
451f75da0c8SAlexey Lapshin       return E;
452f75da0c8SAlexey Lapshin   }
453f75da0c8SAlexey Lapshin 
454a6f3fedcSAlexey Lapshin   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
455a6f3fedcSAlexey Lapshin     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
456f75da0c8SAlexey Lapshin       return E;
457a6f3fedcSAlexey Lapshin     if (Error E = updateSection(NewSection, Obj))
458f75da0c8SAlexey Lapshin       return E;
459f75da0c8SAlexey Lapshin   }
460f75da0c8SAlexey Lapshin 
461f75da0c8SAlexey Lapshin   if (Error E = processLoadCommands(MachOConfig, Obj))
462f75da0c8SAlexey Lapshin     return E;
463f75da0c8SAlexey Lapshin 
464f75da0c8SAlexey Lapshin   return Error::success();
465f75da0c8SAlexey Lapshin }
466f75da0c8SAlexey Lapshin 
467f75da0c8SAlexey Lapshin Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
468f75da0c8SAlexey Lapshin                                              const MachOConfig &MachOConfig,
469f75da0c8SAlexey Lapshin                                              object::MachOObjectFile &In,
470f75da0c8SAlexey Lapshin                                              raw_ostream &Out) {
471f75da0c8SAlexey Lapshin   MachOReader Reader(In);
472f75da0c8SAlexey Lapshin   Expected<std::unique_ptr<Object>> O = Reader.create();
473f75da0c8SAlexey Lapshin   if (!O)
474f75da0c8SAlexey Lapshin     return createFileError(Config.InputFilename, O.takeError());
475f75da0c8SAlexey Lapshin 
476f75da0c8SAlexey Lapshin   if (O->get()->Header.FileType == MachO::HeaderFileType::MH_PRELOAD)
477f75da0c8SAlexey Lapshin     return createStringError(std::errc::not_supported,
478f75da0c8SAlexey Lapshin                              "%s: MH_PRELOAD files are not supported",
479f75da0c8SAlexey Lapshin                              Config.InputFilename.str().c_str());
480f75da0c8SAlexey Lapshin 
481f75da0c8SAlexey Lapshin   if (Error E = handleArgs(Config, MachOConfig, **O))
482f75da0c8SAlexey Lapshin     return createFileError(Config.InputFilename, std::move(E));
483f75da0c8SAlexey Lapshin 
484f75da0c8SAlexey Lapshin   // Page size used for alignment of segment sizes in Mach-O executables and
485f75da0c8SAlexey Lapshin   // dynamic libraries.
486f75da0c8SAlexey Lapshin   uint64_t PageSize;
487f75da0c8SAlexey Lapshin   switch (In.getArch()) {
488f75da0c8SAlexey Lapshin   case Triple::ArchType::arm:
489f75da0c8SAlexey Lapshin   case Triple::ArchType::aarch64:
490f75da0c8SAlexey Lapshin   case Triple::ArchType::aarch64_32:
491f75da0c8SAlexey Lapshin     PageSize = 16384;
492f75da0c8SAlexey Lapshin     break;
493f75da0c8SAlexey Lapshin   default:
494f75da0c8SAlexey Lapshin     PageSize = 4096;
495f75da0c8SAlexey Lapshin   }
496f75da0c8SAlexey Lapshin 
497f75da0c8SAlexey Lapshin   MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(),
498f75da0c8SAlexey Lapshin                      sys::path::filename(Config.OutputFilename), PageSize, Out);
499f75da0c8SAlexey Lapshin   if (auto E = Writer.finalize())
500f75da0c8SAlexey Lapshin     return E;
501f75da0c8SAlexey Lapshin   return Writer.write();
502f75da0c8SAlexey Lapshin }
503f75da0c8SAlexey Lapshin 
504f75da0c8SAlexey Lapshin Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
505f75da0c8SAlexey Lapshin     const MultiFormatConfig &Config, const MachOUniversalBinary &In,
506f75da0c8SAlexey Lapshin     raw_ostream &Out) {
507f75da0c8SAlexey Lapshin   SmallVector<OwningBinary<Binary>, 2> Binaries;
508f75da0c8SAlexey Lapshin   SmallVector<Slice, 2> Slices;
509f75da0c8SAlexey Lapshin   for (const auto &O : In.objects()) {
510f75da0c8SAlexey Lapshin     Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
511f75da0c8SAlexey Lapshin     if (ArOrErr) {
512f75da0c8SAlexey Lapshin       Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
513f75da0c8SAlexey Lapshin           createNewArchiveMembers(Config, **ArOrErr);
514f75da0c8SAlexey Lapshin       if (!NewArchiveMembersOrErr)
515f75da0c8SAlexey Lapshin         return NewArchiveMembersOrErr.takeError();
51606624305SKeith Smiley       auto Kind = (*ArOrErr)->kind();
51706624305SKeith Smiley       if (Kind == object::Archive::K_BSD)
51806624305SKeith Smiley         Kind = object::Archive::K_DARWIN;
519f75da0c8SAlexey Lapshin       Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
520f740bcb3Szhijian           writeArchiveToBuffer(
521f740bcb3Szhijian               *NewArchiveMembersOrErr,
522f740bcb3Szhijian               (*ArOrErr)->hasSymbolTable() ? SymtabWritingMode::NormalSymtab
523f740bcb3Szhijian                                            : SymtabWritingMode::NoSymtab,
524f740bcb3Szhijian               Kind, Config.getCommonConfig().DeterministicArchives,
525f75da0c8SAlexey Lapshin               (*ArOrErr)->isThin());
526f75da0c8SAlexey Lapshin       if (!OutputBufferOrErr)
527f75da0c8SAlexey Lapshin         return OutputBufferOrErr.takeError();
528f75da0c8SAlexey Lapshin       Expected<std::unique_ptr<Binary>> BinaryOrErr =
529f75da0c8SAlexey Lapshin           object::createBinary(**OutputBufferOrErr);
530f75da0c8SAlexey Lapshin       if (!BinaryOrErr)
531f75da0c8SAlexey Lapshin         return BinaryOrErr.takeError();
532f75da0c8SAlexey Lapshin       Binaries.emplace_back(std::move(*BinaryOrErr),
533f75da0c8SAlexey Lapshin                             std::move(*OutputBufferOrErr));
534f75da0c8SAlexey Lapshin       Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()),
535f75da0c8SAlexey Lapshin                           O.getCPUType(), O.getCPUSubType(),
536f75da0c8SAlexey Lapshin                           O.getArchFlagName(), O.getAlign());
537f75da0c8SAlexey Lapshin       continue;
538f75da0c8SAlexey Lapshin     }
539f75da0c8SAlexey Lapshin     // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class
540f75da0c8SAlexey Lapshin     // ObjectForArch return an Error in case of the type mismatch. We need to
541f75da0c8SAlexey Lapshin     // check each in turn to see what kind of slice this is, so ignore errors
542f75da0c8SAlexey Lapshin     // produced along the way.
543f75da0c8SAlexey Lapshin     consumeError(ArOrErr.takeError());
544f75da0c8SAlexey Lapshin 
545f75da0c8SAlexey Lapshin     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile();
546f75da0c8SAlexey Lapshin     if (!ObjOrErr) {
547f75da0c8SAlexey Lapshin       consumeError(ObjOrErr.takeError());
548f75da0c8SAlexey Lapshin       return createStringError(
549f75da0c8SAlexey Lapshin           std::errc::invalid_argument,
550f75da0c8SAlexey Lapshin           "slice for '%s' of the universal Mach-O binary "
551f75da0c8SAlexey Lapshin           "'%s' is not a Mach-O object or an archive",
552f75da0c8SAlexey Lapshin           O.getArchFlagName().c_str(),
553f75da0c8SAlexey Lapshin           Config.getCommonConfig().InputFilename.str().c_str());
554f75da0c8SAlexey Lapshin     }
555f75da0c8SAlexey Lapshin     std::string ArchFlagName = O.getArchFlagName();
556f75da0c8SAlexey Lapshin 
557f75da0c8SAlexey Lapshin     SmallVector<char, 0> Buffer;
558f75da0c8SAlexey Lapshin     raw_svector_ostream MemStream(Buffer);
559f75da0c8SAlexey Lapshin 
560f75da0c8SAlexey Lapshin     Expected<const MachOConfig &> MachO = Config.getMachOConfig();
561f75da0c8SAlexey Lapshin     if (!MachO)
562f75da0c8SAlexey Lapshin       return MachO.takeError();
563f75da0c8SAlexey Lapshin 
564f75da0c8SAlexey Lapshin     if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
565f75da0c8SAlexey Lapshin                                          **ObjOrErr, MemStream))
566f75da0c8SAlexey Lapshin       return E;
567f75da0c8SAlexey Lapshin 
568f75da0c8SAlexey Lapshin     auto MB = std::make_unique<SmallVectorMemoryBuffer>(
569f75da0c8SAlexey Lapshin         std::move(Buffer), ArchFlagName, /*RequiresNullTerminator=*/false);
570f75da0c8SAlexey Lapshin     Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB);
571f75da0c8SAlexey Lapshin     if (!BinaryOrErr)
572f75da0c8SAlexey Lapshin       return BinaryOrErr.takeError();
573f75da0c8SAlexey Lapshin     Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB));
574f75da0c8SAlexey Lapshin     Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()),
575f75da0c8SAlexey Lapshin                         O.getAlign());
576f75da0c8SAlexey Lapshin   }
577f75da0c8SAlexey Lapshin 
578f75da0c8SAlexey Lapshin   if (Error Err = writeUniversalBinaryToStream(Slices, Out))
579f75da0c8SAlexey Lapshin     return Err;
580f75da0c8SAlexey Lapshin 
581f75da0c8SAlexey Lapshin   return Error::success();
582f75da0c8SAlexey Lapshin }
583