因此,在MIPS中,静态变量在.data节中声明,并将它们放置在静态段的内存中。但是,汇编程序是在编译时确定这些地址,还是由操作系统将程序加载到内存中时确定这些地址?
答案 0 :(得分:1)
但是,汇编程序是在编译时确定这些地址,还是在操作系统将程序加载到int内存时确定这些地址?
这取决于操作系统,甚至取决于变量的类型:
10年前,大多数WLAN路由器都使用在其上运行 Linux 的MIPS CPU。
在Linux上,存在一种代码类型,称为“ 与位置有关”代码。这意味着代码将始终被加载到内存中的相同地址。在这种情况下,编译器工具链中的一个工具(编译器,汇编器,链接器...)(*)计算变量的地址并“正确”编写代码。示例:如果变量位于地址0x100024,则代码将如下所示:
lui t2, 0x10
lw t3, 0x24(t2)
然后有“ 位置无关”代码。这种类型的代码可以加载到任何地址。假定变量存储在地址X处,并且标签“ nextAddress”位于地址Y。地址X和Y可能会更改,但是差(X-Y)是固定的。假设X-Y = 0x100024:
bgezal zero, nextAddress
nop
nextAddress:
; Now the address "nextAddress" is in register "ra"
lui t2, 0x10
addu t2, t2, ra
; The next instruction will access address X+0x100024
lw t3, 0x24(t2)
当然,差异(X-Y)是由编译器工具链中的一个工具在编译时计算的。
也有在MIPS CPU上运行 Windows CE 的手持设备(类似于今天的智能手机)。
此操作系统使用所谓的“基本重定位表”:.EXE或.DLL文件包含“所需”地址。文件中的代码看起来像上述的“位置相关”代码。将文件加载到“所需”地址后,无需执行任何操作。
“ 基本重定位表”包含有关文件中地址的信息。例如,文件中所有lui
指令的列表。假设用于加载文件的“所需”地址为0x80000,但是Windows必须将文件加载至地址0xA0000。这意味着文件中所有变量的地址都会更改0x20000。 Windows将处理“基本重定位表”中的信息,并将0x20添加到文件中每个lui
指令的最后16位,因此在“位置”示例中,lui t2, 0x10
变为lui t2, 0x30
依赖代码”。
因此,变量的地址首先由编译器工具链计算,但随后由操作系统进行修改。
下一个可能性是“ 全局偏移表”(Linux)和“ 导入表”(Windows)。这些通常用于访问DLL文件中的变量。
全局偏移量表包含实际变量的地址。在C编程语言中,可以通过以下方式对此进行解释:
实际的C代码:
static int staticVariable;
...
staticVariable = 1234;
生成的汇编代码实际执行的操作:
static int staticVariable;
static int * staticVariable_got = &staticVariable;
...
(*staticVariable_got) = 1234;
组装代码:
lui t2, 0x10
lw t3, 0x24(t2)
; Now t3 contains the address of the variable
sw t4, (t3)
在这种情况下,编译器工具链将计算辅助“变量”(staticVariable_got
)的地址。但是,实际变量(staticVariable
)的地址仅是OS已知的。操作系统将该地址写入“变量” staticVariable_got
。
(*)注意,这不一定是链接程序;还有一些直接编写可执行文件的编译器(不需要汇编器或链接器),还有一些链接器的输出由其他工具进行后处理。