c语言程序经过编译后,每条指令都有一个内存地址,那两个程序如果有相同内存地址的指令怎么办?

发布于2022-01-01 18:13:57

加载到内存中不就会把另一个程序的指令覆盖了吗补充:是经过objdump以后,每条指令前面都有的那个地址,一般是0x400000左右,然后我还发现一些常数一般在0x

10个回答
admin
网友回答2022-01-01

现在每个进程都是操作系统提供的虚拟地址

admin
网友回答2022-01-01

编译后程序的运行环境和编译器没有指明。如果没有操作系统采用虚拟地址管理的条件下,程序地址重叠会出问题。

admin
网友回答2022-01-01

这个 硬件上 的 mmu,以及操作系统 支持的 多进程,虚拟地址空间,就是起这个作用,解决这个问题的 。这样,两个进程,有两个独立的地址空间,相互不会干扰,虽然有可能引用了同一地址,但经过每个 进程的 页表 映射 以后,映射到 不同的 物理地址 上去。这样的例子,典型的有linux 操作系统

某些实时 操作系统,不支持虚拟地址空间,所以,所有在系统上运行的 程序,必须一次性编译好,这样才不会有地址方面的冲突,这样的系统,不支持操作系统启动以后,再加载应用程序 。没有mmu 的 cpu 都采用这样的 操作系统,比如ecos

admin
网友回答2022-01-01

谁告诉你的?是每个映像加载到一块内存,也就是简单算是一个可执行文仲eⅹe或dll什么的,内存不够就加载不了,不过有页面文件,会把一些暂时不用的的进程占用的内存保存到磁盘,空出来的内存再加载新程序,切换时直接从磁盘恢复,所以内存用90%以上时,切换程序就卡

admin
网友回答2022-01-01

写时拷贝

admin
网友回答2022-01-01

实模式下,程序中有个重装载地址表,程序装载到内存时,按实际装载地址对表中指定位置进行地址修改。

虚拟内存模式下就不用担心了,每个程序都有独立的地址空间,由操作系统将虚地址映射到物理地址。

admin
网友回答2022-01-01

通俗说,这好比各个小区都有101房号,会冲突不。

程序的地址并不是绝对地址,而是相对地址。操作系统给运行的程序先安排起始地址存放在某寄存器中,再从相对地址0开始安排程序的相对地址。

安排的程序起始地址不同,不会冲突的。

绝对地址=起始地址+相对地址

admin
网友回答2022-01-01

首先,操作系统下的c程序在编译过程中,并不会将自己的数据占用的内存地址,变成一个绝对地址码,而是一个相对地址码。程序数据使用的所有地址都是被编译为: “基地址+偏移量”这样的形式。程序的基地址在不运行时为0,通常被隐藏,你看到的其实就是偏移量。

在操作系统下运行c程序时,系统会按照程序的内存使用量,给这个程序分配一块内存区域,也就是从地址A开始的一段内存空间。这个地址A,就是程序的基地址,也是首地址。假设一个程序编译完成后,需要占用20k的运行空间,当他运行时,系统就会给他规划一块20k的空间,但基地址并非固定的,而是系统根据当时的内存状况随机分配的。只有当程序运行时,其相对地址才会变成绝对地址,而且每一次运行,同一数据的绝对地址都会不一样。系统一般不会让一个程序的运行空间和另一个程序的空间发生干涉,那会带来太多不可控的后果。

当然,如果你是直接对硬件编程的话,数据地址也有可能被直接编译为绝对地址码,例如各种单片机C程序。但那就是另一个故事了。

admin
网友回答2022-01-01

这涉及到操作系统知识,而且这个似乎没写在教科书上。

C编译后的指令都写在可执行文件之中。所有指令地址都是从文件某个偏移开始的。

当操作系统加载可执行程序并分配进程时,会为每个进程分配自己的独有内存空间。

虽然两个进程的某个内存地址数值相同,但他们物理内存地址绝不相同,进程的独立内存空间只是对物理内存的一种映射关系而已。

再回到可执行指令加载话题。程序一般都有很多跳转指令,它需要一个绝对内存地址,这个就要求操作系统在加载进程时,分配一个进程基础地址,然后在所有跳转指令,以及某些全局变量地址中根据基础地址调整内存地址。

不只是进程加载,其实动态库加载都会涉及跳转指令地址调整问题。

当然,早期系统,例如dos系统,没有这套机制,它的程序内存地址都可以看作物理地址。但就现代操作系统来说,都是有这套机制的。

admin
网友回答2022-01-01

把一个程序自己的代码、数据、堆栈看成一块完整的砖头。编译器就是造砖机,安排好这一块砖内部的结构。

裸奔的系统就这一块砖,不会发生相互覆盖的矛盾。

如果跑多任务,砖头就多了。但这时通常会引入操作系统来管理砖头。堆砌砖头时会给每块砖头不一样的起始坐标,确保不发生两块砖头占一个空间的情况。

早期的dos操作系统规定每块砖头高度不超过1M。编译器做出来的每块砖内部都是用偏移地址0000h—ffffh来区分单元,但是操作系统在往物理内存搬砖堆砌时,会给每块砖不同的段起始地址,和偏移地址加在一起才是物理地址。这样就不会发生重叠了。

当然这里也有编译器的功劳。编译器除了造砖,还会生成一个规格标签,用于通知操作系统这砖有多大多厚,让操作系统能好好堆砖不浪费空间。不同操作系统的这种规格标签格式不一样,因此windows程序是不能直接跑在linux下的。

后来的处理器出现了mmu,内存管理单元,程序的地址空间和物理地址空间的换算就更复杂了。但是保证不同程序各自空间不发生覆盖还是基本要求。

一个程序能覆盖别的程序空间,大概是病毒恶意代码才做的事情。cpu的安全特性越来越强,这种情况很少见了吧。

回到
顶部