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) { 97*5f757f3fSDimitry Andric // Weaken symbols first to match ELFObjcopy behavior. 98*5f757f3fSDimitry Andric bool IsExportedAndDefined = 99*5f757f3fSDimitry Andric (Sym.n_type & llvm::MachO::N_EXT) && 100*5f757f3fSDimitry Andric (Sym.n_type & llvm::MachO::N_TYPE) != llvm::MachO::N_UNDF; 101*5f757f3fSDimitry Andric if (IsExportedAndDefined && 102*5f757f3fSDimitry Andric (Config.Weaken || Config.SymbolsToWeaken.matches(Sym.Name))) 103*5f757f3fSDimitry Andric Sym.n_desc |= llvm::MachO::N_WEAK_DEF; 104*5f757f3fSDimitry Andric 10581ad6265SDimitry Andric auto I = Config.SymbolsToRename.find(Sym.Name); 10681ad6265SDimitry Andric if (I != Config.SymbolsToRename.end()) 10781ad6265SDimitry Andric Sym.Name = std::string(I->getValue()); 10881ad6265SDimitry Andric } 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric auto RemovePred = [&Config, &MachOConfig, 11181ad6265SDimitry Andric &Obj](const std::unique_ptr<SymbolEntry> &N) { 11281ad6265SDimitry Andric if (N->Referenced) 11381ad6265SDimitry Andric return false; 11481ad6265SDimitry Andric if (MachOConfig.KeepUndefined && N->isUndefinedSymbol()) 11581ad6265SDimitry Andric return false; 11681ad6265SDimitry Andric if (N->n_desc & MachO::REFERENCED_DYNAMICALLY) 11781ad6265SDimitry Andric return false; 11881ad6265SDimitry Andric if (Config.StripAll) 11981ad6265SDimitry Andric return true; 12081ad6265SDimitry Andric if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT)) 12181ad6265SDimitry Andric return true; 12281ad6265SDimitry Andric // This behavior is consistent with cctools' strip. 12306c3fb27SDimitry Andric if (Config.StripDebug && (N->n_type & MachO::N_STAB)) 12406c3fb27SDimitry Andric return true; 12506c3fb27SDimitry Andric // This behavior is consistent with cctools' strip. 12681ad6265SDimitry Andric if (MachOConfig.StripSwiftSymbols && 12781ad6265SDimitry Andric (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion && 12881ad6265SDimitry Andric *Obj.SwiftVersion && N->isSwiftSymbol()) 12981ad6265SDimitry Andric return true; 13081ad6265SDimitry Andric return false; 13181ad6265SDimitry Andric }; 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric Obj.SymTable.removeSymbols(RemovePred); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric template <typename LCType> 13781ad6265SDimitry Andric static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) { 13881ad6265SDimitry Andric assert(isLoadCommandWithPayloadString(LC) && 13981ad6265SDimitry Andric "unsupported load command encountered"); 14081ad6265SDimitry Andric 14181ad6265SDimitry Andric uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8); 14281ad6265SDimitry Andric 14381ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize; 14481ad6265SDimitry Andric LC.Payload.assign(NewCmdsize - sizeof(LCType), 0); 14581ad6265SDimitry Andric std::copy(S.begin(), S.end(), LC.Payload.begin()); 14681ad6265SDimitry Andric } 14781ad6265SDimitry Andric 14881ad6265SDimitry Andric static LoadCommand buildRPathLoadCommand(StringRef Path) { 14981ad6265SDimitry Andric LoadCommand LC; 15081ad6265SDimitry Andric MachO::rpath_command RPathLC; 15181ad6265SDimitry Andric RPathLC.cmd = MachO::LC_RPATH; 15281ad6265SDimitry Andric RPathLC.path = sizeof(MachO::rpath_command); 15381ad6265SDimitry Andric RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8); 15481ad6265SDimitry Andric LC.MachOLoadCommand.rpath_command_data = RPathLC; 15581ad6265SDimitry Andric LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0); 15681ad6265SDimitry Andric std::copy(Path.begin(), Path.end(), LC.Payload.begin()); 15781ad6265SDimitry Andric return LC; 15881ad6265SDimitry Andric } 15981ad6265SDimitry Andric 16081ad6265SDimitry Andric static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) { 16181ad6265SDimitry Andric // Remove RPaths. 16281ad6265SDimitry Andric DenseSet<StringRef> RPathsToRemove(MachOConfig.RPathsToRemove.begin(), 16381ad6265SDimitry Andric MachOConfig.RPathsToRemove.end()); 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric LoadCommandPred RemovePred = [&RPathsToRemove, 16681ad6265SDimitry Andric &MachOConfig](const LoadCommand &LC) { 16781ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) { 16881ad6265SDimitry Andric // When removing all RPaths we don't need to care 16981ad6265SDimitry Andric // about what it contains 17081ad6265SDimitry Andric if (MachOConfig.RemoveAllRpaths) 17181ad6265SDimitry Andric return true; 17281ad6265SDimitry Andric 17381ad6265SDimitry Andric StringRef RPath = getPayloadString(LC); 17481ad6265SDimitry Andric if (RPathsToRemove.count(RPath)) { 17581ad6265SDimitry Andric RPathsToRemove.erase(RPath); 17681ad6265SDimitry Andric return true; 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric } 17981ad6265SDimitry Andric return false; 18081ad6265SDimitry Andric }; 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric if (Error E = Obj.removeLoadCommands(RemovePred)) 18381ad6265SDimitry Andric return E; 18481ad6265SDimitry Andric 18581ad6265SDimitry Andric // Emit an error if the Mach-O binary does not contain an rpath path name 18681ad6265SDimitry Andric // specified in -delete_rpath. 18781ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathsToRemove) { 18881ad6265SDimitry Andric if (RPathsToRemove.count(RPath)) 18981ad6265SDimitry Andric return createStringError(errc::invalid_argument, 19081ad6265SDimitry Andric "no LC_RPATH load command with path: %s", 19181ad6265SDimitry Andric RPath.str().c_str()); 19281ad6265SDimitry Andric } 19381ad6265SDimitry Andric 19481ad6265SDimitry Andric DenseSet<StringRef> RPaths; 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric // Get all existing RPaths. 19781ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 19881ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) 19981ad6265SDimitry Andric RPaths.insert(getPayloadString(LC)); 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric // Throw errors for invalid RPaths. 20381ad6265SDimitry Andric for (const auto &OldNew : MachOConfig.RPathsToUpdate) { 20481ad6265SDimitry Andric StringRef Old = OldNew.getFirst(); 20581ad6265SDimitry Andric StringRef New = OldNew.getSecond(); 20681ad6265SDimitry Andric if (!RPaths.contains(Old)) 20781ad6265SDimitry Andric return createStringError(errc::invalid_argument, 20881ad6265SDimitry Andric "no LC_RPATH load command with path: " + Old); 20981ad6265SDimitry Andric if (RPaths.contains(New)) 21081ad6265SDimitry Andric return createStringError(errc::invalid_argument, 21181ad6265SDimitry Andric "rpath '" + New + 21281ad6265SDimitry Andric "' would create a duplicate load command"); 21381ad6265SDimitry Andric } 21481ad6265SDimitry Andric 21581ad6265SDimitry Andric // Update load commands. 21681ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 21781ad6265SDimitry Andric switch (LC.MachOLoadCommand.load_command_data.cmd) { 21881ad6265SDimitry Andric case MachO::LC_ID_DYLIB: 21981ad6265SDimitry Andric if (MachOConfig.SharedLibId) 22081ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::dylib_command>( 22181ad6265SDimitry Andric LC, *MachOConfig.SharedLibId); 22281ad6265SDimitry Andric break; 22381ad6265SDimitry Andric 22481ad6265SDimitry Andric case MachO::LC_RPATH: { 22581ad6265SDimitry Andric StringRef RPath = getPayloadString(LC); 22681ad6265SDimitry Andric StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath); 22781ad6265SDimitry Andric if (!NewRPath.empty()) 22881ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath); 22981ad6265SDimitry Andric break; 23081ad6265SDimitry Andric } 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB 23381ad6265SDimitry Andric // here once llvm-objcopy supports them. 23481ad6265SDimitry Andric case MachO::LC_LOAD_DYLIB: 23581ad6265SDimitry Andric case MachO::LC_LOAD_WEAK_DYLIB: 23681ad6265SDimitry Andric StringRef InstallName = getPayloadString(LC); 23781ad6265SDimitry Andric StringRef NewInstallName = 23881ad6265SDimitry Andric MachOConfig.InstallNamesToUpdate.lookup(InstallName); 23981ad6265SDimitry Andric if (!NewInstallName.empty()) 24081ad6265SDimitry Andric updateLoadCommandPayloadString<MachO::dylib_command>(LC, 24181ad6265SDimitry Andric NewInstallName); 24281ad6265SDimitry Andric break; 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric // Add new RPaths. 24781ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathToAdd) { 24881ad6265SDimitry Andric if (RPaths.contains(RPath)) 24981ad6265SDimitry Andric return createStringError(errc::invalid_argument, 25081ad6265SDimitry Andric "rpath '" + RPath + 25181ad6265SDimitry Andric "' would create a duplicate load command"); 25281ad6265SDimitry Andric RPaths.insert(RPath); 25381ad6265SDimitry Andric Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath)); 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric for (StringRef RPath : MachOConfig.RPathToPrepend) { 25781ad6265SDimitry Andric if (RPaths.contains(RPath)) 25881ad6265SDimitry Andric return createStringError(errc::invalid_argument, 25981ad6265SDimitry Andric "rpath '" + RPath + 26081ad6265SDimitry Andric "' would create a duplicate load command"); 26181ad6265SDimitry Andric 26281ad6265SDimitry Andric RPaths.insert(RPath); 26381ad6265SDimitry Andric Obj.LoadCommands.insert(Obj.LoadCommands.begin(), 26481ad6265SDimitry Andric buildRPathLoadCommand(RPath)); 26581ad6265SDimitry Andric } 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric // Unlike appending rpaths, the indexes of subsequent load commands must 26881ad6265SDimitry Andric // be recalculated after prepending one. 26981ad6265SDimitry Andric if (!MachOConfig.RPathToPrepend.empty()) 27081ad6265SDimitry Andric Obj.updateLoadCommandIndexes(); 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric // Remove any empty segments if required. 27381ad6265SDimitry Andric if (!MachOConfig.EmptySegmentsToRemove.empty()) { 27481ad6265SDimitry Andric auto RemovePred = [&MachOConfig](const LoadCommand &LC) { 27581ad6265SDimitry Andric if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 || 27681ad6265SDimitry Andric LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) { 27781ad6265SDimitry Andric return LC.Sections.empty() && 27881ad6265SDimitry Andric MachOConfig.EmptySegmentsToRemove.contains(*LC.getSegmentName()); 27981ad6265SDimitry Andric } 28081ad6265SDimitry Andric return false; 28181ad6265SDimitry Andric }; 28281ad6265SDimitry Andric if (Error E = Obj.removeLoadCommands(RemovePred)) 28381ad6265SDimitry Andric return E; 28481ad6265SDimitry Andric } 28581ad6265SDimitry Andric 28681ad6265SDimitry Andric return Error::success(); 28781ad6265SDimitry Andric } 28881ad6265SDimitry Andric 28981ad6265SDimitry Andric static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 29081ad6265SDimitry Andric Object &Obj) { 29181ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) 29281ad6265SDimitry Andric for (const std::unique_ptr<Section> &Sec : LC.Sections) { 29381ad6265SDimitry Andric if (Sec->CanonicalName == SecName) { 29481ad6265SDimitry Andric Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 29581ad6265SDimitry Andric FileOutputBuffer::create(Filename, Sec->Content.size()); 29681ad6265SDimitry Andric if (!BufferOrErr) 29781ad6265SDimitry Andric return BufferOrErr.takeError(); 29881ad6265SDimitry Andric std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 29981ad6265SDimitry Andric llvm::copy(Sec->Content, Buf->getBufferStart()); 30081ad6265SDimitry Andric 30181ad6265SDimitry Andric if (Error E = Buf->commit()) 30281ad6265SDimitry Andric return E; 30381ad6265SDimitry Andric return Error::success(); 30481ad6265SDimitry Andric } 30581ad6265SDimitry Andric } 30681ad6265SDimitry Andric 30781ad6265SDimitry Andric return createStringError(object_error::parse_failed, "section '%s' not found", 30881ad6265SDimitry Andric SecName.str().c_str()); 30981ad6265SDimitry Andric } 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric static Error addSection(const NewSectionInfo &NewSection, Object &Obj) { 31281ad6265SDimitry Andric std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(','); 31381ad6265SDimitry Andric StringRef TargetSegName = Pair.first; 31481ad6265SDimitry Andric Section Sec(TargetSegName, Pair.second); 31581ad6265SDimitry Andric Sec.Content = 31681ad6265SDimitry Andric Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer()); 31781ad6265SDimitry Andric Sec.Size = Sec.Content.size(); 31881ad6265SDimitry Andric 31981ad6265SDimitry Andric // Add the a section into an existing segment. 32081ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) { 321bdd1243dSDimitry Andric std::optional<StringRef> SegName = LC.getSegmentName(); 32281ad6265SDimitry Andric if (SegName && SegName == TargetSegName) { 32381ad6265SDimitry Andric uint64_t Addr = *LC.getSegmentVMAddr(); 32481ad6265SDimitry Andric for (const std::unique_ptr<Section> &S : LC.Sections) 32581ad6265SDimitry Andric Addr = std::max(Addr, S->Addr + S->Size); 32681ad6265SDimitry Andric LC.Sections.push_back(std::make_unique<Section>(Sec)); 32781ad6265SDimitry Andric LC.Sections.back()->Addr = Addr; 32881ad6265SDimitry Andric return Error::success(); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric } 33181ad6265SDimitry Andric 33281ad6265SDimitry Andric // There's no segment named TargetSegName. Create a new load command and 33381ad6265SDimitry Andric // Insert a new section into it. 33481ad6265SDimitry Andric LoadCommand &NewSegment = 33581ad6265SDimitry Andric Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384)); 33681ad6265SDimitry Andric NewSegment.Sections.push_back(std::make_unique<Section>(Sec)); 33781ad6265SDimitry Andric NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr(); 33881ad6265SDimitry Andric return Error::success(); 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric static Expected<Section &> findSection(StringRef SecName, Object &O) { 34281ad6265SDimitry Andric StringRef SegName; 34381ad6265SDimitry Andric std::tie(SegName, SecName) = SecName.split(","); 34481ad6265SDimitry Andric auto FoundSeg = 34581ad6265SDimitry Andric llvm::find_if(O.LoadCommands, [SegName](const LoadCommand &LC) { 34681ad6265SDimitry Andric return LC.getSegmentName() == SegName; 34781ad6265SDimitry Andric }); 34881ad6265SDimitry Andric if (FoundSeg == O.LoadCommands.end()) 34981ad6265SDimitry Andric return createStringError(errc::invalid_argument, 35081ad6265SDimitry Andric "could not find segment with name '%s'", 35181ad6265SDimitry Andric SegName.str().c_str()); 35281ad6265SDimitry Andric auto FoundSec = llvm::find_if(FoundSeg->Sections, 35381ad6265SDimitry Andric [SecName](const std::unique_ptr<Section> &Sec) { 35481ad6265SDimitry Andric return Sec->Sectname == SecName; 35581ad6265SDimitry Andric }); 35681ad6265SDimitry Andric if (FoundSec == FoundSeg->Sections.end()) 35781ad6265SDimitry Andric return createStringError(errc::invalid_argument, 35881ad6265SDimitry Andric "could not find section with name '%s'", 35981ad6265SDimitry Andric SecName.str().c_str()); 36081ad6265SDimitry Andric 36181ad6265SDimitry Andric assert(FoundSec->get()->CanonicalName == (SegName + "," + SecName).str()); 362bdd1243dSDimitry Andric return **FoundSec; 36381ad6265SDimitry Andric } 36481ad6265SDimitry Andric 36581ad6265SDimitry Andric static Error updateSection(const NewSectionInfo &NewSection, Object &O) { 36681ad6265SDimitry Andric Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O); 36781ad6265SDimitry Andric 36881ad6265SDimitry Andric if (!SecToUpdateOrErr) 36981ad6265SDimitry Andric return SecToUpdateOrErr.takeError(); 37081ad6265SDimitry Andric Section &Sec = *SecToUpdateOrErr; 37181ad6265SDimitry Andric 37281ad6265SDimitry Andric if (NewSection.SectionData->getBufferSize() > Sec.Size) 37381ad6265SDimitry Andric return createStringError( 37481ad6265SDimitry Andric errc::invalid_argument, 37581ad6265SDimitry Andric "new section cannot be larger than previous section"); 37681ad6265SDimitry Andric Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer()); 37781ad6265SDimitry Andric Sec.Size = Sec.Content.size(); 37881ad6265SDimitry Andric return Error::success(); 37981ad6265SDimitry Andric } 38081ad6265SDimitry Andric 38181ad6265SDimitry Andric // isValidMachOCannonicalName returns success if Name is a MachO cannonical name 38281ad6265SDimitry Andric // ("<segment>,<section>") and lengths of both segment and section names are 38381ad6265SDimitry Andric // valid. 38481ad6265SDimitry Andric static Error isValidMachOCannonicalName(StringRef Name) { 38581ad6265SDimitry Andric if (Name.count(',') != 1) 38681ad6265SDimitry Andric return createStringError(errc::invalid_argument, 38781ad6265SDimitry Andric "invalid section name '%s' (should be formatted " 38881ad6265SDimitry Andric "as '<segment name>,<section name>')", 38981ad6265SDimitry Andric Name.str().c_str()); 39081ad6265SDimitry Andric 39181ad6265SDimitry Andric std::pair<StringRef, StringRef> Pair = Name.split(','); 39281ad6265SDimitry Andric if (Pair.first.size() > 16) 39381ad6265SDimitry Andric return createStringError(errc::invalid_argument, 39481ad6265SDimitry Andric "too long segment name: '%s'", 39581ad6265SDimitry Andric Pair.first.str().c_str()); 39681ad6265SDimitry Andric if (Pair.second.size() > 16) 39781ad6265SDimitry Andric return createStringError(errc::invalid_argument, 39881ad6265SDimitry Andric "too long section name: '%s'", 39981ad6265SDimitry Andric Pair.second.str().c_str()); 40081ad6265SDimitry Andric return Error::success(); 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config, 40481ad6265SDimitry Andric const MachOConfig &MachOConfig, Object &Obj) { 40581ad6265SDimitry Andric // Dump sections before add/remove for compatibility with GNU objcopy. 40681ad6265SDimitry Andric for (StringRef Flag : Config.DumpSection) { 40781ad6265SDimitry Andric StringRef SectionName; 40881ad6265SDimitry Andric StringRef FileName; 40981ad6265SDimitry Andric std::tie(SectionName, FileName) = Flag.split('='); 41081ad6265SDimitry Andric if (Error E = dumpSectionToFile(SectionName, FileName, Obj)) 41181ad6265SDimitry Andric return E; 41281ad6265SDimitry Andric } 41381ad6265SDimitry Andric 41481ad6265SDimitry Andric if (Error E = removeSections(Config, Obj)) 41581ad6265SDimitry Andric return E; 41681ad6265SDimitry Andric 41781ad6265SDimitry Andric // Mark symbols to determine which symbols are still needed. 41881ad6265SDimitry Andric if (Config.StripAll) 41981ad6265SDimitry Andric markSymbols(Config, Obj); 42081ad6265SDimitry Andric 42181ad6265SDimitry Andric updateAndRemoveSymbols(Config, MachOConfig, Obj); 42281ad6265SDimitry Andric 42381ad6265SDimitry Andric if (Config.StripAll) 42481ad6265SDimitry Andric for (LoadCommand &LC : Obj.LoadCommands) 42581ad6265SDimitry Andric for (std::unique_ptr<Section> &Sec : LC.Sections) 42681ad6265SDimitry Andric Sec->Relocations.clear(); 42781ad6265SDimitry Andric 42881ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.AddSection) { 42981ad6265SDimitry Andric if (Error E = isValidMachOCannonicalName(NewSection.SectionName)) 43081ad6265SDimitry Andric return E; 43181ad6265SDimitry Andric if (Error E = addSection(NewSection, Obj)) 43281ad6265SDimitry Andric return E; 43381ad6265SDimitry Andric } 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.UpdateSection) { 43681ad6265SDimitry Andric if (Error E = isValidMachOCannonicalName(NewSection.SectionName)) 43781ad6265SDimitry Andric return E; 43881ad6265SDimitry Andric if (Error E = updateSection(NewSection, Obj)) 43981ad6265SDimitry Andric return E; 44081ad6265SDimitry Andric } 44181ad6265SDimitry Andric 44281ad6265SDimitry Andric if (Error E = processLoadCommands(MachOConfig, Obj)) 44381ad6265SDimitry Andric return E; 44481ad6265SDimitry Andric 44581ad6265SDimitry Andric return Error::success(); 44681ad6265SDimitry Andric } 44781ad6265SDimitry Andric 44881ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config, 44981ad6265SDimitry Andric const MachOConfig &MachOConfig, 45081ad6265SDimitry Andric object::MachOObjectFile &In, 45181ad6265SDimitry Andric raw_ostream &Out) { 45281ad6265SDimitry Andric MachOReader Reader(In); 45381ad6265SDimitry Andric Expected<std::unique_ptr<Object>> O = Reader.create(); 45481ad6265SDimitry Andric if (!O) 45581ad6265SDimitry Andric return createFileError(Config.InputFilename, O.takeError()); 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric if (O->get()->Header.FileType == MachO::HeaderFileType::MH_PRELOAD) 45881ad6265SDimitry Andric return createStringError(std::errc::not_supported, 45981ad6265SDimitry Andric "%s: MH_PRELOAD files are not supported", 46081ad6265SDimitry Andric Config.InputFilename.str().c_str()); 46181ad6265SDimitry Andric 46281ad6265SDimitry Andric if (Error E = handleArgs(Config, MachOConfig, **O)) 46381ad6265SDimitry Andric return createFileError(Config.InputFilename, std::move(E)); 46481ad6265SDimitry Andric 46581ad6265SDimitry Andric // Page size used for alignment of segment sizes in Mach-O executables and 46681ad6265SDimitry Andric // dynamic libraries. 46781ad6265SDimitry Andric uint64_t PageSize; 46881ad6265SDimitry Andric switch (In.getArch()) { 46981ad6265SDimitry Andric case Triple::ArchType::arm: 47081ad6265SDimitry Andric case Triple::ArchType::aarch64: 47181ad6265SDimitry Andric case Triple::ArchType::aarch64_32: 47281ad6265SDimitry Andric PageSize = 16384; 47381ad6265SDimitry Andric break; 47481ad6265SDimitry Andric default: 47581ad6265SDimitry Andric PageSize = 4096; 47681ad6265SDimitry Andric } 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(), 47981ad6265SDimitry Andric sys::path::filename(Config.OutputFilename), PageSize, Out); 48081ad6265SDimitry Andric if (auto E = Writer.finalize()) 48181ad6265SDimitry Andric return E; 48281ad6265SDimitry Andric return Writer.write(); 48381ad6265SDimitry Andric } 48481ad6265SDimitry Andric 48581ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( 48681ad6265SDimitry Andric const MultiFormatConfig &Config, const MachOUniversalBinary &In, 48781ad6265SDimitry Andric raw_ostream &Out) { 48881ad6265SDimitry Andric SmallVector<OwningBinary<Binary>, 2> Binaries; 48981ad6265SDimitry Andric SmallVector<Slice, 2> Slices; 49081ad6265SDimitry Andric for (const auto &O : In.objects()) { 49181ad6265SDimitry Andric Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive(); 49281ad6265SDimitry Andric if (ArOrErr) { 49381ad6265SDimitry Andric Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 49481ad6265SDimitry Andric createNewArchiveMembers(Config, **ArOrErr); 49581ad6265SDimitry Andric if (!NewArchiveMembersOrErr) 49681ad6265SDimitry Andric return NewArchiveMembersOrErr.takeError(); 49781ad6265SDimitry Andric auto Kind = (*ArOrErr)->kind(); 49881ad6265SDimitry Andric if (Kind == object::Archive::K_BSD) 49981ad6265SDimitry Andric Kind = object::Archive::K_DARWIN; 50081ad6265SDimitry Andric Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr = 501*5f757f3fSDimitry Andric writeArchiveToBuffer( 502*5f757f3fSDimitry Andric *NewArchiveMembersOrErr, 503*5f757f3fSDimitry Andric (*ArOrErr)->hasSymbolTable() ? SymtabWritingMode::NormalSymtab 504*5f757f3fSDimitry Andric : SymtabWritingMode::NoSymtab, 505*5f757f3fSDimitry Andric Kind, Config.getCommonConfig().DeterministicArchives, 50681ad6265SDimitry Andric (*ArOrErr)->isThin()); 50781ad6265SDimitry Andric if (!OutputBufferOrErr) 50881ad6265SDimitry Andric return OutputBufferOrErr.takeError(); 50981ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> BinaryOrErr = 51081ad6265SDimitry Andric object::createBinary(**OutputBufferOrErr); 51181ad6265SDimitry Andric if (!BinaryOrErr) 51281ad6265SDimitry Andric return BinaryOrErr.takeError(); 51381ad6265SDimitry Andric Binaries.emplace_back(std::move(*BinaryOrErr), 51481ad6265SDimitry Andric std::move(*OutputBufferOrErr)); 51581ad6265SDimitry Andric Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()), 51681ad6265SDimitry Andric O.getCPUType(), O.getCPUSubType(), 51781ad6265SDimitry Andric O.getArchFlagName(), O.getAlign()); 51881ad6265SDimitry Andric continue; 51981ad6265SDimitry Andric } 52081ad6265SDimitry Andric // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class 52181ad6265SDimitry Andric // ObjectForArch return an Error in case of the type mismatch. We need to 52281ad6265SDimitry Andric // check each in turn to see what kind of slice this is, so ignore errors 52381ad6265SDimitry Andric // produced along the way. 52481ad6265SDimitry Andric consumeError(ArOrErr.takeError()); 52581ad6265SDimitry Andric 52681ad6265SDimitry Andric Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile(); 52781ad6265SDimitry Andric if (!ObjOrErr) { 52881ad6265SDimitry Andric consumeError(ObjOrErr.takeError()); 52981ad6265SDimitry Andric return createStringError( 53081ad6265SDimitry Andric std::errc::invalid_argument, 53181ad6265SDimitry Andric "slice for '%s' of the universal Mach-O binary " 53281ad6265SDimitry Andric "'%s' is not a Mach-O object or an archive", 53381ad6265SDimitry Andric O.getArchFlagName().c_str(), 53481ad6265SDimitry Andric Config.getCommonConfig().InputFilename.str().c_str()); 53581ad6265SDimitry Andric } 53681ad6265SDimitry Andric std::string ArchFlagName = O.getArchFlagName(); 53781ad6265SDimitry Andric 53881ad6265SDimitry Andric SmallVector<char, 0> Buffer; 53981ad6265SDimitry Andric raw_svector_ostream MemStream(Buffer); 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric Expected<const MachOConfig &> MachO = Config.getMachOConfig(); 54281ad6265SDimitry Andric if (!MachO) 54381ad6265SDimitry Andric return MachO.takeError(); 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, 54681ad6265SDimitry Andric **ObjOrErr, MemStream)) 54781ad6265SDimitry Andric return E; 54881ad6265SDimitry Andric 54981ad6265SDimitry Andric auto MB = std::make_unique<SmallVectorMemoryBuffer>( 55081ad6265SDimitry Andric std::move(Buffer), ArchFlagName, /*RequiresNullTerminator=*/false); 55181ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB); 55281ad6265SDimitry Andric if (!BinaryOrErr) 55381ad6265SDimitry Andric return BinaryOrErr.takeError(); 55481ad6265SDimitry Andric Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB)); 55581ad6265SDimitry Andric Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()), 55681ad6265SDimitry Andric O.getAlign()); 55781ad6265SDimitry Andric } 55881ad6265SDimitry Andric 55981ad6265SDimitry Andric if (Error Err = writeUniversalBinaryToStream(Slices, Out)) 56081ad6265SDimitry Andric return Err; 56181ad6265SDimitry Andric 56281ad6265SDimitry Andric return Error::success(); 56381ad6265SDimitry Andric } 564