2

为什么以下2个(简化)示例会出现段错误(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 部分并跳转到内存的不可执行部分。(或类似的东西)。我的问题是“为什么”在大局意义上:
究竟是什么系统强制执行的?是在操作系统级别吗?在硬件层面?在硬件级别,但在将二进制文件加载到内存时需要由操作系统设置?这是什么子系统?ETC...

也许“如何”比“为什么”是一个更好的问题。

4

2 回答 2

0

在 x86 平台上,它在硬件中实现:CPU 将内存划分为页面(在 32 位平台上通常大小为 4kb),每个页面都有不同的访问位(尽管直到相对较晚的时候才真正支持执行访问标志)。

页面信息本身存储在内存中的表中;CPU只保留一个指向主表的寄存器,可能还有一些缓存的内容。

在操作系统级别,操作系统在每次上下文切换期间设置相应的表指针(并在分配内存的系统调用期间更改标志值),因此 CPU 始终知道当前进程可以访问哪些页面。

于 2013-09-17T12:35:11.913 回答
0

对于 Windows,这是通过页面保护在操作系统级别强制执行的。每个页面都为其分配了一组保护标志,指定其特征是什么(可读、可写、可执行、保护页面等)。可以使用VirtualProtect更改页面保护,之后您将能够写入代码页。

在幕后代码不可执行的情况下,可能会受到硬件的支持,例如 NX 标志,这本质上VirtualProtect是切换的。

于 2013-09-17T12:13:27.117 回答