有时,在各种Unix体系结构中,在程序运行时重新编译程序会导致程序崩溃并出现“总线错误”。任何人都可以解释这种情况发生的原因吗首先,如何更新磁盘上的二进制文件对内存中的代码做了什么?我唯一能想到的是,有些系统会将代码映射到内存中,当编译器重写磁盘映像时,这会导致mmap无效。这种方法的优点是什么?通过更改可执行文件来崩溃运行代码似乎非常不理想。
答案 0 :(得分:2)
在本地文件系统上,所有类似Unix的系统都支持通过删除文件来解决此问题。旧的vnode保持打开状态,即使目录条目消失后再重新用于新映像,旧文件仍然存在,未更改,现在未命名,直到最后一次引用(在本例中为内核)消失
但是如果你刚开始重写它,那么是的,它是mmap(3)'ed。重写块时,可能会发生以下两种情况之一,具体取决于动态链接器使用的mmap(3)选项:
无论哪种方式,正在运行的程序都可能遇到麻烦。在第一种情况下,基本上保证会爆炸,在第二种情况下,除非所有页面都被引用,分页并且永不丢弃,否则它将被破坏。
有两个用于解决此问题的mmap标志。一个是MAP_DENYWRITE(防止写入),另一个是MAP_COPY,它保留了原始版本的纯版本,并阻止编写者更改映射图像。
但出于安全原因,DENYWRITE已被禁用,并且COPY未在类Unix系统中实现。
答案 1 :(得分:0)
这是一个有点复杂的情况,可能会发生在你的情况下。此错误的原因通常是内存对齐问题。总线错误更常见于基于FreeBSD的系统。考虑一个具有类似结构的场景,
struct MyStruct { char ch [29]; // 29个字节 int32 i; // 4字节 }
所以这个结构的总大小是33个字节。现在考虑一个具有32字节高速缓存行的系统。此结构无法加载到单个缓存行中。现在考虑以下陈述
Struct MyStruct abc; char * cptr =& abc; //结构开始时的char点 int32 * iptr =(cptr + 1)// iptr指向结构的第二个字节。
现在总结构大小是33个字节,你的int指针指向第二个字节,所以你可以从int指针读取32个字节的数据(因为分配的内存的总大小是33个字节)。但是当您尝试读取它并且如果在高速缓存行的边界处分配结构时,则OS不可能在单个调用中读取32个字节。因为当前高速缓存行仅包含31个字节的数据,剩余的1个字节在下一个高速缓存行上。这将导致无效的地址,并将给出“Buss错误”。大多数操作系统通过在内部生成两个内存读取调用来处理这种情况,但某些Unix系统不处理这种情况。为避免这种情况,建议请注意内存对齐。当您尝试将结构类型转换为另一种数据类型并尝试读取该结构的内存时,通常会发生这种情况。
场景有点复杂,所以我不确定我是否能以更简单的方式解释它。我希望你理解这个场景。