Как проверить, включена ли поддержка битов XN?
Согласно руководству ARM 5.5.3.Выполнить никогда не биты , XN находится в c1 Регистр управления .Пользовательская область (уровень исключения 0) не может получить доступ к этим полям в конфигурациях, о которых я знаю.
У вас есть два или три варианта (или, возможно, один).Во-первых, если выполняется как привилегированный процесс (уровень исключения 1 или выше), просто прочитайте регистр c1.
Во-вторых, посмотрите, можно ли запросить функцию с помощью HWCAP
.Вот Торвальдс asm/hwcaps.h
, но я не вижу HWCAP_XN
или подобное.HWCAP_IWMMXT
может быть, но я не могу найти то, что представляет определение.
HWCAP
- это самый простой путь, потому что вам нужно только сделать следующее (но он не доступен для вас):
if ((getauxval(AT_HWCAP) & HWCAP_XN) != 0)
return true;
Поскольку второй вариант недоступен, вы можете выполнить проверку функции.Я называю их SIGILL
пробами, потому что вы часто проверяете поддержку ISA, например, NEON, используя нагрузку NEON.Если вы ловите SIGILL
, вы знаете, что процессор не поддерживает NEON.
В вашем случае вы должны выполнить то, что @ o11c предлагает в комментарии.Вы должны выделить страницу, установить PROT_EXEC
и посмотреть, сможете ли вы написать на нее.Если вы не можете написать в него, то write
завершится с ошибкой errno=EPERM
или вы поймаете исключение.Если произойдет сбой write
, вы пометите функцию NX как доступную.
У меня нет удобного зонда для XN
(он мне никогда не был нужен), но я могу показать вам, чтоSIGILL
пробник выглядит, когда пробует поддержку ARMv7 .
Также будьте осторожны с пробниками на компьютерах Apple.У Apple есть ошибка, которая влияет на регистр или состояние процесса после взятия 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;
}