【问题标题】:Why the address of main function's parameter change each time?为什么main函数的参数地址每次都变?
【发布时间】:2011-05-11 11:18:53
【问题描述】:

我写了一个测试,打印argv[0]的内容——main函数的参数地址如下:

printf("%p\n",argv[0]);

我在 Windows 7 上使用 Visual Studio 2008 编译了该程序。

然后我执行程序 1000 次,将结果输出到文件中。结果 argv[0] 的地址发生了变化,但是,有些地址是相同的,并且重复了大约 10 次。

为什么main函数的参数地址每次都变化?

【问题讨论】:

  • 为什么每次都一样?为什么你在乎?您的首字母缩写词:ASLR - 地址空间布局随机化。
  • +1 用于 ASLR。所有技术中最酷的一种,可以使糟糕的应用程序变得更糟。 en.wikipedia.org/wiki/Address_space_layout_randomization
  • 要便携打印指针,需要转换为void*:printf("%p\n", (void*)argv);

标签: c parameters main memory-address


【解决方案1】:

argcargv 应在二进制可执行文件的主程序开始之前放入堆栈。其实我认为argv是在堆内的某处动态分配的,然后指针被放到栈上。

这意味着堆分配器是一个关心数据分配位置的分配器,这就是为什么它每次都会更改(取决于策略)..您的程序将要求操作系统为参数分配空间(考虑通过malloc)所以可以根据某些东西(比如他们谈论的ASLR)做出内部选择

【讨论】:

  • 操作系统与此无关。程序的地址空间不应依赖于物理内存页面的可用性
  • 我不是在谈论分页。我说的是操作系统内存分配器无论如何都选择了虚拟地址这一事实。当然,物理地址对程序来说是不可见且未知的,但是当您通过像malloc 这样的系统调用时,虚拟地址也是如此。
  • 但是 malloc 不是操作系统的一部分,操作系统也没有关于这些参数将获得的虚拟地址的发言权。
【解决方案2】:

有趣的问题,我很少或根本没有看到程序自己的地址空间中不确定性的原因。但我会告诉你我所知道的。

首先,argv 不是由 windows 而是由 stdc 运行时分配、创建和初始化的。这反过来又引发了另一个问题——winmain 的 lpCmdLine 参数是否也会改变?在同一个堆上分配了其他几个变量,可能还复制了环境变量。其中之一必须具有取决于执行实例的大小。

无论如何,为什么要黑盒思考?士兵,你的反汇编器呢?

【讨论】:

    【解决方案3】:

    首先,这是语言标准 (n1256) 的规定:

    5.1.2.2.1 程序启动
    ...
    2 如果它们被声明,主函数的参数应遵循以下 约束:

    • argc 的值应为非负数。

    • argv[argc] 应为空指针。

    • 如果argc的值大于零,则数组成员argv[0]通过 argv[argc-1] inclusive 应包含指向字符串的指针,这些指针是给定的 在程序启动之前由主机环境实现定义的值。这 意图是向程序提供在程序启动之前确定的信息 来自托管环境中的其他地方。如果宿主环境不能 提供带有大写和小写字母的字符串,实现 应确保以小写形式接收字符串。

    • 如果argc的值大于零,则argv[0]指向的字符串 表示程序名argv[0][0] 应为空字符,如果 程序名称在主机环境中不可用。如果argc 的值为 大于一,argv[1]argv[argc-1] 指向的字符串 表示程序参数

    • 参数argcargv以及argv数组指向的字符串应该 可由程序修改,并在程序之间保留它们最后存储的值 启动和程序终止。

    关于传递给main 的字符串参数的位置,最后一个项目符号是最有趣的。它们必须是可修改的,并且它们必须具有静态范围,这对它们在内存中的驻留位置设置了一些限制。不过,语言定义方面并不要求每次程序运行时它们都驻留在同一位置。

    我通过 MSDN 粗略搜索了一下,看看他们是否有明确的说法,但还没有找到任何东西。它可能归结为 OP 的 cmets 中提到的 ASLR。

    【讨论】:

    • 当然没有要求,也没有要求他们应该有所不同。与事实无关的事实带来的惊喜。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 2018-06-30
    相关资源
    最近更新 更多