181ad6265SDimitry Andric //===- MachOObjcopy.cpp -----------------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/ObjCopy/MachO/MachOObjcopy.h" 1081ad6265SDimitry Andric #include "Archive.h" 1181ad6265SDimitry Andric #include "MachOReader.h" 1281ad6265SDimitry Andric #include "MachOWriter.h" 1381ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h" 1481ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h" 1581ad6265SDimitry Andric #include "llvm/ObjCopy/MachO/MachOConfig.h" 1681ad6265SDimitry Andric #include "llvm/ObjCopy/MultiFormatConfig.h" 1781ad6265SDimitry Andric #include "llvm/ObjCopy/ObjCopy.h" 1881ad6265SDimitry Andric #include "llvm/Object/ArchiveWriter.h" 1981ad6265SDimitry Andric #include "llvm/Object/MachOUniversal.h" 2081ad6265SDimitry Andric #include "llvm/Object/MachOUniversalWriter.h" 2181ad6265SDimitry Andric #include "llvm/Support/Errc.h" 2281ad6265SDimitry Andric #include "llvm/Support/Error.h" 2381ad6265SDimitry Andric #include "llvm/Support/FileOutputBuffer.h" 2481ad6265SDimitry Andric #include "llvm/Support/Path.h" 2581ad6265SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric using namespace llvm; 2881ad6265SDimitry Andric using namespace llvm::objcopy; 2981ad6265SDimitry Andric using namespace llvm::objcopy::macho; 3081ad6265SDimitry Andric using namespace llvm::object; 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>; 3381ad6265SDimitry Andric using LoadCommandPred = std::function<bool(const LoadCommand &LC)>; 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric #ifndef NDEBUG 3681ad6265SDimitry Andric static bool isLoadCommandWithPayloadString(const LoadCommand &LC) { 3781ad6265SDimitry Andric // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and 3881ad6265SDimitry Andric // LC_LAZY_LOAD_DYLIB 3981ad6265SDimitry Andric return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH || 4081ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB || 4181ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB || 4281ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB; 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric #endif 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric static StringRef getPayloadString(const LoadCommand &LC) { 4781ad6265SDimitry Andric assert(isLoadCommandWithPayloadString(LC) && 4881ad6265SDimitry Andric "unsupported load command encountered"); 4981ad6265SDimitry Andric 5081ad6265SDimitry Andric return StringRef(reinterpret_cast<const char *>(LC.Payload.data()), 5181ad6265SDimitry Andric LC.Payload.size()) 5281ad6265SDimitry Andric .rtrim('\0'); 5381ad6265SDimitry Andric } 5481ad6265SDimitry Andric 5581ad6265SDimitry Andric static Error removeSections(const CommonConfig &Config, Object &Obj) { 5681ad6265SDimitry Andric SectionPred RemovePred = [](const std::unique_ptr<Section> &) { 5781ad6265SDimitry Andric return false; 5881ad6265SDimitry Andric }; 5981ad6265SDimitry Andric 6081ad6265SDimitry Andric if (!Config.ToRemove.empty()) { 6181ad6265SDimitry Andric RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) { 6281ad6265SDimitry Andric return Config.ToRemove.matches(Sec->CanonicalName); 6381ad6265SDimitry Andric }; 6481ad6265SDimitry Andric } 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric if (Config.StripAll || Config.StripDebug) { 6781ad6265SDimitry Andric // Remove all debug sections. 6881ad6265SDimitry Andric RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) { 6981ad6265SDimitry Andric if (Sec->Segname == "__DWARF") 7081ad6265SDimitry Andric return true; 7181ad6265SDimitry Andric 7281ad6265SDimitry Andric return RemovePred(Sec); 7381ad6265SDimitry Andric }; 7481ad6265SDimitry Andric } 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric if (!Config.OnlySection.empty()) { 7781ad6265SDimitry Andric // Overwrite RemovePred because --only-section takes priority. 7881ad6265SDimitry Andric RemovePred = [&Config](const std::unique_ptr<Section> &Sec) { 7981ad6265SDimitry Andric return !Config.OnlySection.matches(Sec->CanonicalName); 8081ad6265SDimitry Andric }; 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric return Obj.removeSections(RemovePred); 8481ad6265SDimitry Andric } 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric static void markSymbols(const CommonConfig &, Object &Obj) { 8781ad6265SDimitry Andric // Symbols referenced from the indirect symbol table must not be removed. 8881ad6265SDimitry Andric for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols) 8981ad6265SDimitry Andric if (ISE.Symbol) 9081ad6265SDimitry Andric (*ISE.Symbol)->Referenced = true; 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric static void updateAndRemoveSymbols(const CommonConfig &Config, 9481ad6265SDimitry Andric const MachOConfig &MachOConfig, 9581ad6265SDimitry Andric Object &Obj) { 9681ad6265SDimitry Andric for (SymbolEntry &Sym : Obj.SymTable) { 9781ad6265SDimitry Andric auto I = Config.SymbolsToRename.find(Sym.Name); 9881ad6265SDimitry Andric if (I != Config.SymbolsToRename.end()) 9981ad6265SDimitry Andric Sym.Name = std::string(I->getValue()); 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric auto RemovePred = [&Config, &MachOConfig, 10381ad6265SDimitry Andric &Obj](const std::unique_ptr<SymbolEntry> &N) { 10481ad6265SDimitry Andric if (N->Referenced) 10581ad6265SDimitry Andric return false; 10681ad6265SDimitry Andric if (MachOConfig.KeepUndefined && N->isUndefinedSymbol()) 10781ad6265SDimitry Andric return false; 10881ad6265SDimitry Andric if (N->n_desc & MachO::REFERENCED_DYNAMICALLY) 10981ad6265SDimitry Andric return false; 11081ad6265SDimitry Andric if (Config.StripAll) 11181ad6265SDimitry Andric return true; 11281ad6265SDimitry Andric if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT)) 11381ad6265SDimitry Andric return true; 11481ad6265SDimitry Andric // This behavior is consistent with cctools' strip. 11581ad6265SDimitry Andric if (MachOConfig.StripSwiftSymbols && 11681ad6265SDimitry Andric (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion && 11781ad6265SDimitry Andric *Obj.SwiftVersion && N->isSwiftSymbol()) 11881ad6265SDimitry Andric return true; 11981ad6265SDimitry Andric return false; 12081ad6265SDimitry Andric }; 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric Obj.SymTable.removeSymbols(RemovePred); 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric template <typename LCType> 12681ad6265SDimitry Andric static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) { 12781ad6265SDimitry Andric assert(isLoadCommandWithPayloadString(LC) && 12881ad6265SDimitry Andric "unsupported load command encountered"); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8); 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize; 13381ad6265SDimitry Andric LC.Payload.assign(NewCmdsize - sizeof(LCType), 0); 13481ad6265SDimitry Andric std::copy(S.begin(), S.end(), LC.Payload.begin()); 13581ad6265SDimitry Andric } 13681ad6265SDimitry Andric 13781ad6265SDimitry Andric static LoadCommand buildRPathLoadCommand(StringRef Path) { 13881ad6265SDimitry Andric LoadCommand LC; 13981ad6265SDimitry Andric MachO::rpath_command RPathLC; 14081ad6265SDimitry Andric RPathLC.cmd = MachO::LC_RPATH; 14181ad6265SDimitry Andric RPathLC.path = sizeof(MachO::rpath_command); 14281ad6265SDimitry Andric RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8); 14381ad6265SDimitry Andric LC.MachOLoadCommand.rpath_command_data = RPathLC; 14481ad6265SDimitry Andric LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0); 14581ad6265SDimitry Andric std::copy(Path.begin(), Path.end(), LC.Payload.begin()); 14681ad6265SDimitry Andric return LC; 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) { 15081ad6265SDimitry Andric // Remove RPaths. 15181ad6265SDimitry Andric DenseSet<StringRef> RPathsToRemove(MachOConfig.RPathsToRemove.begin(), 15281ad6265SDimitry Andric MachOConfig.RPathsToRemove.end()); 15381ad6265SDimitry Andric 15481ad6265SDimitry Andric LoadCommandPred RemovePred = [&RPathsToRemove, 15581ad6265SDimitry Andric &MachOConfig](const LoadCommand &LC) { 15681ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) { 15781ad6265SDimitry Andric // When removing all RPaths we don't need to care 15881ad6265SDimitry Andric // about what it contains 15981ad6265SDimitry Andric if (MachOConfig.RemoveAllRpaths) 16081ad6265SDimitry Andric return true; 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric StringRef RPath = getPayloadString(LC); 16381ad6265SDimitry Andric if (RPathsToRemove.count(RPath)) { 16481ad6265SDimitry Andric RPathsToRemove.erase(RPath); 16581ad6265SDimitry Andric return true; 16681ad6265SDimitry Andric } 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric return false; 16981ad6265SDimitry Andric }; 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric if (Error E = Obj.removeLoadCommands(RemovePred)) 17281ad6265SDimitry Andric return E; 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric // Emit an error if the Mach-O binary does not contain an rpath path name 17581ad6265SDimitry Andric // specified in -delete_rpath. 17681ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathsToRemove) { 17781ad6265SDimitry Andric if (RPathsToRemove.count(RPath)) 17881ad6265SDimitry Andric return createStringError(errc::invalid_argument, 17981ad6265SDimitry Andric "no LC_RPATH load command with path: %s", 18081ad6265SDimitry Andric RPath.str().c_str()); 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric DenseSet<StringRef> RPaths; 18481ad6265SDimitry Andric 18581ad6265SDimitry Andric // Get all existing RPaths. 18681ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 18781ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) 18881ad6265SDimitry Andric RPaths.insert(getPayloadString(LC)); 18981ad6265SDimitry Andric } 19081ad6265SDimitry Andric 19181ad6265SDimitry Andric // Throw errors for invalid RPaths. 19281ad6265SDimitry Andric for (const auto &OldNew : MachOConfig.RPathsToUpdate) { 19381ad6265SDimitry Andric StringRef Old = OldNew.getFirst(); 19481ad6265SDimitry Andric StringRef New = OldNew.getSecond(); 19581ad6265SDimitry Andric if (!RPaths.contains(Old)) 19681ad6265SDimitry Andric return createStringError(errc::invalid_argument, 19781ad6265SDimitry Andric "no LC_RPATH load command with path: " + Old); 19881ad6265SDimitry Andric if (RPaths.contains(New)) 19981ad6265SDimitry Andric return createStringError(errc::invalid_argument, 20081ad6265SDimitry Andric "rpath '" + New + 20181ad6265SDimitry Andric "' would create a duplicate load command"); 20281ad6265SDimitry Andric } 20381ad6265SDimitry Andric 20481ad6265SDimitry Andric // Update load commands. 20581ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 20681ad6265SDimitry Andric switch (LC.MachOLoadCommand.load_command_data.cmd) { 20781ad6265SDimitry Andric case MachO::LC_ID_DYLIB: 20881ad6265SDimitry Andric if (MachOConfig.SharedLibId) 20981ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::dylib_command>( 21081ad6265SDimitry Andric LC, *MachOConfig.SharedLibId); 21181ad6265SDimitry Andric break; 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric case MachO::LC_RPATH: { 21481ad6265SDimitry Andric StringRef RPath = getPayloadString(LC); 21581ad6265SDimitry Andric StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath); 21681ad6265SDimitry Andric if (!NewRPath.empty()) 21781ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath); 21881ad6265SDimitry Andric break; 21981ad6265SDimitry Andric } 22081ad6265SDimitry Andric 22181ad6265SDimitry Andric // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB 22281ad6265SDimitry Andric // here once llvm-objcopy supports them. 22381ad6265SDimitry Andric case MachO::LC_LOAD_DYLIB: 22481ad6265SDimitry Andric case MachO::LC_LOAD_WEAK_DYLIB: 22581ad6265SDimitry Andric StringRef InstallName = getPayloadString(LC); 22681ad6265SDimitry Andric StringRef NewInstallName = 22781ad6265SDimitry Andric MachOConfig.InstallNamesToUpdate.lookup(InstallName); 22881ad6265SDimitry Andric if (!NewInstallName.empty()) 22981ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::dylib_command>(LC, 23081ad6265SDimitry Andric NewInstallName); 23181ad6265SDimitry Andric break; 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric } 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric // Add new RPaths. 23681ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathToAdd) { 23781ad6265SDimitry Andric if (RPaths.contains(RPath)) 23881ad6265SDimitry Andric return createStringError(errc::invalid_argument, 23981ad6265SDimitry Andric "rpath '" + RPath + 24081ad6265SDimitry Andric "' would create a duplicate load command"); 24181ad6265SDimitry Andric RPaths.insert(RPath); 24281ad6265SDimitry Andric Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath)); 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathToPrepend) { 24681ad6265SDimitry Andric if (RPaths.contains(RPath)) 24781ad6265SDimitry Andric return createStringError(errc::invalid_argument, 24881ad6265SDimitry Andric "rpath '" + RPath + 24981ad6265SDimitry Andric "' would create a duplicate load command"); 25081ad6265SDimitry Andric 25181ad6265SDimitry Andric RPaths.insert(RPath); 25281ad6265SDimitry Andric Obj.LoadCommands.insert(Obj.LoadCommands.begin(), 25381ad6265SDimitry Andric buildRPathLoadCommand(RPath)); 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric // Unlike appending rpaths, the indexes of subsequent load commands must 25781ad6265SDimitry Andric // be recalculated after prepending one. 25881ad6265SDimitry Andric if (!MachOConfig.RPathToPrepend.empty()) 25981ad6265SDimitry Andric Obj.updateLoadCommandIndexes(); 26081ad6265SDimitry Andric 26181ad6265SDimitry Andric // Remove any empty segments if required. 26281ad6265SDimitry Andric if (!MachOConfig.EmptySegmentsToRemove.empty()) { 26381ad6265SDimitry Andric auto RemovePred = [&MachOConfig](const LoadCommand &LC) { 26481ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 || 26581ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) { 26681ad6265SDimitry Andric return LC.Sections.empty() && 26781ad6265SDimitry Andric MachOConfig.EmptySegmentsToRemove.contains(*LC.getSegmentName()); 26881ad6265SDimitry Andric } 26981ad6265SDimitry Andric return false; 27081ad6265SDimitry Andric }; 27181ad6265SDimitry Andric if (Error E = Obj.removeLoadCommands(RemovePred)) 27281ad6265SDimitry Andric return E; 27381ad6265SDimitry Andric } 27481ad6265SDimitry Andric 27581ad6265SDimitry Andric return Error::success(); 27681ad6265SDimitry Andric } 27781ad6265SDimitry Andric 27881ad6265SDimitry Andric static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 27981ad6265SDimitry Andric Object &Obj) { 28081ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) 28181ad6265SDimitry Andric for (const std::unique_ptr<Section> &Sec : LC.Sections) { 28281ad6265SDimitry Andric if (Sec->CanonicalName == SecName) { 28381ad6265SDimitry Andric Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 28481ad6265SDimitry Andric FileOutputBuffer::create(Filename, Sec->Content.size()); 28581ad6265SDimitry Andric if (!BufferOrErr) 28681ad6265SDimitry Andric return BufferOrErr.takeError(); 28781ad6265SDimitry Andric std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 28881ad6265SDimitry Andric llvm::copy(Sec->Content, Buf->getBufferStart()); 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric if (Error E = Buf->commit()) 29181ad6265SDimitry Andric return E; 29281ad6265SDimitry Andric return Error::success(); 29381ad6265SDimitry Andric } 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 29681ad6265SDimitry Andric return createStringError(object_error::parse_failed, "section '%s' not found", 29781ad6265SDimitry Andric SecName.str().c_str()); 29881ad6265SDimitry Andric } 29981ad6265SDimitry Andric 30081ad6265SDimitry Andric static Error addSection(const NewSectionInfo &NewSection, Object &Obj) { 30181ad6265SDimitry Andric std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(','); 30281ad6265SDimitry Andric StringRef TargetSegName = Pair.first; 30381ad6265SDimitry Andric Section Sec(TargetSegName, Pair.second); 30481ad6265SDimitry Andric Sec.Content = 30581ad6265SDimitry Andric Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer()); 30681ad6265SDimitry Andric Sec.Size = Sec.Content.size(); 30781ad6265SDimitry Andric 30881ad6265SDimitry Andric // Add the a section into an existing segment. 30981ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 310*bdd1243dSDimitry Andric std::optional<StringRef> SegName = LC.getSegmentName(); 31181ad6265SDimitry Andric if (SegName && SegName == TargetSegName) { 31281ad6265SDimitry Andric uint64_t Addr = *LC.getSegmentVMAddr(); 31381ad6265SDimitry Andric for (const std::unique_ptr<Section> &S : LC.Sections) 31481ad6265SDimitry Andric Addr = std::max(Addr, S->Addr + S->Size); 31581ad6265SDimitry Andric LC.Sections.push_back(std::make_unique<Section>(Sec)); 31681ad6265SDimitry Andric LC.Sections.back()->Addr = Addr; 31781ad6265SDimitry Andric return Error::success(); 31881ad6265SDimitry Andric } 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric // There's no segment named TargetSegName. Create a new load command and 32281ad6265SDimitry Andric // Insert a new section into it. 32381ad6265SDimitry Andric LoadCommand &NewSegment = 32481ad6265SDimitry Andric Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384)); 32581ad6265SDimitry Andric NewSegment.Sections.push_back(std::make_unique<Section>(Sec)); 32681ad6265SDimitry Andric NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr(); 32781ad6265SDimitry Andric return Error::success(); 32881ad6265SDimitry Andric } 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric static Expected<Section &> findSection(StringRef SecName, Object &O) { 33181ad6265SDimitry Andric StringRef SegName; 33281ad6265SDimitry Andric std::tie(SegName, SecName) = SecName.split(","); 33381ad6265SDimitry Andric auto FoundSeg = 33481ad6265SDimitry Andric llvm::find_if(O.LoadCommands, [SegName](const LoadCommand &LC) { 33581ad6265SDimitry Andric return LC.getSegmentName() == SegName; 33681ad6265SDimitry Andric }); 33781ad6265SDimitry Andric if (FoundSeg == O.LoadCommands.end()) 33881ad6265SDimitry Andric return createStringError(errc::invalid_argument, 33981ad6265SDimitry Andric "could not find segment with name '%s'", 34081ad6265SDimitry Andric SegName.str().c_str()); 34181ad6265SDimitry Andric auto FoundSec = llvm::find_if(FoundSeg->Sections, 34281ad6265SDimitry Andric [SecName](const std::unique_ptr<Section> &Sec) { 34381ad6265SDimitry Andric return Sec->Sectname == SecName; 34481ad6265SDimitry Andric }); 34581ad6265SDimitry Andric if (FoundSec == FoundSeg->Sections.end()) 34681ad6265SDimitry Andric return createStringError(errc::invalid_argument, 34781ad6265SDimitry Andric "could not find section with name '%s'", 34881ad6265SDimitry Andric SecName.str().c_str()); 34981ad6265SDimitry Andric 35081ad6265SDimitry Andric assert(FoundSec->get()->CanonicalName == (SegName + "," + SecName).str()); 351*bdd1243dSDimitry Andric return **FoundSec; 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric static Error updateSection(const NewSectionInfo &NewSection, Object &O) { 35581ad6265SDimitry Andric Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O); 35681ad6265SDimitry Andric 35781ad6265SDimitry Andric if (!SecToUpdateOrErr) 35881ad6265SDimitry Andric return SecToUpdateOrErr.takeError(); 35981ad6265SDimitry Andric Section &Sec = *SecToUpdateOrErr; 36081ad6265SDimitry Andric 36181ad6265SDimitry Andric if (NewSection.SectionData->getBufferSize() > Sec.Size) 36281ad6265SDimitry Andric return createStringError( 36381ad6265SDimitry Andric errc::invalid_argument, 36481ad6265SDimitry Andric "new section cannot be larger than previous section"); 36581ad6265SDimitry Andric Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer()); 36681ad6265SDimitry Andric Sec.Size = Sec.Content.size(); 36781ad6265SDimitry Andric return Error::success(); 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric 37081ad6265SDimitry Andric // isValidMachOCannonicalName returns success if Name is a MachO cannonical name 37181ad6265SDimitry Andric // ("<segment>,<section>") and lengths of both segment and section names are 37281ad6265SDimitry Andric // valid. 37381ad6265SDimitry Andric static Error isValidMachOCannonicalName(StringRef Name) { 37481ad6265SDimitry Andric if (Name.count(',') != 1) 37581ad6265SDimitry Andric return createStringError(errc::invalid_argument, 37681ad6265SDimitry Andric "invalid section name '%s' (should be formatted " 37781ad6265SDimitry Andric "as '<segment name>,<section name>')", 37881ad6265SDimitry Andric Name.str().c_str()); 37981ad6265SDimitry Andric 38081ad6265SDimitry Andric std::pair<StringRef, StringRef> Pair = Name.split(','); 38181ad6265SDimitry Andric if (Pair.first.size() > 16) 38281ad6265SDimitry Andric return createStringError(errc::invalid_argument, 38381ad6265SDimitry Andric "too long segment name: '%s'", 38481ad6265SDimitry Andric Pair.first.str().c_str()); 38581ad6265SDimitry Andric if (Pair.second.size() > 16) 38681ad6265SDimitry Andric return createStringError(errc::invalid_argument, 38781ad6265SDimitry Andric "too long section name: '%s'", 38881ad6265SDimitry Andric Pair.second.str().c_str()); 38981ad6265SDimitry Andric return Error::success(); 39081ad6265SDimitry Andric } 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config, 39381ad6265SDimitry Andric const MachOConfig &MachOConfig, Object &Obj) { 39481ad6265SDimitry Andric // Dump sections before add/remove for compatibility with GNU objcopy. 39581ad6265SDimitry Andric for (StringRef Flag : Config.DumpSection) { 39681ad6265SDimitry Andric StringRef SectionName; 39781ad6265SDimitry Andric StringRef FileName; 39881ad6265SDimitry Andric std::tie(SectionName, FileName) = Flag.split('='); 39981ad6265SDimitry Andric if (Error E = dumpSectionToFile(SectionName, FileName, Obj)) 40081ad6265SDimitry Andric return E; 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric if (Error E = removeSections(Config, Obj)) 40481ad6265SDimitry Andric return E; 40581ad6265SDimitry Andric 40681ad6265SDimitry Andric // Mark symbols to determine which symbols are still needed. 40781ad6265SDimitry Andric if (Config.StripAll) 40881ad6265SDimitry Andric markSymbols(Config, Obj); 40981ad6265SDimitry Andric 41081ad6265SDimitry Andric updateAndRemoveSymbols(Config, MachOConfig, Obj); 41181ad6265SDimitry Andric 41281ad6265SDimitry Andric if (Config.StripAll) 41381ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) 41481ad6265SDimitry Andric for (std::unique_ptr<Section> &Sec : LC.Sections) 41581ad6265SDimitry Andric Sec->Relocations.clear(); 41681ad6265SDimitry Andric 41781ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.AddSection) { 41881ad6265SDimitry Andric if (Error E = isValidMachOCannonicalName(NewSection.SectionName)) 41981ad6265SDimitry Andric return E; 42081ad6265SDimitry Andric if (Error E = addSection(NewSection, Obj)) 42181ad6265SDimitry Andric return E; 42281ad6265SDimitry Andric } 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.UpdateSection) { 42581ad6265SDimitry Andric if (Error E = isValidMachOCannonicalName(NewSection.SectionName)) 42681ad6265SDimitry Andric return E; 42781ad6265SDimitry Andric if (Error E = updateSection(NewSection, Obj)) 42881ad6265SDimitry Andric return E; 42981ad6265SDimitry Andric } 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric if (Error E = processLoadCommands(MachOConfig, Obj)) 43281ad6265SDimitry Andric return E; 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric return Error::success(); 43581ad6265SDimitry Andric } 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config, 43881ad6265SDimitry Andric const MachOConfig &MachOConfig, 43981ad6265SDimitry Andric object::MachOObjectFile &In, 44081ad6265SDimitry Andric raw_ostream &Out) { 44181ad6265SDimitry Andric MachOReader Reader(In); 44281ad6265SDimitry Andric Expected<std::unique_ptr<Object>> O = Reader.create(); 44381ad6265SDimitry Andric if (!O) 44481ad6265SDimitry Andric return createFileError(Config.InputFilename, O.takeError()); 44581ad6265SDimitry Andric 44681ad6265SDimitry Andric if (O->get()->Header.FileType == MachO::HeaderFileType::MH_PRELOAD) 44781ad6265SDimitry Andric return createStringError(std::errc::not_supported, 44881ad6265SDimitry Andric "%s: MH_PRELOAD files are not supported", 44981ad6265SDimitry Andric Config.InputFilename.str().c_str()); 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric if (Error E = handleArgs(Config, MachOConfig, **O)) 45281ad6265SDimitry Andric return createFileError(Config.InputFilename, std::move(E)); 45381ad6265SDimitry Andric 45481ad6265SDimitry Andric // Page size used for alignment of segment sizes in Mach-O executables and 45581ad6265SDimitry Andric // dynamic libraries. 45681ad6265SDimitry Andric uint64_t PageSize; 45781ad6265SDimitry Andric switch (In.getArch()) { 45881ad6265SDimitry Andric case Triple::ArchType::arm: 45981ad6265SDimitry Andric case Triple::ArchType::aarch64: 46081ad6265SDimitry Andric case Triple::ArchType::aarch64_32: 46181ad6265SDimitry Andric PageSize = 16384; 46281ad6265SDimitry Andric break; 46381ad6265SDimitry Andric default: 46481ad6265SDimitry Andric PageSize = 4096; 46581ad6265SDimitry Andric } 46681ad6265SDimitry Andric 46781ad6265SDimitry Andric MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(), 46881ad6265SDimitry Andric sys::path::filename(Config.OutputFilename), PageSize, Out); 46981ad6265SDimitry Andric if (auto E = Writer.finalize()) 47081ad6265SDimitry Andric return E; 47181ad6265SDimitry Andric return Writer.write(); 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric 47481ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( 47581ad6265SDimitry Andric const MultiFormatConfig &Config, const MachOUniversalBinary &In, 47681ad6265SDimitry Andric raw_ostream &Out) { 47781ad6265SDimitry Andric SmallVector<OwningBinary<Binary>, 2> Binaries; 47881ad6265SDimitry Andric SmallVector<Slice, 2> Slices; 47981ad6265SDimitry Andric for (const auto &O : In.objects()) { 48081ad6265SDimitry Andric Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive(); 48181ad6265SDimitry Andric if (ArOrErr) { 48281ad6265SDimitry Andric Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 48381ad6265SDimitry Andric createNewArchiveMembers(Config, **ArOrErr); 48481ad6265SDimitry Andric if (!NewArchiveMembersOrErr) 48581ad6265SDimitry Andric return NewArchiveMembersOrErr.takeError(); 48681ad6265SDimitry Andric auto Kind = (*ArOrErr)->kind(); 48781ad6265SDimitry Andric if (Kind == object::Archive::K_BSD) 48881ad6265SDimitry Andric Kind = object::Archive::K_DARWIN; 48981ad6265SDimitry Andric Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr = 49081ad6265SDimitry Andric writeArchiveToBuffer(*NewArchiveMembersOrErr, 49181ad6265SDimitry Andric (*ArOrErr)->hasSymbolTable(), Kind, 49281ad6265SDimitry Andric Config.getCommonConfig().DeterministicArchives, 49381ad6265SDimitry Andric (*ArOrErr)->isThin()); 49481ad6265SDimitry Andric if (!OutputBufferOrErr) 49581ad6265SDimitry Andric return OutputBufferOrErr.takeError(); 49681ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> BinaryOrErr = 49781ad6265SDimitry Andric object::createBinary(**OutputBufferOrErr); 49881ad6265SDimitry Andric if (!BinaryOrErr) 49981ad6265SDimitry Andric return BinaryOrErr.takeError(); 50081ad6265SDimitry Andric Binaries.emplace_back(std::move(*BinaryOrErr), 50181ad6265SDimitry Andric std::move(*OutputBufferOrErr)); 50281ad6265SDimitry Andric Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()), 50381ad6265SDimitry Andric O.getCPUType(), O.getCPUSubType(), 50481ad6265SDimitry Andric O.getArchFlagName(), O.getAlign()); 50581ad6265SDimitry Andric continue; 50681ad6265SDimitry Andric } 50781ad6265SDimitry Andric // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class 50881ad6265SDimitry Andric // ObjectForArch return an Error in case of the type mismatch. We need to 50981ad6265SDimitry Andric // check each in turn to see what kind of slice this is, so ignore errors 51081ad6265SDimitry Andric // produced along the way. 51181ad6265SDimitry Andric consumeError(ArOrErr.takeError()); 51281ad6265SDimitry Andric 51381ad6265SDimitry Andric Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile(); 51481ad6265SDimitry Andric if (!ObjOrErr) { 51581ad6265SDimitry Andric consumeError(ObjOrErr.takeError()); 51681ad6265SDimitry Andric return createStringError( 51781ad6265SDimitry Andric std::errc::invalid_argument, 51881ad6265SDimitry Andric "slice for '%s' of the universal Mach-O binary " 51981ad6265SDimitry Andric "'%s' is not a Mach-O object or an archive", 52081ad6265SDimitry Andric O.getArchFlagName().c_str(), 52181ad6265SDimitry Andric Config.getCommonConfig().InputFilename.str().c_str()); 52281ad6265SDimitry Andric } 52381ad6265SDimitry Andric std::string ArchFlagName = O.getArchFlagName(); 52481ad6265SDimitry Andric 52581ad6265SDimitry Andric SmallVector<char, 0> Buffer; 52681ad6265SDimitry Andric raw_svector_ostream MemStream(Buffer); 52781ad6265SDimitry Andric 52881ad6265SDimitry Andric Expected<const MachOConfig &> MachO = Config.getMachOConfig(); 52981ad6265SDimitry Andric if (!MachO) 53081ad6265SDimitry Andric return MachO.takeError(); 53181ad6265SDimitry Andric 53281ad6265SDimitry Andric if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, 53381ad6265SDimitry Andric **ObjOrErr, MemStream)) 53481ad6265SDimitry Andric return E; 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric auto MB = std::make_unique<SmallVectorMemoryBuffer>( 53781ad6265SDimitry Andric std::move(Buffer), ArchFlagName, /*RequiresNullTerminator=*/false); 53881ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB); 53981ad6265SDimitry Andric if (!BinaryOrErr) 54081ad6265SDimitry Andric return BinaryOrErr.takeError(); 54181ad6265SDimitry Andric Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB)); 54281ad6265SDimitry Andric Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()), 54381ad6265SDimitry Andric O.getAlign()); 54481ad6265SDimitry Andric } 54581ad6265SDimitry Andric 54681ad6265SDimitry Andric if (Error Err = writeUniversalBinaryToStream(Slices, Out)) 54781ad6265SDimitry Andric return Err; 54881ad6265SDimitry Andric 54981ad6265SDimitry Andric return Error::success(); 55081ad6265SDimitry Andric } 551