如何验证是否启用了 XN 位支持?
根据 ARM 手册5.5.3。执行 never 位,XN 在c1 控制寄存器中。Userland(异常级别 0)无法访问我知道的配置中的那些字段。
你有两个或三个选择(或者可能一个)。首先,如果作为特权进程运行(异常级别 1 或更高),则只需读取 c1 寄存器。
其次,查看是否可以使用HWCAP. 这是 Torvald 的asm/hwcaps.h,但我没有看到HWCAP_XN或类似的。HWCAP_IWMMXT可能是这样,但我找不到定义代表什么。
HWCAP是最简单的路径,因为您只需要执行以下操作(但它似乎对您不可用):
if ((getauxval(AT_HWCAP) & HWCAP_XN) != 0)
return true;
由于第二个选项不可用,您可以执行特征探测。我称它们为SIGILL探针是因为您经常在探索 ISA 支持,例如使用 NEON 负载的 NEON。如果你SIGILL发现你知道处理器不支持 NEON。
在您的情况下,您应该执行@o11c 在评论中建议的内容。您应该分配一个页面, setPROT_EXEC并查看是否可以写入。如果您无法写入它,那么write将失败,errno=EPERM否则您将捕获异常。如果write失败,则将 NX 功能标记为可用。
我没有方便的功能探针XN(我从来不需要它),但我可以向您展示探针在探测 ARMv7 支持SIGILL时的样子。
还要小心 Apple 机器上的探针。Apple 有一个 bug 会影响注册或进程的状态longjmp,它会破坏一些可怕的东西。永远不要在 Apple 平台上探查。只需为该功能返回 false 。
extern "C" {
typedef void (*SigHandler)(int);
static jmp_buf s_jmpSIGILL;
static void SigIllHandler(int)
{
longjmp(s_jmpSIGILL, 1);
}
}
bool CPU_ProbeARMv7()
{
// longjmp and clobber warnings. Volatile is required.
// http://stackoverflow.com/q/7721854
volatile bool result = true;
volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
if (oldHandler == SIG_ERR)
return false;
volatile sigset_t oldMask;
if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
return false;
if (setjmp(s_jmpSIGILL))
result = false;
else
{
// ARMv7 added movt and movw
int a;
asm volatile("movw %0,%1 \n"
"movt %0,%1 \n"
: "=r"(a) : "i"(0x1234));
result = (a == 0x12341234);
}
sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
signal(SIGILL, oldHandler);
return result;
}