Mik*_*sev 3 c linux x86 assembly
我曾经以为,支持x86-64的未对齐的内存访问和无效的内存访问总是引起分段错误(除非,也许,SIMD指令像movdqa或movaps).不过最近我用正常mov指令观察到了总线错误.这是一个复制者:
void test(void *a)
{
asm("mov %0, %%rbp\n\t"
"mov 0(%%rbp), %%rdx\n\t"
: : "r"(a) : "rbp", "rdx");
}
int main()
{
test((void *)0x706a2e3630332d69);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
(必须用帧指针省略编译,例如gcc -O test.c && ./a.out).
mov 0(%rbp), %rdx指令和地址0x706a2e3630332d69是从有缺陷的程序的coredump复制的.将其更改为0会导致段0x706a2e3630332d60错误,但只是对齐仍然是总线错误(我的猜测是它与地址空间在x86-64上的48位相关).
问题是:哪些地址导致总线错误(SIGBUS)?它是由体系结构决定还是由OS内核配置(即在页表,控制寄存器或类似的东西中)?
Art*_*Art 10
SIGBUS处于悲伤状态.不同的操作系统之间没有达成共识,它的意义和生成时间在操作系统,CPU架构,配置和月相之间变化很大.除非您使用非常具体的配置,否则您应该将其视为"就像SIGSEGV,但不同".
我怀疑它本来应该是"你尝试过无论内核做什么都无法成功的内存访问",所以换句话说,你在地址中的确切位模式永远不会是有效的内存访问.最常见的是,这意味着严格对齐架构上的未对齐访问.然后,一些系统开始使用它来访问不存在的虚拟地址空间(例如,在您的示例中,您所拥有的地址不可存在).然后偶然的一些系统也意味着userland试图触摸内核内存(因为从技术上讲,它至少是从用户区的角度来看它不存在的虚拟地址空间).然后它变得随机.
除此之外,我见过SIGBUS:
通常,aSIGBUS可以在未对齐的内存访问中发送,即向非 8 字节对齐的地址写入 64 位整数时。然而,在最近的系统中。要么硬件本身正确处理它(尽管比对齐访问慢一点),要么操作系统在异常处理程序中模拟访问(具有 2 个或更多单独的内存访问)。
在这种情况下,问题是指定了允许的虚拟地址地址空间之外的地址。尽管指针是 64 位的,但只有 0-(2^48-1) (0x0-0xffffffffffff) 的地址空间在当前 64 位 intel 处理器上有效。Linux 为其进程提供的地址空间甚至更少,从 0-(2^47-1)(即 0-0x7ffffffffffff),其余的(0x800000000000-0xffffffffffff)由内核使用。
这意味着,内核会SIGBUS因为访问无效地址(每个地址 >= 0x800000000000)而发送 a ,而不是 a SIGSEGV,这意味着发生了对有效地址的访问错误(缺少页面条目、错误的访问权限、 ETC。)。