gpt4 book ai didi

c - 可寻址内存与缓冲区溢出的关系

转载 作者:太空狗 更新时间:2023-10-29 15:05:58 25 4
gpt4 key购买 nike

阅读有关缓冲区溢出的内容时,我发现了下面给出的示例代码:-

void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}

void main() {
function(1,2,3);
}

我猜它来自著名的 smashing the stack for fun and profit 文章。 (引用:http://insecure.org/stf/smashstack.html)

文章说要为 buffer1 和 buffer2 分配空间,需要 20 个字节(8 个字节用于 buffer1,12 个字节用于 buffer2),因为内存地址只能以字大小的倍数访问(1 个字 = 4 个字节)例)。

但我记得内存是字节可寻址的,即我一次可以从内存中访问 1 个字节。我将此与处理器的位数联系起来。例如一个 32 位处理器可以访问 2^32 个内存位置,并且由于 1 个内存位置包含 1 个字节(8 位),因此 32 位处理器的总可寻址内存等于 (2^32)/(1024*1024*1024) = 4096 MB = 4GB。

既然在上面的例子中,buffer1和buffer2都是char类型,假设需要1个字节,那为什么我们不能分别为buffer1和buffer2分配5个字节和10个字节呢?

为什么内存访问限制为字长的倍数?

最佳答案

首先 - 内存访问 不受字长的限制。

正如您所指出的,您可以自由访问各自 CPU 支持的最精细粒度的内存 - 在大多数情况下,这将是字节。

然而,对于 C 中的局部变量,对齐 规则有些特殊。
整个单词访问限制与函数局部变量位于所谓的堆栈 上这一事实有关。

堆栈由 CPU 提供,用于临时存储和检索内存中的寄存器值,每个程序都有自己的内存用作堆栈空间。通常/在某些情况下需要以您的 CPU 使用的寄存器大小访问堆栈,这样您就不会意外地破坏 CPU 使用的推送/弹出访问。在 32 位系统上,访问大小是每个寄存器 4 个字节,对于 64 位系统,它是 8 个字节。

因此在您的示例中,函数的堆栈在 Intel CPU 上可能看起来像这样(取决于操作系统):

|---   function's stack bottom  ---|
| 4 byte Code-Segment index |
| 4 byte return address |
| 4 byte buffer1[0..3] |
| 1 byte buffer1[4], 3 byte pad |
| 4 byte buffer2[0..3] |
| 4 byte buffer2[4..7] |
| 2 byte buffer2[8..9], 2 byte pad |
|--- function's stack top ---|

填充字节是必需的,这样当你的程序运行并从你的函数内部使用堆栈时,它仍然会正确对齐(相信我,它会经常使用它;))。

例如推送/弹出仍会导致 4 字节对齐的地址。

请记住:此对齐规则仅适用于堆栈空间 - 全局或静态变量可以位于奇数内存位置(不太可能,但可能)

我希望这不是针对技术人员/低级人员。

[编辑]
如果您考虑以下事情,这里与缓冲区溢出的关系就会变得很清楚:如果您知道内存和堆栈布局,您就可以操纵诸如返回地址之类的东西。正如您所看到的,通过溢出/下溢缓冲区,您可以轻松更改位于堆栈上方/下方的值。
在大多数情况下,这会使您的代码崩溃,但如果执行得当,您还可以将一些可执行代码放在堆栈上/内存中的某处,并更改函数的返回地址以跳转到该代码,而不是返回到调用它的位置。

关于c - 可寻址内存与缓冲区溢出的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16710381/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com