为什么以下2个(简化)示例为segfault(在Win7下使用GCC编译)?
案例1-写入函数指针
void f() {return;}
int main()
{
memcpy(&f, "", 1);
return 0;
}
案例2 - 调用数据指针
char f[] ={0xC3};
typedef void(*p)();
int main()
{
((p)f)();
return 0;
}
我知道这是因为我正在编写内存的RO部分并跳转到内存的非可执行部分。 (或类似的东西)。我的问题是从大局看出的“为什么”:
什么系统正是强制执行此操作?它是在操作系统级别吗?在HW级别?在HW级别,但是在将二进制文件加载到内存时需要由OS设置?这是什么子系统?等...
也许“如何”比“为什么”更好。
答案 0 :(得分:0)
对于Windows,这是通过页面保护在操作系统级别强制实施的。每个页面都分配了一组保护标志,指定其特征是什么(可读,可写,可执行,保护页等)。可以使用VirtualProtect更改页面保护,之后您就可以写入代码页。
在代码不可执行的封面下可能会受到NX标志等硬件的支持,这基本上是VirtualProtect
正在切换的内容。
答案 1 :(得分:0)
在x86平台上,它在硬件中实现:CPU将内存划分为页面(通常在32位平台上大小为4kb),每个页面都有不同的访问位(尽管直到相对较晚才实际支持执行访问标志)。
页面信息本身存储在内存中的表中; CPU只保留一个指向主表的寄存器,也可能是一些缓存的内容。
在OS级别,OS在每个上下文切换期间设置相应的表指针(并在分配内存的系统调用期间更改标志值),因此CPU始终知道当前进程可以访问哪些页面。