主函数总是在同一地址加载,而variables在大多数情况下有不同的地址?

我今天写了这个小程序,结果被我吹走了。 这是程序

int main(int argc,char **argv) { int a; printf("ntMain is located at: %p and the variable a is located at address: %p",main,&a); return 0; }

在我的机器上,主函数总是被加载到地址“0x80483d4”,并且variables的地址不断变化。这是怎么发生的? 我在操作系统中读到,作为虚拟化scheme的一部分,操作系统一直在重定位指令的地址。 那么为什么每次我运行这个程序时,主要被加载在同一个地址?

在此先感谢家伙。

如何打印进程在C中使用的内存的每个字节?

环境variables地址的随机化

在C#中获取线程的外部进程的起始地址

如何获得可靠的x86_64位linux系统的内存映射

如何在Linux中解码/ proc / pid / pagemap条目?

从内存中获取地址以在源代码中运行

multithreadingLinux进程的地址空间布局

在Linux中查找共享库的加载地址

将限制设置为Linux中可用的总物理内存

我们如何指定variables的物理地址?

在诸如Linux的ELF系统上,正常可执行文件(ELF类型ET_EXEC )加载段的地址在编译时是固定的。 像库这样的共享对象(ELF类型ET_DYN )被构建为位置无关的,其段可以在地址空间中的任何地方加载(可能对某些体系结构有一些限制)。 可以构建可执行文件,使得它们实际上是ET_DYN – 这些文件被称为“位置无关的可执行文件”(PIE),但不是常用的技术。

你所看到的是你的main()函数在你编译的可执行文件的固定地址文本段中。 在通过dlsym()定位之后,试着打印一个库函数的地址,例如printf() – 如果你的系统确实支持并启用了地址空间布局随机化(ASLR),那么你应该看到这个函数的地址从运行你的程序运行。 (如果你直接在你的代码中直接输入引用,就可以打印出库函数的地址,实际上你可能得到的是函数的过程查询表(PLT)trampoline的地址,它是静态编译在你的可执行文件中的一个固定地址。)

您看到的变量是从运行到运行的地址,因为它是在堆栈上创建的自动变量,而不是静态分配的内存。 根据操作系统和版本的不同,即使没有ASLR,堆栈基地址也可能会从运行转换为运行。 如果将变量声明移到函数外的全局变量中,您将看到它的行为与main()函数的行为相同。

下面是一个完整的例子 – 用gcc -o example example.c -dl编译:

#include <stdio.h> #include <dlfcn.h> int a = 0; int main(int argc,char **argv) { int b = 0; void *handle = dlopen(NULL,RTLD_LAZY); printf("&main: %p; &a: %pn",&main,&a); printf("&printf: %p; &b: %pn",dlsym(handle,"printf"),&b); return 0; }

main(...)是一个运行时启动库代码,其中操作系统每次加载并执行。 看看CRT(C运行时库),它将包含代码来执行此操作取决于您的编译器。

另一件需要牢记的地方 – 只要C代码有效,我不会过多担心。 这是一个侥幸模式,依赖于许多因素的顺序,如操作系统负载,使用的驱动程序,硬件,防病毒软件等…

另外,与代码相关的是,如果添加静态变量,函数,指针,这将改变二进制代码的布局,更重要的是,那些在运行时加载的符号的地址将会不同。

相关文章

引言 本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个...
引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要...
一. 宏观概念 ASP.NET Core Middleware是在应用程序处理管道...
背景 在.Net和C#中运行异步代码相当简单,因为我们有时候需要...
HTTP基本认证 在HTTP中,HTTP基本认证(Basic Authenticatio...
1.Linq 执行多列排序 OrderBy的意义是按照指定顺序排序,连续...