- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
根据 The Open Group Base Specifications 和 longjump docs :
It is unspecified whether longjmp() restores the signal mask, leaves the signal mask unchanged, or restores it to its value at the time setjmp() was called.
我想我在 ARMv8 Mustang board 上遇到了警告.我们通过捕获 SIGILL
来执行运行时特征检测。第一个 SIGILL
陷阱在测试 CRC32 扩展时按预期执行。第二个 SIGILL
陷阱在测试 AES 扩展时没有按预期执行。下面是它在调试器下的样子。
我不相信代码属于文档所指出的未定义行为。例如,不使用嵌套信号处理程序,同一线程执行 setjmp
和 longjmp
魔法等。
我的问题是,如何安全地多次执行运行时特性测试?
gdb ./test.exe
...
(gdb) b TryCRC32()
Breakpoint 1 at 0x401034: file test.cc, line 92.
(gdb) b TryAES()
Breakpoint 2 at 0x401120: file test.cc, line 120.
...
(gdb) r
Starting program: /home/cryptopp/test.exe v
Breakpoint 1, TryCRC32 () at test.cc:92
92 volatile bool result = true;
(gdb) n
94 SigHandler oldHandler = signal(SIGILL, SigIllHandlerCRC32);
(gdb)
95 if (oldHandler == SIG_ERR)
(gdb)
98 if (setjmp(s_jmpNoCRC32))
(gdb)
102 word32 w=0, x=0; word16 y=0; byte z=0;
(gdb)
103 w = __crc32cw(w,x);
(gdb)
Program received signal SIGILL, Illegal instruction.
0x00000000004010b4 in __crc32cw (__b=0, __a=0)
at /usr/lib/gcc/aarch64-linux-gnu/4.9/include/arm_acle.h:57
57 return __builtin_aarch64_crc32cw (__a, __b);
(gdb) c
Continuing.
Breakpoint 2, TryAES () at test.cc:120
120 volatile bool result = true;
(gdb) n
122 SigHandler oldHandler = signal(SIGILL, SigIllHandlerAES);
(gdb)
123 if (oldHandler == SIG_ERR)
(gdb)
126 if (setjmp(s_jmpNoAES))
(gdb)
130 uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
(gdb)
131 uint8x16_t r1 = vaeseq_u8(data, key);
(gdb)
Program received signal SIGILL, Illegal instruction.
0x0000000000400a64 in vaeseq_u8 (data=..., key=...)
at /usr/lib/gcc/aarch64-linux-gnu/4.9/include/arm_neon.h:13731
13731 return __builtin_aarch64_crypto_aesev16qi_uuu (data, key);
(gdb) c
Continuing.
Program terminated with signal SIGILL, Illegal instruction.
The program no longer exists.
这是测试程序。它编译为:
$ export CXXFLAGS="-g3 -O0 -march=armv8-a+crc+crypto"
$ g++ $CXXFLAGS test.cc -o test.exe
-march=armv8-a+crc+crypto
表示定义了预处理器符号,如 __ARM_NEON
和 __ARM_FEATURE_CRYPTO
。
像 static volatile bool TryNEON()
这样的声明是 Mustang 揭示的另一个问题(即,GCC 正在优化检查)。它导致程序终止并返回 SIGILL
。不要因为它而分心,因为它现在只是权宜之计。
#include <signal.h>
#include <setjmp.h>
#include <stdint.h>
#include <arm_neon.h>
#include <arm_acle.h>
#include <iostream>
#define UNUSED(x) ((void)(x))
typedef uint8_t byte;
typedef uint16_t word16;
typedef uint32_t word32;
typedef uint64_t word64;
typedef void (*SigHandler)(int);
extern "C" {
static jmp_buf s_jmpNoNEON;
static void SigIllHandlerNEON(int)
{
longjmp(s_jmpNoNEON, 1);
}
static jmp_buf s_jmpNoCRC32;
static void SigIllHandlerCRC32(int)
{
longjmp(s_jmpNoCRC32, 1);
}
static jmp_buf s_jmpNoAES;
static void SigIllHandlerAES(int)
{
longjmp(s_jmpNoAES, 1);
}
static jmp_buf s_jmpNoSHA1;
static void SigIllHandlerSHA1(int)
{
longjmp(s_jmpNoSHA1, 1);
}
static jmp_buf s_jmpNoSHA2;
static void SigIllHandlerSHA2(int)
{
longjmp(s_jmpNoSHA2, 1);
}
};
static volatile bool TryNEON()
{
#if defined(__ARM_NEON)
volatile bool result = true;
SigHandler oldHandler = signal(SIGILL, SigIllHandlerNEON);
if (oldHandler == SIG_ERR)
result = false;
if (setjmp(s_jmpNoNEON))
result = false;
else
{
uint32_t v1[4] = {1,1,1,1};
uint32x4_t x1 = vld1q_u32(v1);
uint64_t v2[2] = {1,1};
uint64x2_t x2 = vld1q_u64(v2);
uint32x4_t x3 = vdupq_n_u32(0);
x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
uint64x2_t x4 = vdupq_n_u64(0);
x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
}
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_NEON
}
static volatile bool TryCRC32()
{
#if defined(__ARM_FEATURE_CRC32)
volatile bool result = true;
SigHandler oldHandler = signal(SIGILL, SigIllHandlerCRC32);
if (oldHandler == SIG_ERR)
result = false;
if (setjmp(s_jmpNoCRC32))
result = false;
else
{
word32 w=0, x=0; word16 y=0; byte z=0;
w = __crc32cw(w,x);
w = __crc32ch(w,y);
w = __crc32cb(w,z);
}
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_FEATURE_CRC32
}
static volatile bool TryAES()
{
#if defined(__ARM_FEATURE_CRYPTO)
volatile bool result = true;
SigHandler oldHandler = signal(SIGILL, SigIllHandlerAES);
if (oldHandler == SIG_ERR)
result = false;
if (setjmp(s_jmpNoAES))
result = false;
else
{
uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
uint8x16_t r1 = vaeseq_u8(data, key);
uint8x16_t r2 = vaesdq_u8(data, key);
UNUSED(r1), UNUSED(r2);
}
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_FEATURE_CRYPTO
}
static volatile bool TrySHA1()
{
#if defined(__ARM_FEATURE_CRYPTO)
volatile bool result = true;
SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA1);
if (oldHandler == SIG_ERR)
result = false;
if (setjmp(s_jmpNoSHA1))
result = false;
else
{
uint32x4_t data = vdupq_n_u32(0);
uint32_t hash = 0x0;
uint32x4_t r1 = vsha1cq_u32 (data, hash, data);
uint32x4_t r2 = vsha1mq_u32 (data, hash, data);
uint32x4_t r3 = vsha1pq_u32 (data, hash, data);
UNUSED(r1), UNUSED(r2), UNUSED(r3);
}
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_FEATURE_CRYPTO
}
static volatile bool TrySHA2()
{
#if defined(__ARM_FEATURE_CRYPTO)
volatile bool result = true;
SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA2);
if (oldHandler == SIG_ERR)
result = false;
if (setjmp(s_jmpNoSHA2))
result = false;
else
{
uint32x4_t data = vdupq_n_u32(0);
uint32x4_t hash = vdupq_n_u32(0);
uint32x4_t r1 = vsha256hq_u32 (hash, hash, data);
uint32x4_t r2 = vsha256h2q_u32 (hash, hash, data);
uint32x4_t r3 = vsha256su0q_u32 (data, data);
uint32x4_t r4 = vsha256su1q_u32 (data, data, data);
UNUSED(r1), UNUSED(r2), UNUSED(r3), UNUSED(r4);
}
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_FEATURE_CRYPTO
}
bool hasNEON = TryNEON();
bool hasCRC32 = TryCRC32();
bool hasAES = TryAES();
bool hasSHA1 = TrySHA1();
bool hasSHA2 = TrySHA2();
int main(int argc, char* argv[])
{
std::cout << "Has NEON: " << hasNEON << std::endl;
std::cout << "Has CRC32: " << hasCRC32 << std::endl;
std::cout << "Has AES: " << hasAES << std::endl;
std::cout << "Has SHA1: " << hasSHA1 << std::endl;
std::cout << "Has SHA2: " << hasSHA2 << std::endl;
return 0;
}
最佳答案
代码有两个问题。首先,所有变量都变得不稳定。其次,需要保存和恢复工艺掩码。第二个问题仅在不存在某个功能时出现,并且在第二次(或后续)失败的功能测试时出现。如果该功能可用,则问题不会浮出水面。
这是一个例子:
static bool TryNEON()
{
#if defined(__ARM_NEON)
volatile bool result = true;
volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerNEON);
if (oldHandler == SIG_ERR)
return false;
volatile sigset_t oldMask;
if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
return false;
if (setjmp(s_jmpNoNEON))
result = false;
else
{
uint32_t v1[4] = {1,1,1,1};
uint32x4_t x1 = vld1q_u32(v1);
uint64_t v2[2] = {1,1};
uint64x2_t x2 = vld1q_u64(v2);
uint32x4_t x3 = {0,0,0,0};
x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
uint64x2_t x4 = {0,0};
x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
// Hack... GCC optimizes away the code and returns true
result = !!(vgetq_lane_u32(x3,0) | vgetq_lane_u64(x4,1));
}
sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
signal(SIGILL, oldHandler);
return result;
#else
return false;
#endif // __ARM_NEON
}
关于c++ - 运行时特性测试、setjmp、longjmp 和信号掩码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37516057/
有没有办法使用 setjmp 来实现多任务处理?和 longjmp职能 最佳答案 这是所谓的用户空间上下文切换的一种形式。 这是可能的,但很容易出错,特别是如果您使用 setjmp 和 longjmp
我想在 Linux 环境中实现 POSIX 兼容的微线程。基本思路如下: 使用描述的技术 here , 为每个纤程分配新的栈空间。 使用 setitimer,创建将以固定时间间隔发送信号的计时器。此计
ISO/IEC 9899:1999 7.13.1.1 The setjmp macro Environmental limits 4 An invocation of the setjmp macro
我一直在尝试追踪我的代码(使用 setjmp)中的间歇性崩溃错误,并将其缩小为:在使用/O2 编译时显示,使用/O2/Oy- 消失,即仅显示省略帧指针。 http://msdn.microsoft.c
通常 setjmp 和 longjmp 不关心调用栈——函数只是保存和恢复寄存器。 我想使用 setjmp 和 longjmp 以便保留调用堆栈,然后在不同的执行上下文中恢复 EnableFeatur
下面的代码无法正常工作。谁能指出原因 #define STACK_SIZE 1524 static void mt_allocate_stack(struct thread_struct *mythr
一段代码在这里 jmp_buf mark; int Sub_Func() { int be_modify, jmpret; be_modify = 0; jmp
我的问题针对的是 setjmp/longjmp 关于局部变量的行为。 示例代码: jmp_buf env; void abc() { int error; ... if(error)
我正在尝试为 C OSX Carbon 多线程 应用程序安装“崩溃处理程序”。在 Windows 上,我可以轻松使用简单高效的 __try{} __except{} SEH of Windows效果很
我必须使用 setjmp/longjmp 实现用户级线程库作为作业。这是我写的代码: #include #include #include #include #include #includ
这个问题来自 SetJmp/LongJmp: Why is this throwing a segfault? 当我使用 Debug模式运行代码时,它确实按预期崩溃了。但是如果我使用 release
我不明白为什么在函数 middleFunc() 中,当 entry_point(arg) 在 if ( setjmp(中间) ) 语句。 #include #include
为什么 setjmp 不保存堆栈? 考虑以下代码: #include jmp_buf Buf; jmp_buf Buf2; void MyFunction() { for(int i = 0
#include #include #include #include static jmp_buf env_alrm; static void sig_alarm(int signo) {
在不久前的blog post中,Scott Vokes使用C函数setjmp和longjmp描述了与lua实现协程相关的技术问题: The main limitation of Lua corouti
在jpeglib ,必须使用 setjmp/longjmp 来实现自定义错误处理。 有很多资源说 setjmp/longjmp 不能很好地与 c++ 配合使用(例如 this question 中的答
我的问题针对的是 setjmp/longjmp 关于局部变量的行为。 示例代码: jmp_buf env; void abc() { int error; ... if(error)
我试图理解以下代码中的 setjmp: http://androidxref.com/4.2.2_r1/xref/frameworks/base/core/jni/android/graphics/Y
我正在调查setjmp/longjmp,发现setjmp 保存指令指针、堆栈指针等寄存器... 然而,我在这里没有得到的是,在调用 setjmp 和 longjmp 之间,不能修改线程本身堆栈中的数据
在 Why volatile works for setjmp/longjmp , 用户 greggo评论: Actually modern C compilers do need to know t
我是一名优秀的程序员,十分优秀!