338 lines
14 KiB
C
338 lines
14 KiB
C
|
//===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// ABI specific code for Orc, e.g. callback assembly.
|
||
|
//
|
||
|
// ABI classes should be part of the JIT *target* process, not the host
|
||
|
// process (except where you're doing hosted JITing and the two are one and the
|
||
|
// same).
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
|
||
|
#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
|
||
|
|
||
|
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||
|
#include "llvm/Support/Error.h"
|
||
|
#include "llvm/Support/ErrorHandling.h"
|
||
|
#include "llvm/Support/MathExtras.h"
|
||
|
#include <algorithm>
|
||
|
#include <cstdint>
|
||
|
|
||
|
namespace llvm {
|
||
|
namespace orc {
|
||
|
|
||
|
struct IndirectStubsAllocationSizes {
|
||
|
uint64_t StubBytes = 0;
|
||
|
uint64_t PointerBytes = 0;
|
||
|
unsigned NumStubs = 0;
|
||
|
};
|
||
|
|
||
|
template <typename ORCABI>
|
||
|
IndirectStubsAllocationSizes
|
||
|
getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) {
|
||
|
assert(
|
||
|
(RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) &&
|
||
|
"RoundToMultipleOf is not a multiple of stub size");
|
||
|
uint64_t StubBytes = MinStubs * ORCABI::StubSize;
|
||
|
if (RoundToMultipleOf)
|
||
|
StubBytes = alignTo(StubBytes, RoundToMultipleOf);
|
||
|
unsigned NumStubs = StubBytes / ORCABI::StubSize;
|
||
|
uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
|
||
|
return {StubBytes, PointerBytes, NumStubs};
|
||
|
}
|
||
|
|
||
|
/// Generic ORC ABI support.
|
||
|
///
|
||
|
/// This class can be substituted as the target architecture support class for
|
||
|
/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
|
||
|
/// support lazy JITing however, and any attempt to use that functionality
|
||
|
/// will result in execution of an llvm_unreachable.
|
||
|
class OrcGenericABI {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = sizeof(uintptr_t);
|
||
|
static constexpr unsigned TrampolineSize = 1;
|
||
|
static constexpr unsigned StubSize = 1;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1;
|
||
|
static constexpr unsigned ResolverCodeSize = 1;
|
||
|
|
||
|
static void writeResolverCode(char *ResolveWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddr,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr) {
|
||
|
llvm_unreachable("writeResolverCode is not supported by the generic host "
|
||
|
"support class");
|
||
|
}
|
||
|
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddr,
|
||
|
JITTargetAddress ResolverAddr,
|
||
|
unsigned NumTrampolines) {
|
||
|
llvm_unreachable("writeTrampolines is not supported by the generic host "
|
||
|
"support class");
|
||
|
}
|
||
|
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) {
|
||
|
llvm_unreachable(
|
||
|
"writeIndirectStubsBlock is not supported by the generic host "
|
||
|
"support class");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class OrcAArch64 {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = 8;
|
||
|
static constexpr unsigned TrampolineSize = 12;
|
||
|
static constexpr unsigned StubSize = 8;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
|
||
|
static constexpr unsigned ResolverCodeSize = 0x120;
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress RentryCtxAddr);
|
||
|
|
||
|
/// Write the requested number of trampolines into the given memory,
|
||
|
/// which must be big enough to hold 1 pointer, plus NumTrampolines
|
||
|
/// trampolines.
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddress,
|
||
|
JITTargetAddress ResolverAddr,
|
||
|
unsigned NumTrampolines);
|
||
|
|
||
|
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
|
||
|
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
|
||
|
/// Nth stub using the Nth pointer in memory starting at
|
||
|
/// PointersBlockTargetAddress.
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned MinStubs);
|
||
|
};
|
||
|
|
||
|
/// X86_64 code that's common to all ABIs.
|
||
|
///
|
||
|
/// X86_64 supports lazy JITing.
|
||
|
class OrcX86_64_Base {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = 8;
|
||
|
static constexpr unsigned TrampolineSize = 8;
|
||
|
static constexpr unsigned StubSize = 8;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
|
||
|
|
||
|
/// Write the requested number of trampolines into the given memory,
|
||
|
/// which must be big enough to hold 1 pointer, plus NumTrampolines
|
||
|
/// trampolines.
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddress,
|
||
|
JITTargetAddress ResolverAddr,
|
||
|
unsigned NumTrampolines);
|
||
|
|
||
|
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
|
||
|
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
|
||
|
/// Nth stub using the Nth pointer in memory starting at
|
||
|
/// PointersBlockTargetAddress.
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
|
||
|
};
|
||
|
|
||
|
/// X86_64 support for SysV ABI (Linux, MacOSX).
|
||
|
///
|
||
|
/// X86_64_SysV supports lazy JITing.
|
||
|
class OrcX86_64_SysV : public OrcX86_64_Base {
|
||
|
public:
|
||
|
static constexpr unsigned ResolverCodeSize = 0x6C;
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr);
|
||
|
};
|
||
|
|
||
|
/// X86_64 support for Win32.
|
||
|
///
|
||
|
/// X86_64_Win32 supports lazy JITing.
|
||
|
class OrcX86_64_Win32 : public OrcX86_64_Base {
|
||
|
public:
|
||
|
static constexpr unsigned ResolverCodeSize = 0x74;
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr);
|
||
|
};
|
||
|
|
||
|
/// I386 support.
|
||
|
///
|
||
|
/// I386 supports lazy JITing.
|
||
|
class OrcI386 {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = 4;
|
||
|
static constexpr unsigned TrampolineSize = 8;
|
||
|
static constexpr unsigned StubSize = 8;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
|
||
|
static constexpr unsigned ResolverCodeSize = 0x4a;
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr);
|
||
|
|
||
|
/// Write the requested number of trampolines into the given memory,
|
||
|
/// which must be big enough to hold 1 pointer, plus NumTrampolines
|
||
|
/// trampolines.
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddress,
|
||
|
JITTargetAddress ResolverAddr,
|
||
|
unsigned NumTrampolines);
|
||
|
|
||
|
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
|
||
|
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
|
||
|
/// Nth stub using the Nth pointer in memory starting at
|
||
|
/// PointersBlockTargetAddress.
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
|
||
|
};
|
||
|
|
||
|
// @brief Mips32 support.
|
||
|
//
|
||
|
// Mips32 supports lazy JITing.
|
||
|
class OrcMips32_Base {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = 4;
|
||
|
static constexpr unsigned TrampolineSize = 20;
|
||
|
static constexpr unsigned StubSize = 8;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
|
||
|
static constexpr unsigned ResolverCodeSize = 0xfc;
|
||
|
|
||
|
/// Write the requested number of trampolines into the given memory,
|
||
|
/// which must be big enough to hold 1 pointer, plus NumTrampolines
|
||
|
/// trampolines.
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddress,
|
||
|
JITTargetAddress ResolverAddr,
|
||
|
unsigned NumTrampolines);
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverBlockWorkingMem,
|
||
|
JITTargetAddress ResolverBlockTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr,
|
||
|
bool isBigEndian);
|
||
|
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
|
||
|
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
|
||
|
/// Nth stub using the Nth pointer in memory starting at
|
||
|
/// PointersBlockTargetAddress.
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
|
||
|
};
|
||
|
|
||
|
class OrcMips32Le : public OrcMips32_Base {
|
||
|
public:
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr) {
|
||
|
OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
|
||
|
ReentryFnAddr, ReentryCtxAddr, false);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class OrcMips32Be : public OrcMips32_Base {
|
||
|
public:
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr) {
|
||
|
OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
|
||
|
ReentryFnAddr, ReentryCtxAddr, true);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// @brief Mips64 support.
|
||
|
//
|
||
|
// Mips64 supports lazy JITing.
|
||
|
class OrcMips64 {
|
||
|
public:
|
||
|
static constexpr unsigned PointerSize = 8;
|
||
|
static constexpr unsigned TrampolineSize = 40;
|
||
|
static constexpr unsigned StubSize = 32;
|
||
|
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
|
||
|
static constexpr unsigned ResolverCodeSize = 0x120;
|
||
|
|
||
|
/// Write the resolver code into the given memory. The user is
|
||
|
/// responsible for allocating the memory and setting permissions.
|
||
|
///
|
||
|
/// ReentryFnAddr should be the address of a function whose signature matches
|
||
|
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
|
||
|
/// argument of writeResolverCode will be passed as the second argument to
|
||
|
/// the function at ReentryFnAddr.
|
||
|
static void writeResolverCode(char *ResolverWorkingMem,
|
||
|
JITTargetAddress ResolverTargetAddress,
|
||
|
JITTargetAddress ReentryFnAddr,
|
||
|
JITTargetAddress ReentryCtxAddr);
|
||
|
|
||
|
/// Write the requested number of trampolines into the given memory,
|
||
|
/// which must be big enough to hold 1 pointer, plus NumTrampolines
|
||
|
/// trampolines.
|
||
|
static void writeTrampolines(char *TrampolineBlockWorkingMem,
|
||
|
JITTargetAddress TrampolineBlockTargetAddress,
|
||
|
JITTargetAddress ResolverFnAddr,
|
||
|
unsigned NumTrampolines);
|
||
|
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
|
||
|
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
|
||
|
/// Nth stub using the Nth pointer in memory starting at
|
||
|
/// PointersBlockTargetAddress.
|
||
|
static void writeIndirectStubsBlock(
|
||
|
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
|
||
|
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
|
||
|
};
|
||
|
|
||
|
} // end namespace orc
|
||
|
} // end namespace llvm
|
||
|
|
||
|
#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
|