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