blob: c3a12421dacd71fc7ef3e0de75305b882f5891a5 [file] [log] [blame]
//===-- llvm-jitlink-macho.cpp -- MachO parsing support for llvm-jitlink --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// .
//
//===----------------------------------------------------------------------===//
#include "llvm-jitlink.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#define DEBUG_TYPE "llvm-jitlink"
using namespace llvm;
using namespace llvm::jitlink;
static bool isMachOGOTSection(Section &S) { return S.getName() == "$__GOT"; }
static bool isMachOStubsSection(Section &S) {
return S.getName() == "$__STUBS";
}
static Expected<Edge &> getFirstRelocationEdge(AtomGraph &G, DefinedAtom &DA) {
auto EItr = std::find_if(DA.edges().begin(), DA.edges().end(),
[](Edge &E) { return E.isRelocation(); });
if (EItr == DA.edges().end())
return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
DA.getSection().getName() +
"\" has no relocations",
inconvertibleErrorCode());
return *EItr;
}
static Expected<Atom &> getMachOGOTTarget(AtomGraph &G, DefinedAtom &DA) {
auto E = getFirstRelocationEdge(G, DA);
if (!E)
return E.takeError();
auto &TA = E->getTarget();
if (!TA.hasName())
return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
DA.getSection().getName() +
"\" points to anonymous "
"atom",
inconvertibleErrorCode());
if (TA.isDefined() || TA.isAbsolute())
return make_error<StringError>(
"GOT entry \"" + TA.getName() + "\" in " + G.getName() + ", \"" +
DA.getSection().getName() + "\" does not point to an external atom",
inconvertibleErrorCode());
return TA;
}
static Expected<Atom &> getMachOStubTarget(AtomGraph &G, DefinedAtom &DA) {
auto E = getFirstRelocationEdge(G, DA);
if (!E)
return E.takeError();
auto &GOTA = E->getTarget();
if (!GOTA.isDefined() ||
!isMachOGOTSection(static_cast<DefinedAtom &>(GOTA).getSection()))
return make_error<StringError>("Stubs entry in " + G.getName() + ", \"" +
DA.getSection().getName() +
"\" does not point to GOT entry",
inconvertibleErrorCode());
return getMachOGOTTarget(G, static_cast<DefinedAtom &>(GOTA));
}
namespace llvm {
Error registerMachOStubsAndGOT(Session &S, AtomGraph &G) {
auto FileName = sys::path::filename(G.getName());
if (S.FileInfos.count(FileName)) {
return make_error<StringError>("When -check is passed, file names must be "
"distinct (duplicate: \"" +
FileName + "\")",
inconvertibleErrorCode());
}
auto &FileInfo = S.FileInfos[FileName];
LLVM_DEBUG({
dbgs() << "Registering MachO file info for \"" << FileName << "\"\n";
});
for (auto &Sec : G.sections()) {
LLVM_DEBUG({
dbgs() << " Section \"" << Sec.getName() << "\": "
<< (Sec.atoms_empty() ? "empty. skipping." : "processing...")
<< "\n";
});
// Skip empty sections.
if (Sec.atoms_empty())
continue;
if (FileInfo.SectionInfos.count(Sec.getName()))
return make_error<StringError>("Encountered duplicate section name \"" +
Sec.getName() + "\" in \"" + FileName +
"\"",
inconvertibleErrorCode());
bool isGOTSection = isMachOGOTSection(Sec);
bool isStubsSection = isMachOStubsSection(Sec);
auto &SectionInfo = FileInfo.SectionInfos[Sec.getName()];
auto *FirstAtom = *Sec.atoms().begin();
auto *LastAtom = FirstAtom;
for (auto *DA : Sec.atoms()) {
if (DA->getAddress() < FirstAtom->getAddress())
FirstAtom = DA;
if (DA->getAddress() > LastAtom->getAddress())
LastAtom = DA;
if (isGOTSection) {
if (auto TA = getMachOGOTTarget(G, *DA)) {
FileInfo.GOTEntryInfos[TA->getName()] = {DA->getContent(),
DA->getAddress()};
} else
return TA.takeError();
} else if (isStubsSection) {
if (auto TA = getMachOStubTarget(G, *DA))
FileInfo.StubInfos[TA->getName()] = {DA->getContent(),
DA->getAddress()};
else
return TA.takeError();
} else if (DA->hasName() && DA->isGlobal())
S.SymbolInfos[DA->getName()] = {DA->getContent(), DA->getAddress()};
}
const char *StartAddr = FirstAtom->getContent().data();
const char *EndAddr =
LastAtom->getContent().data() + LastAtom->getContent().size();
SectionInfo.TargetAddress = FirstAtom->getAddress();
SectionInfo.Content = StringRef(StartAddr, EndAddr - StartAddr);
}
return Error::success();
}
} // end namespace llvm