how can a label in assembly know its runtime address?
我正在学习汇编(z80 和 x86),现在开始掌握如何使用汇编器构建二进制文件。
如何使用带有绝对(相对于相对)地址的标签?
据我了解,汇编程序会在编译时将标签转换为内存地址,但是汇编程序如何知道标签在运行时将驻留在哪个地址?
对于 z80 裸机系统来说,这似乎很简单,因为您可以将程序加载到特定的内存地址并发送
在操作系统中执行的代码不会不知道它的起始地址(因此无法在标签上使用像
如果机器码不是位置无关的,有两种常用的策略:
-
在可执行文件中包含附加信息(AKA 重定位信息),告诉操作系统需要调整的绝对地址在哪里
-
只需将可执行文件加载到它想要的位置,这意味着您可能需要先驱逐另一个可执行文件,或者您需要为每个可执行文件提供单独的地址空间,因此一开始就无需为正确的位置而战
CP/M 的解决方案可能值得一读,它很简单:二进制文件总是在一个固定地址加载,操作系统入口点总是在另一个固定地址。这在 8 位机器上是相当典型的,即使是那些具有正式操作系统的机器,并且被带到 MS-DOS 中。使用 MMU 的多任务操作系统在技术上也是可行的,因为每个进程都有自己的地址空间,因此每个二进制文件都可以认为它是在同一个地方加载的。
使用可重定位代码之间的生成。要么它与位置无关,因为 CPU 很容易支持(根据经典 Mac OS 和 68000 的相对于 PC 的寻址),要么实际上是在加载二进制文件时发生经典两遍汇编程序的第二遍。因此,二进制文件是编译后的代码,其中包含所有绝对地址的占位符以及这些占位符所在位置的列表,以便在知道实际地址后可以替换它们。
唯一的问题是它会阻止快速虚拟内存。使用非 MMU Mac OS 方法,程序被编译为 16kb 块,每个块内的跳转直接发生,远程跳转通过寻呼机进行。如果目标块已加载,则关闭它,如果没有,则加载它,然后发生跳转。如果需要在每次加载时计算和填写地址,这种按需加载是令人望而却步的。
我猜,您的程序将小于 64 kb。在这种情况下,程序只需知道标签的偏移量(称为近跳转)。操作系统每次都在相同的 OFFSET 处启动程序,但在另一个段。条件跳转和"jmp short"仅使用 jmp 命令和标签之间的区别。在某些特殊情况下,例如如果一个过程在执行之前存储到堆栈中,编译器会插入一个代码来更改 jmp 命令的参数。
汇编器使用偏移量。
1 2 3 4 | LABEL . . . . . JMP LABEL // Knows the number of bytes to label. SO label can be anywhere. |