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