xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp (revision 23085ec36d0821d4e3d69f4acf75d47ed0789837)
1 //===-- llvm-jitlink-macho.cpp -- MachO parsing support for llvm-jitlink --===//
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 // MachO parsing support for llvm-jitlink.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm-jitlink.h"
14 
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/Path.h"
17 
18 #define DEBUG_TYPE "llvm-jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 
23 static bool isMachOGOTSection(Section &S) { return S.getName() == "$__GOT"; }
24 
25 static bool isMachOStubsSection(Section &S) {
26   return S.getName() == "$__STUBS";
27 }
28 
29 static Expected<Edge &> getFirstRelocationEdge(AtomGraph &G, DefinedAtom &DA) {
30   auto EItr = std::find_if(DA.edges().begin(), DA.edges().end(),
31                            [](Edge &E) { return E.isRelocation(); });
32   if (EItr == DA.edges().end())
33     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
34                                        DA.getSection().getName() +
35                                        "\" has no relocations",
36                                    inconvertibleErrorCode());
37   return *EItr;
38 }
39 
40 static Expected<Atom &> getMachOGOTTarget(AtomGraph &G, DefinedAtom &DA) {
41   auto E = getFirstRelocationEdge(G, DA);
42   if (!E)
43     return E.takeError();
44   auto &TA = E->getTarget();
45   if (!TA.hasName())
46     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
47                                        DA.getSection().getName() +
48                                        "\" points to anonymous "
49                                        "atom",
50                                    inconvertibleErrorCode());
51   if (TA.isDefined() || TA.isAbsolute())
52     return make_error<StringError>(
53         "GOT entry \"" + TA.getName() + "\" in " + G.getName() + ", \"" +
54             DA.getSection().getName() + "\" does not point to an external atom",
55         inconvertibleErrorCode());
56   return TA;
57 }
58 
59 static Expected<Atom &> getMachOStubTarget(AtomGraph &G, DefinedAtom &DA) {
60   auto E = getFirstRelocationEdge(G, DA);
61   if (!E)
62     return E.takeError();
63   auto &GOTA = E->getTarget();
64   if (!GOTA.isDefined() ||
65       !isMachOGOTSection(static_cast<DefinedAtom &>(GOTA).getSection()))
66     return make_error<StringError>("Stubs entry in " + G.getName() + ", \"" +
67                                        DA.getSection().getName() +
68                                        "\" does not point to GOT entry",
69                                    inconvertibleErrorCode());
70   return getMachOGOTTarget(G, static_cast<DefinedAtom &>(GOTA));
71 }
72 
73 namespace llvm {
74 
75 Error registerMachOStubsAndGOT(Session &S, AtomGraph &G) {
76   auto FileName = sys::path::filename(G.getName());
77   if (S.FileInfos.count(FileName)) {
78     return make_error<StringError>("When -check is passed, file names must be "
79                                    "distinct (duplicate: \"" +
80                                        FileName + "\")",
81                                    inconvertibleErrorCode());
82   }
83 
84   auto &FileInfo = S.FileInfos[FileName];
85   LLVM_DEBUG({
86     dbgs() << "Registering MachO file info for \"" << FileName << "\"\n";
87   });
88   for (auto &Sec : G.sections()) {
89     LLVM_DEBUG({
90       dbgs() << "  Section \"" << Sec.getName() << "\": "
91              << (Sec.atoms_empty() ? "empty. skipping." : "processing...")
92              << "\n";
93     });
94 
95     // Skip empty sections.
96     if (Sec.atoms_empty())
97       continue;
98 
99     if (FileInfo.SectionInfos.count(Sec.getName()))
100       return make_error<StringError>("Encountered duplicate section name \"" +
101                                          Sec.getName() + "\" in \"" + FileName +
102                                          "\"",
103                                      inconvertibleErrorCode());
104 
105     bool isGOTSection = isMachOGOTSection(Sec);
106     bool isStubsSection = isMachOStubsSection(Sec);
107 
108     auto *FirstAtom = *Sec.atoms().begin();
109     auto *LastAtom = FirstAtom;
110     for (auto *DA : Sec.atoms()) {
111       if (DA->getAddress() < FirstAtom->getAddress())
112         FirstAtom = DA;
113       if (DA->getAddress() > LastAtom->getAddress())
114         LastAtom = DA;
115       if (isGOTSection) {
116         if (Sec.isZeroFill())
117           return make_error<StringError>("Content atom in zero-fill section",
118                                          inconvertibleErrorCode());
119 
120         if (auto TA = getMachOGOTTarget(G, *DA)) {
121           FileInfo.GOTEntryInfos[TA->getName()] = {DA->getContent(),
122                                                    DA->getAddress()};
123         } else
124           return TA.takeError();
125       } else if (isStubsSection) {
126         if (Sec.isZeroFill())
127           return make_error<StringError>("Content atom in zero-fill section",
128                                          inconvertibleErrorCode());
129 
130         if (auto TA = getMachOStubTarget(G, *DA))
131           FileInfo.StubInfos[TA->getName()] = {DA->getContent(),
132                                                DA->getAddress()};
133         else
134           return TA.takeError();
135       } else if (DA->hasName() && DA->isGlobal()) {
136         if (DA->isZeroFill())
137           S.SymbolInfos[DA->getName()] = {DA->getSize(), DA->getAddress()};
138         else {
139           if (Sec.isZeroFill())
140             return make_error<StringError>("Content atom in zero-fill section",
141                                            inconvertibleErrorCode());
142           S.SymbolInfos[DA->getName()] = {DA->getContent(), DA->getAddress()};
143         }
144       }
145     }
146 
147     JITTargetAddress SecAddr = FirstAtom->getAddress();
148     uint64_t SecSize = (LastAtom->getAddress() + LastAtom->getSize()) -
149                        FirstAtom->getAddress();
150 
151     if (Sec.isZeroFill())
152       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr};
153     else
154       FileInfo.SectionInfos[Sec.getName()] = {
155           StringRef(FirstAtom->getContent().data(), SecSize), SecAddr};
156   }
157 
158   return Error::success();
159 }
160 
161 } // end namespace llvm
162