Enable PAC in addition to BTI on arm64 such that JIT code matches the default branch protection provided by our base compiler
This commit is contained in:
parent
128113431e
commit
1908ee2b1e
3 changed files with 83 additions and 21 deletions
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "util/detect.h"
|
#include "util/detect.h"
|
||||||
#include "pipe/p_compiler.h"
|
#include "util/compiler.h"
|
||||||
#include "util/macros.h"
|
#include "util/macros.h"
|
||||||
#include "util/u_cpu_detect.h"
|
#include "util/u_cpu_detect.h"
|
||||||
#include "util/u_debug.h"
|
#include "util/u_debug.h"
|
||||||
|
@ -42,14 +42,14 @@
|
||||||
|
|
||||||
#include <llvm/Config/llvm-config.h>
|
#include <llvm/Config/llvm-config.h>
|
||||||
#include <llvm-c/Analysis.h>
|
#include <llvm-c/Analysis.h>
|
||||||
#include <llvm-c/Transforms/Scalar.h>
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
|
||||||
#include <llvm-c/Transforms/Utils.h>
|
|
||||||
#endif
|
|
||||||
#include <llvm-c/BitWriter.h>
|
#include <llvm-c/BitWriter.h>
|
||||||
#if GALLIVM_USE_NEW_PASS == 1
|
#if GALLIVM_USE_NEW_PASS == 1
|
||||||
#include <llvm-c/Transforms/PassBuilder.h>
|
#include <llvm-c/Transforms/PassBuilder.h>
|
||||||
#elif GALLIVM_HAVE_CORO == 1
|
#elif GALLIVM_HAVE_CORO == 1
|
||||||
|
#include <llvm-c/Transforms/Scalar.h>
|
||||||
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
|
#include <llvm-c/Transforms/Utils.h>
|
||||||
|
#endif
|
||||||
#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64)
|
#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64)
|
||||||
#include <llvm-c/Transforms/IPO.h>
|
#include <llvm-c/Transforms/IPO.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,7 +85,7 @@ static const struct debug_named_value lp_bld_debug_flags[] = {
|
||||||
DEBUG_GET_ONCE_FLAGS_OPTION(gallivm_debug, "GALLIVM_DEBUG", lp_bld_debug_flags, 0)
|
DEBUG_GET_ONCE_FLAGS_OPTION(gallivm_debug, "GALLIVM_DEBUG", lp_bld_debug_flags, 0)
|
||||||
|
|
||||||
|
|
||||||
static boolean gallivm_initialized = FALSE;
|
static bool gallivm_initialized = false;
|
||||||
|
|
||||||
unsigned lp_native_vector_width;
|
unsigned lp_native_vector_width;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ enum LLVM_CodeGenOpt_Level {
|
||||||
* relevant optimization passes.
|
* relevant optimization passes.
|
||||||
* \return TRUE for success, FALSE for failure
|
* \return TRUE for success, FALSE for failure
|
||||||
*/
|
*/
|
||||||
static boolean
|
static bool
|
||||||
create_pass_manager(struct gallivm_state *gallivm)
|
create_pass_manager(struct gallivm_state *gallivm)
|
||||||
{
|
{
|
||||||
#if GALLIVM_USE_NEW_PASS == 0
|
#if GALLIVM_USE_NEW_PASS == 0
|
||||||
|
@ -121,7 +121,7 @@ create_pass_manager(struct gallivm_state *gallivm)
|
||||||
|
|
||||||
gallivm->passmgr = LLVMCreateFunctionPassManagerForModule(gallivm->module);
|
gallivm->passmgr = LLVMCreateFunctionPassManagerForModule(gallivm->module);
|
||||||
if (!gallivm->passmgr)
|
if (!gallivm->passmgr)
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
#if GALLIVM_HAVE_CORO == 1
|
#if GALLIVM_HAVE_CORO == 1
|
||||||
gallivm->cgpassmgr = LLVMCreatePassManager();
|
gallivm->cgpassmgr = LLVMCreatePassManager();
|
||||||
|
@ -191,7 +191,7 @@ create_pass_manager(struct gallivm_state *gallivm)
|
||||||
LLVMAddCoroCleanupPass(gallivm->passmgr);
|
LLVMAddCoroCleanupPass(gallivm->passmgr);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -266,7 +266,7 @@ gallivm_free_code(struct gallivm_state *gallivm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static boolean
|
static bool
|
||||||
init_gallivm_engine(struct gallivm_state *gallivm)
|
init_gallivm_engine(struct gallivm_state *gallivm)
|
||||||
{
|
{
|
||||||
if (1) {
|
if (1) {
|
||||||
|
@ -316,10 +316,10 @@ init_gallivm_engine(struct gallivm_state *gallivm)
|
||||||
free(engine_data_layout);
|
free(engine_data_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -327,7 +327,7 @@ fail:
|
||||||
* Allocate gallivm LLVM objects.
|
* Allocate gallivm LLVM objects.
|
||||||
* \return TRUE for success, FALSE for failure
|
* \return TRUE for success, FALSE for failure
|
||||||
*/
|
*/
|
||||||
static boolean
|
static bool
|
||||||
init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||||
LLVMContextRef context, struct lp_cached_code *cache)
|
LLVMContextRef context, struct lp_cached_code *cache)
|
||||||
{
|
{
|
||||||
|
@ -335,7 +335,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||||
assert(!gallivm->module);
|
assert(!gallivm->module);
|
||||||
|
|
||||||
if (!lp_build_init())
|
if (!lp_build_init())
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
gallivm->context = context;
|
gallivm->context = context;
|
||||||
gallivm->cache = cache;
|
gallivm->cache = cache;
|
||||||
|
@ -360,6 +360,10 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||||
lp_set_module_stack_alignment_override(gallivm->module, 4);
|
lp_set_module_stack_alignment_override(gallivm->module, 4);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DETECT_ARCH_AARCH64
|
||||||
|
lp_set_module_branch_protection(gallivm->module);
|
||||||
|
#endif
|
||||||
|
|
||||||
gallivm->builder = LLVMCreateBuilderInContext(gallivm->context);
|
gallivm->builder = LLVMCreateBuilderInContext(gallivm->context);
|
||||||
if (!gallivm->builder)
|
if (!gallivm->builder)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -404,7 +408,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||||
|
|
||||||
gallivm->target = LLVMCreateTargetData(layout);
|
gallivm->target = LLVMCreateTargetData(layout);
|
||||||
if (!gallivm->target) {
|
if (!gallivm->target) {
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,12 +416,12 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
lp_build_coro_declare_malloc_hooks(gallivm);
|
lp_build_coro_declare_malloc_hooks(gallivm);
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
gallivm_free_ir(gallivm);
|
gallivm_free_ir(gallivm);
|
||||||
gallivm_free_code(gallivm);
|
gallivm_free_code(gallivm);
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
|
@ -433,12 +437,12 @@ lp_build_init_native_width(void)
|
||||||
return lp_native_vector_width;
|
return lp_native_vector_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean
|
bool
|
||||||
lp_build_init(void)
|
lp_build_init(void)
|
||||||
{
|
{
|
||||||
lp_build_init_native_width();
|
lp_build_init_native_width();
|
||||||
if (gallivm_initialized)
|
if (gallivm_initialized)
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
/* LLVMLinkIn* are no-ops at runtime. They just ensure the respective
|
/* LLVMLinkIn* are no-ops at runtime. They just ensure the respective
|
||||||
|
@ -475,9 +479,9 @@ lp_build_init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gallivm_initialized = TRUE;
|
gallivm_initialized = true;
|
||||||
|
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include <llvm/Support/PrettyStackTrace.h>
|
#include <llvm/Support/PrettyStackTrace.h>
|
||||||
#include <llvm/ExecutionEngine/ObjectCache.h>
|
#include <llvm/ExecutionEngine/ObjectCache.h>
|
||||||
#include <llvm/Support/TargetSelect.h>
|
#include <llvm/Support/TargetSelect.h>
|
||||||
|
#include <llvm/CodeGen/SelectionDAGNodes.h>
|
||||||
#if LLVM_VERSION_MAJOR >= 15
|
#if LLVM_VERSION_MAJOR >= 15
|
||||||
#include <llvm/Support/MemoryBuffer.h>
|
#include <llvm/Support/MemoryBuffer.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -100,6 +101,8 @@
|
||||||
#include "lp_bld_misc.h"
|
#include "lp_bld_misc.h"
|
||||||
#include "lp_bld_debug.h"
|
#include "lp_bld_debug.h"
|
||||||
|
|
||||||
|
static void lp_run_atexit_for_destructors(void);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class LLVMEnsureMultithreaded {
|
class LLVMEnsureMultithreaded {
|
||||||
|
@ -147,6 +150,7 @@ static void init_native_targets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
lp_run_atexit_for_destructors();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
|
@ -366,7 +370,11 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
|
||||||
builder.setEngineKind(EngineKind::JIT)
|
builder.setEngineKind(EngineKind::JIT)
|
||||||
.setErrorStr(&Error)
|
.setErrorStr(&Error)
|
||||||
.setTargetOptions(options)
|
.setTargetOptions(options)
|
||||||
|
#if LLVM_VERSION_MAJOR >= 18
|
||||||
|
.setOptLevel((CodeGenOptLevel)OptLevel);
|
||||||
|
#else
|
||||||
.setOptLevel((CodeGenOpt::Level)OptLevel);
|
.setOptLevel((CodeGenOpt::Level)OptLevel);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DETECT_OS_WINDOWS
|
#if DETECT_OS_WINDOWS
|
||||||
/*
|
/*
|
||||||
|
@ -408,6 +416,13 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
|
||||||
* so we do not use llvm::sys::getHostCPUFeatures to detect cpu features
|
* so we do not use llvm::sys::getHostCPUFeatures to detect cpu features
|
||||||
* but using util_get_cpu_caps() instead.
|
* but using util_get_cpu_caps() instead.
|
||||||
*/
|
*/
|
||||||
|
#if DETECT_ARCH_X86_64
|
||||||
|
/*
|
||||||
|
* Without this, on some "buggy" qemu cpu setup, LLVM could crash
|
||||||
|
* if LLVM detects the wrong CPU type.
|
||||||
|
*/
|
||||||
|
MAttrs.push_back("+64bit");
|
||||||
|
#endif
|
||||||
MAttrs.push_back(util_get_cpu_caps()->has_sse ? "+sse" : "-sse" );
|
MAttrs.push_back(util_get_cpu_caps()->has_sse ? "+sse" : "-sse" );
|
||||||
MAttrs.push_back(util_get_cpu_caps()->has_sse2 ? "+sse2" : "-sse2" );
|
MAttrs.push_back(util_get_cpu_caps()->has_sse2 ? "+sse2" : "-sse2" );
|
||||||
MAttrs.push_back(util_get_cpu_caps()->has_sse3 ? "+sse3" : "-sse3" );
|
MAttrs.push_back(util_get_cpu_caps()->has_sse3 ? "+sse3" : "-sse3" );
|
||||||
|
@ -619,3 +634,42 @@ lp_set_module_stack_alignment_override(LLVMModuleRef MRef, unsigned align)
|
||||||
M->setOverrideStackAlignment(align);
|
M->setOverrideStackAlignment(align);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
lp_set_module_branch_protection(LLVMModuleRef MRef)
|
||||||
|
{
|
||||||
|
/* Enable standard (bti+pac-ret) branch protection */
|
||||||
|
llvm::Module *M = llvm::unwrap(MRef);
|
||||||
|
M->addModuleFlag(llvm::Module::Override, "branch-target-enforcement", 1);
|
||||||
|
M->addModuleFlag(llvm::Module::Override, "sign-return-address", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
class GallivmRunAtExitForStaticDestructors : public SDNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* getSDVTList (protected) calls getValueTypeList (private), which contains static variables. */
|
||||||
|
GallivmRunAtExitForStaticDestructors(): SDNode(0, 0, DebugLoc(), getSDVTList(MVT::Other))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
lp_run_atexit_for_destructors(void)
|
||||||
|
{
|
||||||
|
/* LLVM >= 16 registers static variable destructors on the first compile, which gcc
|
||||||
|
* implements by calling atexit there. Before that, u_queue registers its atexit
|
||||||
|
* handler to kill all threads. Since exit() runs atexit handlers in the reverse order,
|
||||||
|
* the LLVM destructors are called first while shader compiler threads may still be
|
||||||
|
* running, which crashes in LLVM in SelectionDAG.cpp.
|
||||||
|
*
|
||||||
|
* The solution is to run the code that declares the LLVM static variables first,
|
||||||
|
* so that atexit for LLVM is registered first and u_queue is registered after that,
|
||||||
|
* which ensures that all u_queue threads are terminated before LLVM destructors are
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* This just executes the code that declares static variables.
|
||||||
|
*/
|
||||||
|
GallivmRunAtExitForStaticDestructors();
|
||||||
|
}
|
||||||
|
|
|
@ -94,6 +94,10 @@ lp_free_objcache(void *objcache);
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_set_module_stack_alignment_override(LLVMModuleRef M, unsigned align);
|
lp_set_module_stack_alignment_override(LLVMModuleRef M, unsigned align);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_set_module_branch_protection(LLVMModuleRef M);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue