为什么每次内存地址的最后一位都一样

Why are the last digits of the memory addresses same each time

这更像是一个请帮助我理解而不是调试问题。所以,我最近开始研究 C,在使用指针工作了一段时间后,我遇到了这种情况。

#include <stdio.h>

int main()
{
        char *name="Bob";
        for(int i=0;i<3;i++)
        {
                printf("Address is %0x and value is %ld",name,*name);
                printf("\n");
                name++;
        }
        printf("\n");
        return 0;
}

我 运行 程序 3 次并得到类似 -->

的输出
Address is 9a756008 and value is 66
Address is 9a756009 and value is 111
Address is 9a75600a and value is 98

Address is ba49d008 and value is 66
Address is ba49d009 and value is 111
Address is ba49d00a and value is 98

Address is 2cb44008 and value is 66
Address is 2cb44009 and value is 111
Address is 2cb4400a and value is 98

我的问题是:内存每次都被分配 运行domly 那么为什么所有三种情况下的最后三位数字(每次我 运行 程序都得到相同的结果)相同?内存分配有没有固定的规则?

如有任何信息,我们将不胜感激。谢谢! :)

地址是程序加载器故意随机化的。此随机化仅影响地址的较高位。

如果程序中存在某些缺陷并且攻击者知道程序存储某些数据或代码的某些地址,则攻击者可能能够利用这些缺陷获得他们不应访问的权限或数据。例如,如果一个程序错误地接受了太多的输入,它会遍历程序为数据保留的数组,额外的输入会覆盖内存中的其他内容,例如堆栈上的 return 地址。当攻击者知道代码在内存中的位置时,他们可以构造输入,以便 return 地址被攻击者编辑的地址 select 覆盖,从而允许攻击者选择程序执行的代码.

为了减少这种情况发生的可能性,优秀的现代程序加载器使用 address space layout randomization。加载程序时,程序各部分在内存中的起始位置是随机select的。这可以防止攻击者确切知道数据或代码的位置。

程序加载器的起始位置可能受到操作系统和可执行文件格式的各种规则的限制select。操作系统仅以称为 的某种大小为单位分配内存。 4096 字节是典型的页面大小。程序可能期望其布局的某些部分(常量数据、程序代码、初始化的非常量数据等)从页面边界开始。在这种情况下,程序加载器只能 select 作为页面边界的随机地址。如果一个页面是 4096 字节,则每个页面的起始地址是 100016 的倍数(十六进制 1000 = 4096)。

这意味着起始地址的格式为 xxx00016,其中 xxx是由程序加载器编辑的随机值 select,000 是页面的开始。页面中的任何内容都会受到 xxx 中更改的影响,但 000 中的更改不会影响它。

因此,如果某些数据位于相对于其程序段开头的偏移量 678 处,则其地址将始终具有某个值 xxx678,并且 xxx 会因程序运行而异,但 678 不会。

这些规则源于操作系统和程序加载器的行为,它们是 C 实现的一部分。它们不是 C 标准的一部分。