MachOAtomGraphBuilder.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. //=--------- MachOAtomGraphBuilder.cpp - MachO AtomGraph builder ----------===//
  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. //
  9. // Generic MachO AtomGraph buliding code.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "MachOAtomGraphBuilder.h"
  13. #define DEBUG_TYPE "jitlink"
  14. namespace llvm {
  15. namespace jitlink {
  16. MachOAtomGraphBuilder::~MachOAtomGraphBuilder() {}
  17. Expected<std::unique_ptr<AtomGraph>> MachOAtomGraphBuilder::buildGraph() {
  18. if (auto Err = parseSections())
  19. return std::move(Err);
  20. if (auto Err = addAtoms())
  21. return std::move(Err);
  22. if (auto Err = addRelocations())
  23. return std::move(Err);
  24. return std::move(G);
  25. }
  26. MachOAtomGraphBuilder::MachOAtomGraphBuilder(const object::MachOObjectFile &Obj)
  27. : Obj(Obj),
  28. G(std::make_unique<AtomGraph>(Obj.getFileName(), getPointerSize(Obj),
  29. getEndianness(Obj))) {}
  30. void MachOAtomGraphBuilder::addCustomAtomizer(StringRef SectionName,
  31. CustomAtomizeFunction Atomizer) {
  32. assert(!CustomAtomizeFunctions.count(SectionName) &&
  33. "Custom atomizer for this section already exists");
  34. CustomAtomizeFunctions[SectionName] = std::move(Atomizer);
  35. }
  36. bool MachOAtomGraphBuilder::areLayoutLocked(const Atom &A, const Atom &B) {
  37. // If these atoms are the same then they're trivially "locked".
  38. if (&A == &B)
  39. return true;
  40. // If A and B are different, check whether either is undefined. (in which
  41. // case they are not locked).
  42. if (!A.isDefined() || !B.isDefined())
  43. return false;
  44. // A and B are different, but they're both defined atoms. We need to check
  45. // whether they're part of the same alt_entry chain.
  46. auto &DA = static_cast<const DefinedAtom &>(A);
  47. auto &DB = static_cast<const DefinedAtom &>(B);
  48. auto AStartItr = AltEntryStarts.find(&DA);
  49. if (AStartItr == AltEntryStarts.end()) // If A is not in a chain bail out.
  50. return false;
  51. auto BStartItr = AltEntryStarts.find(&DB);
  52. if (BStartItr == AltEntryStarts.end()) // If B is not in a chain bail out.
  53. return false;
  54. // A and B are layout locked if they're in the same chain.
  55. return AStartItr->second == BStartItr->second;
  56. }
  57. unsigned
  58. MachOAtomGraphBuilder::getPointerSize(const object::MachOObjectFile &Obj) {
  59. return Obj.is64Bit() ? 8 : 4;
  60. }
  61. support::endianness
  62. MachOAtomGraphBuilder::getEndianness(const object::MachOObjectFile &Obj) {
  63. return Obj.isLittleEndian() ? support::little : support::big;
  64. }
  65. MachOAtomGraphBuilder::MachOSection &MachOAtomGraphBuilder::getCommonSection() {
  66. if (!CommonSymbolsSection) {
  67. auto Prot = static_cast<sys::Memory::ProtectionFlags>(
  68. sys::Memory::MF_READ | sys::Memory::MF_WRITE);
  69. auto &GenericSection = G->createSection("<common>", 1, Prot, true);
  70. CommonSymbolsSection = MachOSection(GenericSection);
  71. }
  72. return *CommonSymbolsSection;
  73. }
  74. Error MachOAtomGraphBuilder::parseSections() {
  75. for (auto &SecRef : Obj.sections()) {
  76. assert((SecRef.getAlignment() <= std::numeric_limits<uint32_t>::max()) &&
  77. "Section alignment does not fit in 32 bits");
  78. Expected<StringRef> NameOrErr = SecRef.getName();
  79. if (!NameOrErr)
  80. return NameOrErr.takeError();
  81. StringRef Name = *NameOrErr;
  82. unsigned SectionIndex = SecRef.getIndex() + 1;
  83. uint32_t Align = SecRef.getAlignment();
  84. if (!isPowerOf2_32(Align))
  85. return make_error<JITLinkError>("Section " + Name +
  86. " has non-power-of-2 "
  87. "alignment");
  88. // FIXME: Get real section permissions
  89. // How, exactly, on MachO?
  90. sys::Memory::ProtectionFlags Prot;
  91. if (SecRef.isText())
  92. Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
  93. sys::Memory::MF_EXEC);
  94. else
  95. Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
  96. sys::Memory::MF_WRITE);
  97. auto &GenericSection = G->createSection(Name, Align, Prot, SecRef.isBSS());
  98. LLVM_DEBUG({
  99. dbgs() << "Adding section " << Name << ": "
  100. << format("0x%016" PRIx64, SecRef.getAddress())
  101. << ", align: " << SecRef.getAlignment() << "\n";
  102. });
  103. assert(!Sections.count(SectionIndex) && "Section index already in use");
  104. auto &MachOSec =
  105. Sections
  106. .try_emplace(SectionIndex, GenericSection, SecRef.getAddress(),
  107. SecRef.getAlignment())
  108. .first->second;
  109. if (!SecRef.isVirtual()) {
  110. // If this section has content then record it.
  111. Expected<StringRef> Content = SecRef.getContents();
  112. if (!Content)
  113. return Content.takeError();
  114. if (Content->size() != SecRef.getSize())
  115. return make_error<JITLinkError>("Section content size does not match "
  116. "declared size for " +
  117. Name);
  118. MachOSec.setContent(*Content);
  119. } else {
  120. // If this is a zero-fill section then just record the size.
  121. MachOSec.setZeroFill(SecRef.getSize());
  122. }
  123. uint32_t SectionFlags =
  124. Obj.is64Bit() ? Obj.getSection64(SecRef.getRawDataRefImpl()).flags
  125. : Obj.getSection(SecRef.getRawDataRefImpl()).flags;
  126. MachOSec.setNoDeadStrip(SectionFlags & MachO::S_ATTR_NO_DEAD_STRIP);
  127. }
  128. return Error::success();
  129. }
  130. // Adds atoms with identified start addresses (but not lengths) for all named
  131. // atoms.
  132. // Also, for every section that contains named atoms, but does not have an
  133. // atom at offset zero of that section, constructs an anonymous atom covering
  134. // that range.
  135. Error MachOAtomGraphBuilder::addNonCustomAtoms() {
  136. using AddrToAtomMap = std::map<JITTargetAddress, DefinedAtom *>;
  137. DenseMap<MachOSection *, AddrToAtomMap> SecToAtoms;
  138. DenseMap<MachOSection *, unsigned> FirstOrdinal;
  139. std::vector<DefinedAtom *> AltEntryAtoms;
  140. DenseSet<StringRef> ProcessedSymbols; // Used to check for duplicate defs.
  141. for (auto SymI = Obj.symbol_begin(), SymE = Obj.symbol_end(); SymI != SymE;
  142. ++SymI) {
  143. object::SymbolRef Sym(SymI->getRawDataRefImpl(), &Obj);
  144. auto Name = Sym.getName();
  145. if (!Name)
  146. return Name.takeError();
  147. // Bail out on duplicate definitions: There should never be more than one
  148. // definition for a symbol in a given object file.
  149. if (ProcessedSymbols.count(*Name))
  150. return make_error<JITLinkError>("Duplicate definition within object: " +
  151. *Name);
  152. else
  153. ProcessedSymbols.insert(*Name);
  154. auto Addr = Sym.getAddress();
  155. if (!Addr)
  156. return Addr.takeError();
  157. auto SymType = Sym.getType();
  158. if (!SymType)
  159. return SymType.takeError();
  160. auto Flags = Sym.getFlags();
  161. if (Flags & object::SymbolRef::SF_Undefined) {
  162. LLVM_DEBUG(dbgs() << "Adding undef atom \"" << *Name << "\"\n");
  163. G->addExternalAtom(*Name);
  164. continue;
  165. } else if (Flags & object::SymbolRef::SF_Absolute) {
  166. LLVM_DEBUG(dbgs() << "Adding absolute \"" << *Name << "\" addr: "
  167. << format("0x%016" PRIx64, *Addr) << "\n");
  168. auto &A = G->addAbsoluteAtom(*Name, *Addr);
  169. A.setGlobal(Flags & object::SymbolRef::SF_Global);
  170. A.setExported(Flags & object::SymbolRef::SF_Exported);
  171. A.setWeak(Flags & object::SymbolRef::SF_Weak);
  172. continue;
  173. } else if (Flags & object::SymbolRef::SF_Common) {
  174. LLVM_DEBUG({
  175. dbgs() << "Adding common \"" << *Name
  176. << "\" addr: " << format("0x%016" PRIx64, *Addr) << "\n";
  177. });
  178. auto &A =
  179. G->addCommonAtom(getCommonSection().getGenericSection(), *Name, *Addr,
  180. std::max(Sym.getAlignment(), 1U),
  181. Obj.getCommonSymbolSize(Sym.getRawDataRefImpl()));
  182. A.setGlobal(Flags & object::SymbolRef::SF_Global);
  183. A.setExported(Flags & object::SymbolRef::SF_Exported);
  184. continue;
  185. }
  186. LLVM_DEBUG(dbgs() << "Adding defined atom \"" << *Name << "\"\n");
  187. // This atom is neither undefined nor absolute, so it must be defined in
  188. // this object. Get its section index.
  189. auto SecItr = Sym.getSection();
  190. if (!SecItr)
  191. return SecItr.takeError();
  192. uint64_t SectionIndex = (*SecItr)->getIndex() + 1;
  193. LLVM_DEBUG(dbgs() << " to section index " << SectionIndex << "\n");
  194. auto SecByIndexItr = Sections.find(SectionIndex);
  195. if (SecByIndexItr == Sections.end())
  196. return make_error<JITLinkError>("Unrecognized section index in macho");
  197. auto &Sec = SecByIndexItr->second;
  198. auto &DA = G->addDefinedAtom(Sec.getGenericSection(), *Name, *Addr,
  199. std::max(Sym.getAlignment(), 1U));
  200. DA.setGlobal(Flags & object::SymbolRef::SF_Global);
  201. DA.setExported(Flags & object::SymbolRef::SF_Exported);
  202. DA.setWeak(Flags & object::SymbolRef::SF_Weak);
  203. DA.setCallable(*SymType & object::SymbolRef::ST_Function);
  204. // Check NDesc flags.
  205. {
  206. uint16_t NDesc = 0;
  207. if (Obj.is64Bit())
  208. NDesc = Obj.getSymbol64TableEntry(SymI->getRawDataRefImpl()).n_desc;
  209. else
  210. NDesc = Obj.getSymbolTableEntry(SymI->getRawDataRefImpl()).n_desc;
  211. // Record atom for alt-entry post-processing (where the layout-next
  212. // constraints will be added).
  213. if (NDesc & MachO::N_ALT_ENTRY)
  214. AltEntryAtoms.push_back(&DA);
  215. // If this atom has a no-dead-strip attr attached then mark it live.
  216. if (NDesc & MachO::N_NO_DEAD_STRIP)
  217. DA.setLive(true);
  218. }
  219. LLVM_DEBUG({
  220. dbgs() << " Added " << *Name
  221. << " addr: " << format("0x%016" PRIx64, *Addr)
  222. << ", align: " << DA.getAlignment()
  223. << ", section: " << Sec.getGenericSection().getName() << "\n";
  224. });
  225. auto &SecAtoms = SecToAtoms[&Sec];
  226. SecAtoms[DA.getAddress() - Sec.getAddress()] = &DA;
  227. }
  228. // Add anonymous atoms.
  229. for (auto &KV : Sections) {
  230. auto &S = KV.second;
  231. // Skip empty sections.
  232. if (S.empty())
  233. continue;
  234. // Skip sections with custom handling.
  235. if (CustomAtomizeFunctions.count(S.getName()))
  236. continue;
  237. auto SAI = SecToAtoms.find(&S);
  238. // If S is not in the SecToAtoms map then it contained no named atom. Add
  239. // one anonymous atom to cover the whole section.
  240. if (SAI == SecToAtoms.end()) {
  241. SecToAtoms[&S][0] = &G->addAnonymousAtom(
  242. S.getGenericSection(), S.getAddress(), S.getAlignment());
  243. continue;
  244. }
  245. // Otherwise, check whether this section had an atom covering offset zero.
  246. // If not, add one.
  247. auto &SecAtoms = SAI->second;
  248. if (!SecAtoms.count(0))
  249. SecAtoms[0] = &G->addAnonymousAtom(S.getGenericSection(), S.getAddress(),
  250. S.getAlignment());
  251. }
  252. LLVM_DEBUG(dbgs() << "MachOGraphBuilder setting atom content\n");
  253. // Set atom contents and any section-based flags.
  254. for (auto &KV : SecToAtoms) {
  255. auto &S = *KV.first;
  256. auto &SecAtoms = KV.second;
  257. // Iterate the atoms in reverse order and set up their contents.
  258. JITTargetAddress LastAtomAddr = S.getSize();
  259. for (auto I = SecAtoms.rbegin(), E = SecAtoms.rend(); I != E; ++I) {
  260. auto Offset = I->first;
  261. auto &A = *I->second;
  262. LLVM_DEBUG({
  263. dbgs() << " " << A << " to [ " << S.getAddress() + Offset << " .. "
  264. << S.getAddress() + LastAtomAddr << " ]\n";
  265. });
  266. if (S.isZeroFill())
  267. A.setZeroFill(LastAtomAddr - Offset);
  268. else
  269. A.setContent(S.getContent().substr(Offset, LastAtomAddr - Offset));
  270. // If the section has no-dead-strip set then mark the atom as live.
  271. if (S.isNoDeadStrip())
  272. A.setLive(true);
  273. LastAtomAddr = Offset;
  274. }
  275. }
  276. LLVM_DEBUG(dbgs() << "Adding alt-entry starts\n");
  277. // Sort alt-entry atoms by address in ascending order.
  278. llvm::sort(AltEntryAtoms.begin(), AltEntryAtoms.end(),
  279. [](const DefinedAtom *LHS, const DefinedAtom *RHS) {
  280. return LHS->getAddress() < RHS->getAddress();
  281. });
  282. // Process alt-entry atoms in address order to build the table of alt-entry
  283. // atoms to alt-entry chain starts.
  284. for (auto *DA : AltEntryAtoms) {
  285. assert(!AltEntryStarts.count(DA) && "Duplicate entry in AltEntryStarts");
  286. // DA is an alt-entry atom. Look for the predecessor atom that it is locked
  287. // to, bailing out if we do not find one.
  288. auto AltEntryPred = G->findAtomByAddress(DA->getAddress() - 1);
  289. if (!AltEntryPred)
  290. return AltEntryPred.takeError();
  291. // Add a LayoutNext edge from the predecessor to this atom.
  292. AltEntryPred->setLayoutNext(*DA);
  293. // Check to see whether the predecessor itself is an alt-entry atom.
  294. auto AltEntryStartItr = AltEntryStarts.find(&*AltEntryPred);
  295. if (AltEntryStartItr != AltEntryStarts.end()) {
  296. // If the predecessor was an alt-entry atom then re-use its value.
  297. LLVM_DEBUG({
  298. dbgs() << " " << *DA << " -> " << *AltEntryStartItr->second
  299. << " (based on existing entry for " << *AltEntryPred << ")\n";
  300. });
  301. AltEntryStarts[DA] = AltEntryStartItr->second;
  302. } else {
  303. // If the predecessor does not have an entry then add an entry for this
  304. // atom (i.e. the alt_entry atom) and a self-reference entry for the
  305. /// predecessory atom that is the start of this chain.
  306. LLVM_DEBUG({
  307. dbgs() << " " << *AltEntryPred << " -> " << *AltEntryPred << "\n"
  308. << " " << *DA << " -> " << *AltEntryPred << "\n";
  309. });
  310. AltEntryStarts[&*AltEntryPred] = &*AltEntryPred;
  311. AltEntryStarts[DA] = &*AltEntryPred;
  312. }
  313. }
  314. return Error::success();
  315. }
  316. Error MachOAtomGraphBuilder::addAtoms() {
  317. // Add all named atoms.
  318. if (auto Err = addNonCustomAtoms())
  319. return Err;
  320. // Process special sections.
  321. for (auto &KV : Sections) {
  322. auto &S = KV.second;
  323. auto HI = CustomAtomizeFunctions.find(S.getGenericSection().getName());
  324. if (HI != CustomAtomizeFunctions.end()) {
  325. auto &Atomize = HI->second;
  326. if (auto Err = Atomize(S))
  327. return Err;
  328. }
  329. }
  330. return Error::success();
  331. }
  332. } // end namespace jitlink
  333. } // end namespace llvm