谁以及如何生成虚拟/逻辑地址?如果是编译器、链接器、加载器,会造成混乱

问题描述 投票:0回答:1

我知道当我编译一个程序然后用 objdump 检查时,我有地址。这些是相对地址

但是如果它是一个 C 程序,并且我使用 %p 来 printf 一个指针,那就是一个 虚拟/逻辑地址。谁产生这个?那是装载机吗?

如果是,为什么我需要加载程序来执行此操作? 一个相对地址(由编译器生成),然后MMU只需添加程序在实内存中的基址偏移量即可到达物理地址,这还不够吗?为什么需要虚拟地址而相对地址不够?

此外,虚拟地址应该用来创建一种假象,使进程成为内存中唯一的一个并且连续分配。我可以用相对(由编译器生成)地址来想象这一点,但我无法用虚拟/逻辑(由加载器生成)地址来想象......加载器如何实现将程序代码放入虚拟内存的连续部分?虚拟内存不是被其他程序在不同的部分使用吗?或者是否会发生

两个完全不同的程序具有相同的虚拟/逻辑地址?

另外,最后一个疑问:

为什么网上很多地方都写着“虚拟/逻辑地址是由CPU生成的”.....这不是真的.....它是由操作系统完成的,所以为什么这么写到处?我错过了什么吗?

memory memory-management paging virtual-memory virtual-address-space
1个回答
0
投票
答案是有多个答案,具体取决于内存的分配或使用方式。

案例一:

链接器定义进程的初始状态。如果您打印来自链接器的静态位置的地址。

案例二:

由于共享库(也由链接器创建)通常可以加载到不同的位置,因此这可能会变得复杂。在这种情况下,您的地址是由链接器(偏移量)和加载器的组合定义的。

为了安全起见,某些操作系统会在不同位置加载程序,这也可能会让情况变得复杂。在这种情况下,您的地址是由链接器和加载器的组合定义的。链接

正是出于这两个原因,我们努力寻求不依赖于特定内存位置的“位置无关代码”。

但是,在某些情况下,需要特定的内存位置或来自位置不独立的代码。

静态 int a, *b=&a ;

这里“b”的初始化需要知道“a”的位置。一些系统对此有解决方法,允许加载器在加载时初始化“a”,以便代码仍然可以独立于位置。

案例三:

如果要打印动态内存的位置,该位置通常来自运行时的操作系统。

int *x = malloc(sizeof(*x));

案例四:

如果要打印堆栈的位置,则该位置是在运行时通过备份确定的,该备份可以在运行时来自链接器或操作系统。在系统中,链接器定义堆栈。在其他情况下,操作系统定义堆栈。

© www.soinside.com 2019 - 2024. All rights reserved.