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