forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			314 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
 | 
						|
 | 
						|
#include "llvm/BinaryFormat/Magic.h"
 | 
						|
#include "llvm/ExecutionEngine/JITLink/MachO.h"
 | 
						|
#include "llvm/Support/Format.h"
 | 
						|
#include "llvm/Support/ManagedStatic.h"
 | 
						|
#include "llvm/Support/MemoryBuffer.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::object;
 | 
						|
 | 
						|
#define DEBUG_TYPE "jitlink"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
enum JITLinkErrorCode { GenericJITLinkError = 1 };
 | 
						|
 | 
						|
// FIXME: This class is only here to support the transition to llvm::Error. It
 | 
						|
// will be removed once this transition is complete. Clients should prefer to
 | 
						|
// deal with the Error value directly, rather than converting to error_code.
 | 
						|
class JITLinkerErrorCategory : public std::error_category {
 | 
						|
public:
 | 
						|
  const char *name() const noexcept override { return "runtimedyld"; }
 | 
						|
 | 
						|
  std::string message(int Condition) const override {
 | 
						|
    switch (static_cast<JITLinkErrorCode>(Condition)) {
 | 
						|
    case GenericJITLinkError:
 | 
						|
      return "Generic JITLink error";
 | 
						|
    }
 | 
						|
    llvm_unreachable("Unrecognized JITLinkErrorCode");
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory;
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace jitlink {
 | 
						|
 | 
						|
char JITLinkError::ID = 0;
 | 
						|
 | 
						|
void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
 | 
						|
 | 
						|
std::error_code JITLinkError::convertToErrorCode() const {
 | 
						|
  return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory);
 | 
						|
}
 | 
						|
 | 
						|
const char *getGenericEdgeKindName(Edge::Kind K) {
 | 
						|
  switch (K) {
 | 
						|
  case Edge::Invalid:
 | 
						|
    return "INVALID RELOCATION";
 | 
						|
  case Edge::KeepAlive:
 | 
						|
    return "Keep-Alive";
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Unrecognized relocation kind");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const char *getLinkageName(Linkage L) {
 | 
						|
  switch (L) {
 | 
						|
  case Linkage::Strong:
 | 
						|
    return "strong";
 | 
						|
  case Linkage::Weak:
 | 
						|
    return "weak";
 | 
						|
  }
 | 
						|
  llvm_unreachable("Unrecognized llvm.jitlink.Linkage enum");
 | 
						|
}
 | 
						|
 | 
						|
const char *getScopeName(Scope S) {
 | 
						|
  switch (S) {
 | 
						|
  case Scope::Default:
 | 
						|
    return "default";
 | 
						|
  case Scope::Hidden:
 | 
						|
    return "hidden";
 | 
						|
  case Scope::Local:
 | 
						|
    return "local";
 | 
						|
  }
 | 
						|
  llvm_unreachable("Unrecognized llvm.jitlink.Scope enum");
 | 
						|
}
 | 
						|
 | 
						|
raw_ostream &operator<<(raw_ostream &OS, const Block &B) {
 | 
						|
  return OS << formatv("{0:x16}", B.getAddress()) << " -- "
 | 
						|
            << formatv("{0:x16}", B.getAddress() + B.getSize()) << ": "
 | 
						|
            << (B.isZeroFill() ? "zero-fill" : "content")
 | 
						|
            << ", align = " << B.getAlignment()
 | 
						|
            << ", align-ofs = " << B.getAlignmentOffset()
 | 
						|
            << ", section = " << B.getSection().getName();
 | 
						|
}
 | 
						|
 | 
						|
raw_ostream &operator<<(raw_ostream &OS, const Symbol &Sym) {
 | 
						|
  OS << "<";
 | 
						|
  if (Sym.getName().empty())
 | 
						|
    OS << "*anon*";
 | 
						|
  else
 | 
						|
    OS << Sym.getName();
 | 
						|
  OS << ": flags = ";
 | 
						|
  switch (Sym.getLinkage()) {
 | 
						|
  case Linkage::Strong:
 | 
						|
    OS << 'S';
 | 
						|
    break;
 | 
						|
  case Linkage::Weak:
 | 
						|
    OS << 'W';
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  switch (Sym.getScope()) {
 | 
						|
  case Scope::Default:
 | 
						|
    OS << 'D';
 | 
						|
    break;
 | 
						|
  case Scope::Hidden:
 | 
						|
    OS << 'H';
 | 
						|
    break;
 | 
						|
  case Scope::Local:
 | 
						|
    OS << 'L';
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  OS << (Sym.isLive() ? '+' : '-')
 | 
						|
     << ", size = " << formatv("{0:x8}", Sym.getSize())
 | 
						|
     << ", addr = " << formatv("{0:x16}", Sym.getAddress()) << " ("
 | 
						|
     << formatv("{0:x16}", Sym.getAddressable().getAddress()) << " + "
 | 
						|
     << formatv("{0:x8}", Sym.getOffset());
 | 
						|
  if (Sym.isDefined())
 | 
						|
    OS << " " << Sym.getBlock().getSection().getName();
 | 
						|
  OS << ")>";
 | 
						|
  return OS;
 | 
						|
}
 | 
						|
 | 
						|
void printEdge(raw_ostream &OS, const Block &B, const Edge &E,
 | 
						|
               StringRef EdgeKindName) {
 | 
						|
  OS << "edge@" << formatv("{0:x16}", B.getAddress() + E.getOffset()) << ": "
 | 
						|
     << formatv("{0:x16}", B.getAddress()) << " + " << E.getOffset() << " -- "
 | 
						|
     << EdgeKindName << " -> " << E.getTarget() << " + " << E.getAddend();
 | 
						|
}
 | 
						|
 | 
						|
Section::~Section() {
 | 
						|
  for (auto *Sym : Symbols)
 | 
						|
    Sym->~Symbol();
 | 
						|
  for (auto *B : Blocks)
 | 
						|
    B->~Block();
 | 
						|
}
 | 
						|
 | 
						|
Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex,
 | 
						|
                             SplitBlockCache *Cache) {
 | 
						|
 | 
						|
  assert(SplitIndex > 0 && "splitBlock can not be called with SplitIndex == 0");
 | 
						|
 | 
						|
  // If the split point covers all of B then just return B.
 | 
						|
  if (SplitIndex == B.getSize())
 | 
						|
    return B;
 | 
						|
 | 
						|
  assert(SplitIndex < B.getSize() && "SplitIndex out of range");
 | 
						|
 | 
						|
  // Create the new block covering [ 0, SplitIndex ).
 | 
						|
  auto &NewBlock =
 | 
						|
      B.isZeroFill()
 | 
						|
          ? createZeroFillBlock(B.getSection(), SplitIndex, B.getAddress(),
 | 
						|
                                B.getAlignment(), B.getAlignmentOffset())
 | 
						|
          : createContentBlock(
 | 
						|
                B.getSection(), B.getContent().substr(0, SplitIndex),
 | 
						|
                B.getAddress(), B.getAlignment(), B.getAlignmentOffset());
 | 
						|
 | 
						|
  // Modify B to cover [ SplitIndex, B.size() ).
 | 
						|
  B.setAddress(B.getAddress() + SplitIndex);
 | 
						|
  B.setContent(B.getContent().substr(SplitIndex));
 | 
						|
  B.setAlignmentOffset((B.getAlignmentOffset() + SplitIndex) %
 | 
						|
                       B.getAlignment());
 | 
						|
 | 
						|
  // Handle edge transfer/update.
 | 
						|
  {
 | 
						|
    // Copy edges to NewBlock (recording their iterators so that we can remove
 | 
						|
    // them from B), and update of Edges remaining on B.
 | 
						|
    std::vector<Block::edge_iterator> EdgesToRemove;
 | 
						|
    for (auto I = B.edges().begin(), E = B.edges().end(); I != E; ++I) {
 | 
						|
      if (I->getOffset() < SplitIndex) {
 | 
						|
        NewBlock.addEdge(*I);
 | 
						|
        EdgesToRemove.push_back(I);
 | 
						|
      } else
 | 
						|
        I->setOffset(I->getOffset() - SplitIndex);
 | 
						|
    }
 | 
						|
 | 
						|
    // Remove edges that were transfered to NewBlock from B.
 | 
						|
    while (!EdgesToRemove.empty()) {
 | 
						|
      B.removeEdge(EdgesToRemove.back());
 | 
						|
      EdgesToRemove.pop_back();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Handle symbol transfer/update.
 | 
						|
  {
 | 
						|
    // Initialize the symbols cache if necessary.
 | 
						|
    SplitBlockCache LocalBlockSymbolsCache;
 | 
						|
    if (!Cache)
 | 
						|
      Cache = &LocalBlockSymbolsCache;
 | 
						|
    if (*Cache == None) {
 | 
						|
      *Cache = SplitBlockCache::value_type();
 | 
						|
      for (auto *Sym : B.getSection().symbols())
 | 
						|
        if (&Sym->getBlock() == &B)
 | 
						|
          (*Cache)->push_back(Sym);
 | 
						|
 | 
						|
      llvm::sort(**Cache, [](const Symbol *LHS, const Symbol *RHS) {
 | 
						|
        return LHS->getOffset() > RHS->getOffset();
 | 
						|
      });
 | 
						|
    }
 | 
						|
    auto &BlockSymbols = **Cache;
 | 
						|
 | 
						|
    // Transfer all symbols with offset less than SplitIndex to NewBlock.
 | 
						|
    while (!BlockSymbols.empty() &&
 | 
						|
           BlockSymbols.back()->getOffset() < SplitIndex) {
 | 
						|
      BlockSymbols.back()->setBlock(NewBlock);
 | 
						|
      BlockSymbols.pop_back();
 | 
						|
    }
 | 
						|
 | 
						|
    // Update offsets for all remaining symbols in B.
 | 
						|
    for (auto *Sym : BlockSymbols)
 | 
						|
      Sym->setOffset(Sym->getOffset() - SplitIndex);
 | 
						|
  }
 | 
						|
 | 
						|
  return NewBlock;
 | 
						|
}
 | 
						|
 | 
						|
void LinkGraph::dump(raw_ostream &OS,
 | 
						|
                     std::function<StringRef(Edge::Kind)> EdgeKindToName) {
 | 
						|
  if (!EdgeKindToName)
 | 
						|
    EdgeKindToName = [](Edge::Kind K) { return StringRef(); };
 | 
						|
 | 
						|
  OS << "Symbols:\n";
 | 
						|
  for (auto *Sym : defined_symbols()) {
 | 
						|
    OS << "  " << format("0x%016" PRIx64, Sym->getAddress()) << ": " << *Sym
 | 
						|
       << "\n";
 | 
						|
    if (Sym->isDefined()) {
 | 
						|
      for (auto &E : Sym->getBlock().edges()) {
 | 
						|
        OS << "    ";
 | 
						|
        StringRef EdgeName = (E.getKind() < Edge::FirstRelocation
 | 
						|
                                  ? getGenericEdgeKindName(E.getKind())
 | 
						|
                                  : EdgeKindToName(E.getKind()));
 | 
						|
 | 
						|
        if (!EdgeName.empty())
 | 
						|
          printEdge(OS, Sym->getBlock(), E, EdgeName);
 | 
						|
        else {
 | 
						|
          auto EdgeNumberString = std::to_string(E.getKind());
 | 
						|
          printEdge(OS, Sym->getBlock(), E, EdgeNumberString);
 | 
						|
        }
 | 
						|
        OS << "\n";
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  OS << "Absolute symbols:\n";
 | 
						|
  for (auto *Sym : absolute_symbols())
 | 
						|
    OS << "  " << format("0x%016" PRIx64, Sym->getAddress()) << ": " << *Sym
 | 
						|
       << "\n";
 | 
						|
 | 
						|
  OS << "External symbols:\n";
 | 
						|
  for (auto *Sym : external_symbols())
 | 
						|
    OS << "  " << format("0x%016" PRIx64, Sym->getAddress()) << ": " << *Sym
 | 
						|
       << "\n";
 | 
						|
}
 | 
						|
 | 
						|
raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LF) {
 | 
						|
  switch (LF) {
 | 
						|
  case SymbolLookupFlags::RequiredSymbol:
 | 
						|
    return OS << "RequiredSymbol";
 | 
						|
  case SymbolLookupFlags::WeaklyReferencedSymbol:
 | 
						|
    return OS << "WeaklyReferencedSymbol";
 | 
						|
  }
 | 
						|
  llvm_unreachable("Unrecognized lookup flags");
 | 
						|
}
 | 
						|
 | 
						|
void JITLinkAsyncLookupContinuation::anchor() {}
 | 
						|
 | 
						|
JITLinkContext::~JITLinkContext() {}
 | 
						|
 | 
						|
bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const {
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
LinkGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {
 | 
						|
  return LinkGraphPassFunction();
 | 
						|
}
 | 
						|
 | 
						|
Error JITLinkContext::modifyPassConfig(const Triple &TT,
 | 
						|
                                       PassConfiguration &Config) {
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
Error markAllSymbolsLive(LinkGraph &G) {
 | 
						|
  for (auto *Sym : G.defined_symbols())
 | 
						|
    Sym->setLive(true);
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
void jitLink(std::unique_ptr<JITLinkContext> Ctx) {
 | 
						|
  auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer());
 | 
						|
  switch (Magic) {
 | 
						|
  case file_magic::macho_object:
 | 
						|
    return jitLink_MachO(std::move(Ctx));
 | 
						|
  default:
 | 
						|
    Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format"));
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace jitlink
 | 
						|
} // end namespace llvm
 |