xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===-- llvm-jitlink-macho.cpp -- MachO parsing support for llvm-jitlink --===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // MachO parsing support for llvm-jitlink.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "llvm-jitlink.h"
1409467b48Spatrick 
1509467b48Spatrick #include "llvm/Support/Error.h"
1609467b48Spatrick #include "llvm/Support/Path.h"
1709467b48Spatrick 
18097a140dSpatrick #define DEBUG_TYPE "llvm_jitlink"
1909467b48Spatrick 
2009467b48Spatrick using namespace llvm;
2109467b48Spatrick using namespace llvm::jitlink;
2209467b48Spatrick 
isMachOGOTSection(Section & S)2309467b48Spatrick static bool isMachOGOTSection(Section &S) { return S.getName() == "$__GOT"; }
2409467b48Spatrick 
isMachOStubsSection(Section & S)2509467b48Spatrick static bool isMachOStubsSection(Section &S) {
2609467b48Spatrick   return S.getName() == "$__STUBS";
2709467b48Spatrick }
2809467b48Spatrick 
getFirstRelocationEdge(LinkGraph & G,Block & B)2909467b48Spatrick static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
30*d415bd75Srobert   auto EItr =
31*d415bd75Srobert       llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
3209467b48Spatrick   if (EItr == B.edges().end())
3309467b48Spatrick     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
3409467b48Spatrick                                        B.getSection().getName() +
3509467b48Spatrick                                        "\" has no relocations",
3609467b48Spatrick                                    inconvertibleErrorCode());
3709467b48Spatrick   return *EItr;
3809467b48Spatrick }
3909467b48Spatrick 
getMachOGOTTarget(LinkGraph & G,Block & B)4009467b48Spatrick static Expected<Symbol &> getMachOGOTTarget(LinkGraph &G, Block &B) {
4109467b48Spatrick   auto E = getFirstRelocationEdge(G, B);
4209467b48Spatrick   if (!E)
4309467b48Spatrick     return E.takeError();
4409467b48Spatrick   auto &TargetSym = E->getTarget();
4509467b48Spatrick   if (!TargetSym.hasName())
4609467b48Spatrick     return make_error<StringError>(
4709467b48Spatrick         "GOT entry in " + G.getName() + ", \"" +
4809467b48Spatrick             TargetSym.getBlock().getSection().getName() +
4909467b48Spatrick             "\" points to anonymous "
5009467b48Spatrick             "symbol",
5109467b48Spatrick         inconvertibleErrorCode());
5209467b48Spatrick   return TargetSym;
5309467b48Spatrick }
5409467b48Spatrick 
getMachOStubTarget(LinkGraph & G,Block & B)5509467b48Spatrick static Expected<Symbol &> getMachOStubTarget(LinkGraph &G, Block &B) {
5609467b48Spatrick   auto E = getFirstRelocationEdge(G, B);
5709467b48Spatrick   if (!E)
5809467b48Spatrick     return E.takeError();
5909467b48Spatrick   auto &GOTSym = E->getTarget();
6009467b48Spatrick   if (!GOTSym.isDefined() || !isMachOGOTSection(GOTSym.getBlock().getSection()))
6109467b48Spatrick     return make_error<StringError>(
6209467b48Spatrick         "Stubs entry in " + G.getName() + ", \"" +
6309467b48Spatrick             GOTSym.getBlock().getSection().getName() +
6409467b48Spatrick             "\" does not point to GOT entry",
6509467b48Spatrick         inconvertibleErrorCode());
6609467b48Spatrick   return getMachOGOTTarget(G, GOTSym.getBlock());
6709467b48Spatrick }
6809467b48Spatrick 
6909467b48Spatrick namespace llvm {
7009467b48Spatrick 
registerMachOGraphInfo(Session & S,LinkGraph & G)71097a140dSpatrick Error registerMachOGraphInfo(Session &S, LinkGraph &G) {
7209467b48Spatrick   auto FileName = sys::path::filename(G.getName());
7309467b48Spatrick   if (S.FileInfos.count(FileName)) {
7409467b48Spatrick     return make_error<StringError>("When -check is passed, file names must be "
7509467b48Spatrick                                    "distinct (duplicate: \"" +
7609467b48Spatrick                                        FileName + "\")",
7709467b48Spatrick                                    inconvertibleErrorCode());
7809467b48Spatrick   }
7909467b48Spatrick 
8009467b48Spatrick   auto &FileInfo = S.FileInfos[FileName];
8109467b48Spatrick   LLVM_DEBUG({
8209467b48Spatrick     dbgs() << "Registering MachO file info for \"" << FileName << "\"\n";
8309467b48Spatrick   });
8409467b48Spatrick   for (auto &Sec : G.sections()) {
8509467b48Spatrick     LLVM_DEBUG({
8609467b48Spatrick       dbgs() << "  Section \"" << Sec.getName() << "\": "
87*d415bd75Srobert              << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
8809467b48Spatrick              << "\n";
8909467b48Spatrick     });
9009467b48Spatrick 
9109467b48Spatrick     // Skip empty sections.
92*d415bd75Srobert     if (Sec.symbols().empty())
9309467b48Spatrick       continue;
9409467b48Spatrick 
9509467b48Spatrick     if (FileInfo.SectionInfos.count(Sec.getName()))
9609467b48Spatrick       return make_error<StringError>("Encountered duplicate section name \"" +
9709467b48Spatrick                                          Sec.getName() + "\" in \"" + FileName +
9809467b48Spatrick                                          "\"",
9909467b48Spatrick                                      inconvertibleErrorCode());
10009467b48Spatrick 
10109467b48Spatrick     bool isGOTSection = isMachOGOTSection(Sec);
10209467b48Spatrick     bool isStubsSection = isMachOStubsSection(Sec);
10309467b48Spatrick 
10409467b48Spatrick     bool SectionContainsContent = false;
10509467b48Spatrick     bool SectionContainsZeroFill = false;
10609467b48Spatrick 
10709467b48Spatrick     auto *FirstSym = *Sec.symbols().begin();
10809467b48Spatrick     auto *LastSym = FirstSym;
10909467b48Spatrick     for (auto *Sym : Sec.symbols()) {
11009467b48Spatrick       if (Sym->getAddress() < FirstSym->getAddress())
11109467b48Spatrick         FirstSym = Sym;
11209467b48Spatrick       if (Sym->getAddress() > LastSym->getAddress())
11309467b48Spatrick         LastSym = Sym;
11409467b48Spatrick       if (isGOTSection) {
11509467b48Spatrick         if (Sym->isSymbolZeroFill())
11609467b48Spatrick           return make_error<StringError>("zero-fill atom in GOT section",
11709467b48Spatrick                                          inconvertibleErrorCode());
11809467b48Spatrick 
11909467b48Spatrick         if (auto TS = getMachOGOTTarget(G, Sym->getBlock()))
120*d415bd75Srobert           FileInfo.GOTEntryInfos[TS->getName()] = {
121*d415bd75Srobert               Sym->getSymbolContent(), Sym->getAddress().getValue()};
12209467b48Spatrick         else
12309467b48Spatrick           return TS.takeError();
12409467b48Spatrick         SectionContainsContent = true;
12509467b48Spatrick       } else if (isStubsSection) {
12609467b48Spatrick         if (Sym->isSymbolZeroFill())
12709467b48Spatrick           return make_error<StringError>("zero-fill atom in Stub section",
12809467b48Spatrick                                          inconvertibleErrorCode());
12909467b48Spatrick 
13009467b48Spatrick         if (auto TS = getMachOStubTarget(G, Sym->getBlock()))
13109467b48Spatrick           FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
132*d415bd75Srobert                                                Sym->getAddress().getValue()};
13309467b48Spatrick         else
13409467b48Spatrick           return TS.takeError();
13509467b48Spatrick         SectionContainsContent = true;
13609467b48Spatrick       } else if (Sym->hasName()) {
13709467b48Spatrick         if (Sym->isSymbolZeroFill()) {
138*d415bd75Srobert           S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
139*d415bd75Srobert                                            Sym->getAddress().getValue()};
14009467b48Spatrick           SectionContainsZeroFill = true;
14109467b48Spatrick         } else {
14209467b48Spatrick           S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
143*d415bd75Srobert                                            Sym->getAddress().getValue()};
14409467b48Spatrick           SectionContainsContent = true;
14509467b48Spatrick         }
14609467b48Spatrick       }
14709467b48Spatrick     }
14809467b48Spatrick 
149*d415bd75Srobert     auto SecAddr = FirstSym->getAddress();
150*d415bd75Srobert     auto SecSize =
15109467b48Spatrick         (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -
15209467b48Spatrick         SecAddr;
15309467b48Spatrick 
15409467b48Spatrick     if (SectionContainsZeroFill && SectionContainsContent)
15509467b48Spatrick       return make_error<StringError>("Mixed zero-fill and content sections not "
15609467b48Spatrick                                      "supported yet",
15709467b48Spatrick                                      inconvertibleErrorCode());
15809467b48Spatrick     if (SectionContainsZeroFill)
159*d415bd75Srobert       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};
16009467b48Spatrick     else
16109467b48Spatrick       FileInfo.SectionInfos[Sec.getName()] = {
16273471bf0Spatrick           ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
163*d415bd75Srobert           SecAddr.getValue()};
16409467b48Spatrick   }
16509467b48Spatrick 
16609467b48Spatrick   return Error::success();
16709467b48Spatrick }
16809467b48Spatrick 
16909467b48Spatrick } // end namespace llvm
170