MachOObjcopy.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. //===- MachOObjcopy.cpp -----------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "MachOObjcopy.h"
  9. #include "../CopyConfig.h"
  10. #include "../llvm-objcopy.h"
  11. #include "MachOReader.h"
  12. #include "MachOWriter.h"
  13. #include "llvm/ADT/DenseSet.h"
  14. #include "llvm/Object/ArchiveWriter.h"
  15. #include "llvm/Object/MachOUniversal.h"
  16. #include "llvm/Object/MachOUniversalWriter.h"
  17. #include "llvm/Support/Errc.h"
  18. #include "llvm/Support/Error.h"
  19. namespace llvm {
  20. namespace objcopy {
  21. namespace macho {
  22. using namespace object;
  23. using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
  24. using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
  25. #ifndef NDEBUG
  26. static bool isLoadCommandWithPayloadString(const LoadCommand &LC) {
  27. // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
  28. // LC_LAZY_LOAD_DYLIB
  29. return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH ||
  30. LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB ||
  31. LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB ||
  32. LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB;
  33. }
  34. #endif
  35. static StringRef getPayloadString(const LoadCommand &LC) {
  36. assert(isLoadCommandWithPayloadString(LC) &&
  37. "unsupported load command encountered");
  38. return StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
  39. LC.Payload.size())
  40. .rtrim('\0');
  41. }
  42. static Error removeSections(const CopyConfig &Config, Object &Obj) {
  43. SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
  44. return false;
  45. };
  46. if (!Config.ToRemove.empty()) {
  47. RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) {
  48. return Config.ToRemove.matches(Sec->CanonicalName);
  49. };
  50. }
  51. if (Config.StripAll || Config.StripDebug) {
  52. // Remove all debug sections.
  53. RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) {
  54. if (Sec->Segname == "__DWARF")
  55. return true;
  56. return RemovePred(Sec);
  57. };
  58. }
  59. if (!Config.OnlySection.empty()) {
  60. // Overwrite RemovePred because --only-section takes priority.
  61. RemovePred = [&Config](const std::unique_ptr<Section> &Sec) {
  62. return !Config.OnlySection.matches(Sec->CanonicalName);
  63. };
  64. }
  65. return Obj.removeSections(RemovePred);
  66. }
  67. static void markSymbols(const CopyConfig &Config, Object &Obj) {
  68. // Symbols referenced from the indirect symbol table must not be removed.
  69. for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
  70. if (ISE.Symbol)
  71. (*ISE.Symbol)->Referenced = true;
  72. }
  73. static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
  74. for (SymbolEntry &Sym : Obj.SymTable) {
  75. auto I = Config.SymbolsToRename.find(Sym.Name);
  76. if (I != Config.SymbolsToRename.end())
  77. Sym.Name = std::string(I->getValue());
  78. }
  79. auto RemovePred = [Config, &Obj](const std::unique_ptr<SymbolEntry> &N) {
  80. if (N->Referenced)
  81. return false;
  82. if (Config.StripAll)
  83. return true;
  84. if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
  85. return true;
  86. // This behavior is consistent with cctools' strip.
  87. if (Config.StripSwiftSymbols && (Obj.Header.Flags & MachO::MH_DYLDLINK) &&
  88. Obj.SwiftVersion && *Obj.SwiftVersion && N->isSwiftSymbol())
  89. return true;
  90. return false;
  91. };
  92. Obj.SymTable.removeSymbols(RemovePred);
  93. }
  94. template <typename LCType>
  95. static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
  96. assert(isLoadCommandWithPayloadString(LC) &&
  97. "unsupported load command encountered");
  98. uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
  99. LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
  100. LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
  101. std::copy(S.begin(), S.end(), LC.Payload.begin());
  102. }
  103. static LoadCommand buildRPathLoadCommand(StringRef Path) {
  104. LoadCommand LC;
  105. MachO::rpath_command RPathLC;
  106. RPathLC.cmd = MachO::LC_RPATH;
  107. RPathLC.path = sizeof(MachO::rpath_command);
  108. RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
  109. LC.MachOLoadCommand.rpath_command_data = RPathLC;
  110. LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
  111. std::copy(Path.begin(), Path.end(), LC.Payload.begin());
  112. return LC;
  113. }
  114. static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
  115. // Remove RPaths.
  116. DenseSet<StringRef> RPathsToRemove(Config.RPathsToRemove.begin(),
  117. Config.RPathsToRemove.end());
  118. LoadCommandPred RemovePred = [&RPathsToRemove,
  119. &Config](const LoadCommand &LC) {
  120. if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
  121. // When removing all RPaths we don't need to care
  122. // about what it contains
  123. if (Config.RemoveAllRpaths)
  124. return true;
  125. StringRef RPath = getPayloadString(LC);
  126. if (RPathsToRemove.count(RPath)) {
  127. RPathsToRemove.erase(RPath);
  128. return true;
  129. }
  130. }
  131. return false;
  132. };
  133. if (Error E = Obj.removeLoadCommands(RemovePred))
  134. return E;
  135. // Emit an error if the Mach-O binary does not contain an rpath path name
  136. // specified in -delete_rpath.
  137. for (StringRef RPath : Config.RPathsToRemove) {
  138. if (RPathsToRemove.count(RPath))
  139. return createStringError(errc::invalid_argument,
  140. "no LC_RPATH load command with path: %s",
  141. RPath.str().c_str());
  142. }
  143. DenseSet<StringRef> RPaths;
  144. // Get all existing RPaths.
  145. for (LoadCommand &LC : Obj.LoadCommands) {
  146. if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
  147. RPaths.insert(getPayloadString(LC));
  148. }
  149. // Throw errors for invalid RPaths.
  150. for (const auto &OldNew : Config.RPathsToUpdate) {
  151. StringRef Old = OldNew.getFirst();
  152. StringRef New = OldNew.getSecond();
  153. if (!RPaths.contains(Old))
  154. return createStringError(errc::invalid_argument,
  155. "no LC_RPATH load command with path: " + Old);
  156. if (RPaths.contains(New))
  157. return createStringError(errc::invalid_argument,
  158. "rpath '" + New +
  159. "' would create a duplicate load command");
  160. }
  161. // Update load commands.
  162. for (LoadCommand &LC : Obj.LoadCommands) {
  163. switch (LC.MachOLoadCommand.load_command_data.cmd) {
  164. case MachO::LC_ID_DYLIB:
  165. if (Config.SharedLibId)
  166. updateLoadCommandPayloadString<MachO::dylib_command>(
  167. LC, *Config.SharedLibId);
  168. break;
  169. case MachO::LC_RPATH: {
  170. StringRef RPath = getPayloadString(LC);
  171. StringRef NewRPath = Config.RPathsToUpdate.lookup(RPath);
  172. if (!NewRPath.empty())
  173. updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
  174. break;
  175. }
  176. // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
  177. // here once llvm-objcopy supports them.
  178. case MachO::LC_LOAD_DYLIB:
  179. case MachO::LC_LOAD_WEAK_DYLIB:
  180. StringRef InstallName = getPayloadString(LC);
  181. StringRef NewInstallName =
  182. Config.InstallNamesToUpdate.lookup(InstallName);
  183. if (!NewInstallName.empty())
  184. updateLoadCommandPayloadString<MachO::dylib_command>(LC,
  185. NewInstallName);
  186. break;
  187. }
  188. }
  189. // Add new RPaths.
  190. for (StringRef RPath : Config.RPathToAdd) {
  191. if (RPaths.contains(RPath))
  192. return createStringError(errc::invalid_argument,
  193. "rpath '" + RPath +
  194. "' would create a duplicate load command");
  195. RPaths.insert(RPath);
  196. Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
  197. }
  198. for (StringRef RPath : Config.RPathToPrepend) {
  199. if (RPaths.contains(RPath))
  200. return createStringError(errc::invalid_argument,
  201. "rpath '" + RPath +
  202. "' would create a duplicate load command");
  203. RPaths.insert(RPath);
  204. Obj.LoadCommands.insert(Obj.LoadCommands.begin(),
  205. buildRPathLoadCommand(RPath));
  206. }
  207. // Unlike appending rpaths, the indexes of subsequent load commands must
  208. // be recalculated after prepending one.
  209. if (!Config.RPathToPrepend.empty())
  210. Obj.updateLoadCommandIndexes();
  211. return Error::success();
  212. }
  213. static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
  214. Object &Obj) {
  215. for (LoadCommand &LC : Obj.LoadCommands)
  216. for (const std::unique_ptr<Section> &Sec : LC.Sections) {
  217. if (Sec->CanonicalName == SecName) {
  218. Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
  219. FileOutputBuffer::create(Filename, Sec->Content.size());
  220. if (!BufferOrErr)
  221. return BufferOrErr.takeError();
  222. std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
  223. llvm::copy(Sec->Content, Buf->getBufferStart());
  224. if (Error E = Buf->commit())
  225. return E;
  226. return Error::success();
  227. }
  228. }
  229. return createStringError(object_error::parse_failed, "section '%s' not found",
  230. SecName.str().c_str());
  231. }
  232. static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
  233. ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
  234. MemoryBuffer::getFile(Filename);
  235. if (!BufOrErr)
  236. return createFileError(Filename, errorCodeToError(BufOrErr.getError()));
  237. std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
  238. std::pair<StringRef, StringRef> Pair = SecName.split(',');
  239. StringRef TargetSegName = Pair.first;
  240. Section Sec(TargetSegName, Pair.second);
  241. Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer());
  242. Sec.Size = Sec.Content.size();
  243. // Add the a section into an existing segment.
  244. for (LoadCommand &LC : Obj.LoadCommands) {
  245. Optional<StringRef> SegName = LC.getSegmentName();
  246. if (SegName && SegName == TargetSegName) {
  247. uint64_t Addr = *LC.getSegmentVMAddr();
  248. for (const std::unique_ptr<Section> &S : LC.Sections)
  249. Addr = std::max(Addr, S->Addr + S->Size);
  250. LC.Sections.push_back(std::make_unique<Section>(Sec));
  251. LC.Sections.back()->Addr = Addr;
  252. return Error::success();
  253. }
  254. }
  255. // There's no segment named TargetSegName. Create a new load command and
  256. // Insert a new section into it.
  257. LoadCommand &NewSegment =
  258. Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
  259. NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
  260. NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
  261. return Error::success();
  262. }
  263. // isValidMachOCannonicalName returns success if Name is a MachO cannonical name
  264. // ("<segment>,<section>") and lengths of both segment and section names are
  265. // valid.
  266. static Error isValidMachOCannonicalName(StringRef Name) {
  267. if (Name.count(',') != 1)
  268. return createStringError(errc::invalid_argument,
  269. "invalid section name '%s' (should be formatted "
  270. "as '<segment name>,<section name>')",
  271. Name.str().c_str());
  272. std::pair<StringRef, StringRef> Pair = Name.split(',');
  273. if (Pair.first.size() > 16)
  274. return createStringError(errc::invalid_argument,
  275. "too long segment name: '%s'",
  276. Pair.first.str().c_str());
  277. if (Pair.second.size() > 16)
  278. return createStringError(errc::invalid_argument,
  279. "too long section name: '%s'",
  280. Pair.second.str().c_str());
  281. return Error::success();
  282. }
  283. static Error handleArgs(const CopyConfig &Config, Object &Obj) {
  284. if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
  285. Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
  286. !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
  287. !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() ||
  288. Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
  289. !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
  290. !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
  291. !Config.SectionsToRename.empty() ||
  292. !Config.UnneededSymbolsToRemove.empty() ||
  293. !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
  294. Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
  295. Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc ||
  296. Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
  297. Config.StripUnneeded || Config.DiscardMode == DiscardType::Locals ||
  298. !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
  299. return createStringError(llvm::errc::invalid_argument,
  300. "option not supported by llvm-objcopy for MachO");
  301. }
  302. // Dump sections before add/remove for compatibility with GNU objcopy.
  303. for (StringRef Flag : Config.DumpSection) {
  304. StringRef SectionName;
  305. StringRef FileName;
  306. std::tie(SectionName, FileName) = Flag.split('=');
  307. if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
  308. return E;
  309. }
  310. if (Error E = removeSections(Config, Obj))
  311. return E;
  312. // Mark symbols to determine which symbols are still needed.
  313. if (Config.StripAll)
  314. markSymbols(Config, Obj);
  315. updateAndRemoveSymbols(Config, Obj);
  316. if (Config.StripAll)
  317. for (LoadCommand &LC : Obj.LoadCommands)
  318. for (std::unique_ptr<Section> &Sec : LC.Sections)
  319. Sec->Relocations.clear();
  320. for (const auto &Flag : Config.AddSection) {
  321. std::pair<StringRef, StringRef> SecPair = Flag.split("=");
  322. StringRef SecName = SecPair.first;
  323. StringRef File = SecPair.second;
  324. if (Error E = isValidMachOCannonicalName(SecName))
  325. return E;
  326. if (Error E = addSection(SecName, File, Obj))
  327. return E;
  328. }
  329. if (Error E = processLoadCommands(Config, Obj))
  330. return E;
  331. return Error::success();
  332. }
  333. Error executeObjcopyOnBinary(const CopyConfig &Config,
  334. object::MachOObjectFile &In, Buffer &Out) {
  335. MachOReader Reader(In);
  336. Expected<std::unique_ptr<Object>> O = Reader.create();
  337. if (!O)
  338. return createFileError(Config.InputFilename, O.takeError());
  339. if (Error E = handleArgs(Config, **O))
  340. return createFileError(Config.InputFilename, std::move(E));
  341. // Page size used for alignment of segment sizes in Mach-O executables and
  342. // dynamic libraries.
  343. uint64_t PageSize;
  344. switch (In.getArch()) {
  345. case Triple::ArchType::arm:
  346. case Triple::ArchType::aarch64:
  347. case Triple::ArchType::aarch64_32:
  348. PageSize = 16384;
  349. break;
  350. default:
  351. PageSize = 4096;
  352. }
  353. MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(), PageSize, Out);
  354. if (auto E = Writer.finalize())
  355. return E;
  356. return Writer.write();
  357. }
  358. Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
  359. const MachOUniversalBinary &In,
  360. Buffer &Out) {
  361. SmallVector<OwningBinary<Binary>, 2> Binaries;
  362. SmallVector<Slice, 2> Slices;
  363. for (const auto &O : In.objects()) {
  364. Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
  365. if (ArOrErr) {
  366. Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
  367. createNewArchiveMembers(Config, **ArOrErr);
  368. if (!NewArchiveMembersOrErr)
  369. return NewArchiveMembersOrErr.takeError();
  370. Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
  371. writeArchiveToBuffer(*NewArchiveMembersOrErr,
  372. (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(),
  373. Config.DeterministicArchives,
  374. (*ArOrErr)->isThin());
  375. if (!OutputBufferOrErr)
  376. return OutputBufferOrErr.takeError();
  377. Expected<std::unique_ptr<Binary>> BinaryOrErr =
  378. object::createBinary(**OutputBufferOrErr);
  379. if (!BinaryOrErr)
  380. return BinaryOrErr.takeError();
  381. Binaries.emplace_back(std::move(*BinaryOrErr),
  382. std::move(*OutputBufferOrErr));
  383. Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()),
  384. O.getCPUType(), O.getCPUSubType(),
  385. O.getArchFlagName(), O.getAlign());
  386. continue;
  387. }
  388. // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class
  389. // ObjectForArch return an Error in case of the type mismatch. We need to
  390. // check each in turn to see what kind of slice this is, so ignore errors
  391. // produced along the way.
  392. consumeError(ArOrErr.takeError());
  393. Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile();
  394. if (!ObjOrErr) {
  395. consumeError(ObjOrErr.takeError());
  396. return createStringError(std::errc::invalid_argument,
  397. "slice for '%s' of the universal Mach-O binary "
  398. "'%s' is not a Mach-O object or an archive",
  399. O.getArchFlagName().c_str(),
  400. Config.InputFilename.str().c_str());
  401. }
  402. std::string ArchFlagName = O.getArchFlagName();
  403. MemBuffer MB(ArchFlagName);
  404. if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MB))
  405. return E;
  406. std::unique_ptr<WritableMemoryBuffer> OutputBuffer =
  407. MB.releaseMemoryBuffer();
  408. Expected<std::unique_ptr<Binary>> BinaryOrErr =
  409. object::createBinary(*OutputBuffer);
  410. if (!BinaryOrErr)
  411. return BinaryOrErr.takeError();
  412. Binaries.emplace_back(std::move(*BinaryOrErr), std::move(OutputBuffer));
  413. Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()),
  414. O.getAlign());
  415. }
  416. Expected<std::unique_ptr<MemoryBuffer>> B =
  417. writeUniversalBinaryToBuffer(Slices);
  418. if (!B)
  419. return B.takeError();
  420. if (Error E = Out.allocate((*B)->getBufferSize()))
  421. return E;
  422. memcpy(Out.getBufferStart(), (*B)->getBufferStart(), (*B)->getBufferSize());
  423. return Out.commit();
  424. }
  425. } // end namespace macho
  426. } // end namespace objcopy
  427. } // end namespace llvm