MachOObject.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //===- MachOObject.cpp - Mach-O object file model ---------------*- 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 "MachOObject.h"
  9. #include "llvm/ADT/SmallPtrSet.h"
  10. #include <unordered_set>
  11. using namespace llvm;
  12. using namespace llvm::objcopy::macho;
  13. Section::Section(StringRef SegName, StringRef SectName)
  14. : Segname(SegName), Sectname(SectName),
  15. CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {}
  16. Section::Section(StringRef SegName, StringRef SectName, StringRef Content)
  17. : Segname(SegName), Sectname(SectName),
  18. CanonicalName((Twine(SegName) + Twine(',') + SectName).str()),
  19. Content(Content) {}
  20. const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
  21. assert(Index < Symbols.size() && "invalid symbol index");
  22. return Symbols[Index].get();
  23. }
  24. SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
  25. return const_cast<SymbolEntry *>(
  26. static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
  27. }
  28. void SymbolTable::removeSymbols(
  29. function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
  30. llvm::erase_if(Symbols, ToRemove);
  31. }
  32. void Object::updateLoadCommandIndexes() {
  33. static constexpr char TextSegmentName[] = "__TEXT";
  34. // Update indices of special load commands
  35. for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
  36. LoadCommand &LC = LoadCommands[Index];
  37. switch (LC.MachOLoadCommand.load_command_data.cmd) {
  38. case MachO::LC_CODE_SIGNATURE:
  39. CodeSignatureCommandIndex = Index;
  40. break;
  41. case MachO::LC_SEGMENT:
  42. if (StringRef(LC.MachOLoadCommand.segment_command_data.segname) ==
  43. TextSegmentName)
  44. TextSegmentCommandIndex = Index;
  45. break;
  46. case MachO::LC_SEGMENT_64:
  47. if (StringRef(LC.MachOLoadCommand.segment_command_64_data.segname) ==
  48. TextSegmentName)
  49. TextSegmentCommandIndex = Index;
  50. break;
  51. case MachO::LC_SYMTAB:
  52. SymTabCommandIndex = Index;
  53. break;
  54. case MachO::LC_DYSYMTAB:
  55. DySymTabCommandIndex = Index;
  56. break;
  57. case MachO::LC_DYLD_INFO:
  58. case MachO::LC_DYLD_INFO_ONLY:
  59. DyLdInfoCommandIndex = Index;
  60. break;
  61. case MachO::LC_DATA_IN_CODE:
  62. DataInCodeCommandIndex = Index;
  63. break;
  64. case MachO::LC_LINKER_OPTIMIZATION_HINT:
  65. LinkerOptimizationHintCommandIndex = Index;
  66. break;
  67. case MachO::LC_FUNCTION_STARTS:
  68. FunctionStartsCommandIndex = Index;
  69. break;
  70. case MachO::LC_DYLIB_CODE_SIGN_DRS:
  71. DylibCodeSignDRsIndex = Index;
  72. break;
  73. case MachO::LC_DYLD_CHAINED_FIXUPS:
  74. ChainedFixupsCommandIndex = Index;
  75. break;
  76. case MachO::LC_DYLD_EXPORTS_TRIE:
  77. ExportsTrieCommandIndex = Index;
  78. break;
  79. }
  80. }
  81. }
  82. Error Object::removeLoadCommands(
  83. function_ref<bool(const LoadCommand &)> ToRemove) {
  84. auto It = std::stable_partition(
  85. LoadCommands.begin(), LoadCommands.end(),
  86. [&](const LoadCommand &LC) { return !ToRemove(LC); });
  87. LoadCommands.erase(It, LoadCommands.end());
  88. updateLoadCommandIndexes();
  89. return Error::success();
  90. }
  91. Error Object::removeSections(
  92. function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
  93. DenseMap<uint32_t, const Section *> OldIndexToSection;
  94. uint32_t NextSectionIndex = 1;
  95. for (LoadCommand &LC : LoadCommands) {
  96. auto It = std::stable_partition(
  97. std::begin(LC.Sections), std::end(LC.Sections),
  98. [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
  99. for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
  100. OldIndexToSection[(*I)->Index] = I->get();
  101. (*I)->Index = NextSectionIndex++;
  102. }
  103. LC.Sections.erase(It, LC.Sections.end());
  104. }
  105. auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
  106. std::optional<uint32_t> Section = S->section();
  107. return (Section && !OldIndexToSection.count(*Section));
  108. };
  109. SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
  110. for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
  111. if (IsDead(Sym))
  112. DeadSymbols.insert(Sym.get());
  113. for (const LoadCommand &LC : LoadCommands)
  114. for (const std::unique_ptr<Section> &Sec : LC.Sections)
  115. for (const RelocationInfo &R : Sec->Relocations)
  116. if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
  117. return createStringError(std::errc::invalid_argument,
  118. "symbol '%s' defined in section with index "
  119. "'%u' cannot be removed because it is "
  120. "referenced by a relocation in section '%s'",
  121. (*R.Symbol)->Name.c_str(),
  122. *((*R.Symbol)->section()),
  123. Sec->CanonicalName.c_str());
  124. SymTable.removeSymbols(IsDead);
  125. for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
  126. if (S->section())
  127. S->n_sect = OldIndexToSection[S->n_sect]->Index;
  128. return Error::success();
  129. }
  130. uint64_t Object::nextAvailableSegmentAddress() const {
  131. uint64_t HeaderSize =
  132. is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
  133. uint64_t Addr = HeaderSize + Header.SizeOfCmds;
  134. for (const LoadCommand &LC : LoadCommands) {
  135. const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
  136. switch (MLC.load_command_data.cmd) {
  137. case MachO::LC_SEGMENT:
  138. Addr = std::max(Addr,
  139. static_cast<uint64_t>(MLC.segment_command_data.vmaddr) +
  140. MLC.segment_command_data.vmsize);
  141. break;
  142. case MachO::LC_SEGMENT_64:
  143. Addr = std::max(Addr, MLC.segment_command_64_data.vmaddr +
  144. MLC.segment_command_64_data.vmsize);
  145. break;
  146. default:
  147. continue;
  148. }
  149. }
  150. return Addr;
  151. }
  152. template <typename SegmentType>
  153. static void
  154. constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
  155. StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
  156. assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
  157. memset(&Seg, 0, sizeof(SegmentType));
  158. Seg.cmd = CmdType;
  159. strncpy(Seg.segname, SegName.data(), SegName.size());
  160. Seg.maxprot |=
  161. (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
  162. Seg.initprot |=
  163. (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
  164. Seg.vmaddr = SegVMAddr;
  165. Seg.vmsize = SegVMSize;
  166. }
  167. LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
  168. LoadCommand LC;
  169. const uint64_t SegVMAddr = nextAvailableSegmentAddress();
  170. if (is64Bit())
  171. constructSegment(LC.MachOLoadCommand.segment_command_64_data,
  172. MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
  173. else
  174. constructSegment(LC.MachOLoadCommand.segment_command_data,
  175. MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
  176. LoadCommands.push_back(std::move(LC));
  177. return LoadCommands.back();
  178. }
  179. /// Extracts a segment name from a string which is possibly non-null-terminated.
  180. static StringRef extractSegmentName(const char *SegName) {
  181. return StringRef(SegName,
  182. strnlen(SegName, sizeof(MachO::segment_command::segname)));
  183. }
  184. std::optional<StringRef> LoadCommand::getSegmentName() const {
  185. const MachO::macho_load_command &MLC = MachOLoadCommand;
  186. switch (MLC.load_command_data.cmd) {
  187. case MachO::LC_SEGMENT:
  188. return extractSegmentName(MLC.segment_command_data.segname);
  189. case MachO::LC_SEGMENT_64:
  190. return extractSegmentName(MLC.segment_command_64_data.segname);
  191. default:
  192. return std::nullopt;
  193. }
  194. }
  195. std::optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
  196. const MachO::macho_load_command &MLC = MachOLoadCommand;
  197. switch (MLC.load_command_data.cmd) {
  198. case MachO::LC_SEGMENT:
  199. return MLC.segment_command_data.vmaddr;
  200. case MachO::LC_SEGMENT_64:
  201. return MLC.segment_command_64_data.vmaddr;
  202. default:
  203. return std::nullopt;
  204. }
  205. }