我今天写了这个小程序,结果被我吹走了。 这是程序
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代码有效,我不会过多担心。 这是一个侥幸模式,依赖于许多因素的顺序,如操作系统负载,使用的驱动程序,硬件,防病毒软件等…
另外,与代码相关的是,如果添加静态变量,函数,指针,这将改变二进制代码的布局,更重要的是,那些在运行时加载的符号的地址将会不同。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。