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 "pipe/p_compiler.h"
|
||||
#include "util/compiler.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_debug.h"
|
||||
|
@ -42,14 +42,14 @@
|
|||
|
||||
#include <llvm/Config/llvm-config.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>
|
||||
#if GALLIVM_USE_NEW_PASS == 1
|
||||
#include <llvm-c/Transforms/PassBuilder.h>
|
||||
#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)
|
||||
#include <llvm-c/Transforms/IPO.h>
|
||||
#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)
|
||||
|
||||
|
||||
static boolean gallivm_initialized = FALSE;
|
||||
static bool gallivm_initialized = false;
|
||||
|
||||
unsigned lp_native_vector_width;
|
||||
|
||||
|
@ -112,7 +112,7 @@ enum LLVM_CodeGenOpt_Level {
|
|||
* relevant optimization passes.
|
||||
* \return TRUE for success, FALSE for failure
|
||||
*/
|
||||
static boolean
|
||||
static bool
|
||||
create_pass_manager(struct gallivm_state *gallivm)
|
||||
{
|
||||
#if GALLIVM_USE_NEW_PASS == 0
|
||||
|
@ -121,7 +121,7 @@ create_pass_manager(struct gallivm_state *gallivm)
|
|||
|
||||
gallivm->passmgr = LLVMCreateFunctionPassManagerForModule(gallivm->module);
|
||||
if (!gallivm->passmgr)
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
#if GALLIVM_HAVE_CORO == 1
|
||||
gallivm->cgpassmgr = LLVMCreatePassManager();
|
||||
|
@ -191,7 +191,7 @@ create_pass_manager(struct gallivm_state *gallivm)
|
|||
LLVMAddCoroCleanupPass(gallivm->passmgr);
|
||||
#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)
|
||||
{
|
||||
if (1) {
|
||||
|
@ -316,10 +316,10 @@ init_gallivm_engine(struct gallivm_state *gallivm)
|
|||
free(engine_data_layout);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -327,7 +327,7 @@ fail:
|
|||
* Allocate gallivm LLVM objects.
|
||||
* \return TRUE for success, FALSE for failure
|
||||
*/
|
||||
static boolean
|
||||
static bool
|
||||
init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
||||
LLVMContextRef context, struct lp_cached_code *cache)
|
||||
{
|
||||
|
@ -335,7 +335,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
|||
assert(!gallivm->module);
|
||||
|
||||
if (!lp_build_init())
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
gallivm->context = context;
|
||||
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);
|
||||
#endif
|
||||
|
||||
#if DETECT_ARCH_AARCH64
|
||||
lp_set_module_branch_protection(gallivm->module);
|
||||
#endif
|
||||
|
||||
gallivm->builder = LLVMCreateBuilderInContext(gallivm->context);
|
||||
if (!gallivm->builder)
|
||||
goto fail;
|
||||
|
@ -404,7 +408,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
|||
|
||||
gallivm->target = LLVMCreateTargetData(layout);
|
||||
if (!gallivm->target) {
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,12 +416,12 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
|||
goto fail;
|
||||
|
||||
lp_build_coro_declare_malloc_hooks(gallivm);
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
gallivm_free_ir(gallivm);
|
||||
gallivm_free_code(gallivm);
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -433,12 +437,12 @@ lp_build_init_native_width(void)
|
|||
return lp_native_vector_width;
|
||||
}
|
||||
|
||||
boolean
|
||||
bool
|
||||
lp_build_init(void)
|
||||
{
|
||||
lp_build_init_native_width();
|
||||
if (gallivm_initialized)
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
|
||||
/* LLVMLinkIn* are no-ops at runtime. They just ensure the respective
|
||||
|
@ -475,9 +479,9 @@ lp_build_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
gallivm_initialized = TRUE;
|
||||
gallivm_initialized = true;
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include <llvm/Support/PrettyStackTrace.h>
|
||||
#include <llvm/ExecutionEngine/ObjectCache.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/CodeGen/SelectionDAGNodes.h>
|
||||
#if LLVM_VERSION_MAJOR >= 15
|
||||
#include <llvm/Support/MemoryBuffer.h>
|
||||
#endif
|
||||
|
@ -100,6 +101,8 @@
|
|||
#include "lp_bld_misc.h"
|
||||
#include "lp_bld_debug.h"
|
||||
|
||||
static void lp_run_atexit_for_destructors(void);
|
||||
|
||||
namespace {
|
||||
|
||||
class LLVMEnsureMultithreaded {
|
||||
|
@ -147,6 +150,7 @@ static void init_native_targets()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
lp_run_atexit_for_destructors();
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
|
@ -366,7 +370,11 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
|
|||
builder.setEngineKind(EngineKind::JIT)
|
||||
.setErrorStr(&Error)
|
||||
.setTargetOptions(options)
|
||||
#if LLVM_VERSION_MAJOR >= 18
|
||||
.setOptLevel((CodeGenOptLevel)OptLevel);
|
||||
#else
|
||||
.setOptLevel((CodeGenOpt::Level)OptLevel);
|
||||
#endif
|
||||
|
||||
#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
|
||||
* 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_sse2 ? "+sse2" : "-sse2" );
|
||||
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);
|
||||
#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
|
||||
lp_set_module_stack_alignment_override(LLVMModuleRef M, unsigned align);
|
||||
|
||||
void
|
||||
lp_set_module_branch_protection(LLVMModuleRef M);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue