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
isLoadCommandWithPayloadString(const LoadCommand & LC)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
getPayloadString(const LoadCommand & LC)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
removeSections(const CommonConfig & Config,Object & Obj)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
markSymbols(const CommonConfig &,Object & Obj)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
updateAndRemoveSymbols(const CommonConfig & Config,const MachOConfig & MachOConfig,Object & Obj)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>
updateLoadCommandPayloadString(LoadCommand & LC,StringRef S)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
buildRPathLoadCommand(StringRef Path)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
processLoadCommands(const MachOConfig & MachOConfig,Object & Obj)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
dumpSectionToFile(StringRef SecName,StringRef Filename,Object & Obj)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
addSection(const NewSectionInfo & NewSection,Object & Obj)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
findSection(StringRef SecName,Object & O)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
updateSection(const NewSectionInfo & NewSection,Object & O)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.
isValidMachOCannonicalName(StringRef Name)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
handleArgs(const CommonConfig & Config,const MachOConfig & MachOConfig,Object & Obj)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
executeObjcopyOnBinary(const CommonConfig & Config,const MachOConfig & MachOConfig,object::MachOObjectFile & In,raw_ostream & Out)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
executeObjcopyOnMachOUniversalBinary(const MultiFormatConfig & Config,const MachOUniversalBinary & In,raw_ostream & Out)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