我试图了解编译器如何引用自动变量。我的参考点是带有XC32编译器的PIC32MZ微控制器。
到目前为止,我了解全局变量和静态变量是如何工作的。编译器将它们放在内存中,然后将地址和大小直接硬编码到代码中。指令将包含地址。因此,如果c = a + b之类的操作都是全局变量,则将看起来像这样。 (须藤组装)
将a的地址移动到工作寄存器。 将b的地址移到另一个工作寄存器。 添加两个工作寄存器。 将结果移到c的地址。
这对自动变量如何起作用?
通过阅读XC32编译器手册,自动变量将存储在堆栈中。堆栈指针跟踪堆栈的末尾。它没有提及以后如何引用它们。如果变量在内存中的位置发生变化,指令将包含哪个地址或命令?
有了动态记忆,这个想法就很有意义了。 malloc的返回是指向新变量位置的指针,并且该指针存储在已经存在的变量中。
答案 0 :(得分:0)
通过查看我编写的某些代码的反汇编,我找到了想要的答案。总的想法与预期的一样,但是我发现的细节令人惊讶。
这是函数开头和结尾的一小段。
功能开始
0x9D005640: ADDIU SP, SP, -56
0x9D005644: SW RA, 52(SP)
0x9D005648: SW S7, 48(SP)
0x9D00564C: SW S6, 44(SP)
0x9D005650: SW S5, 40(SP)
0x9D005654: SW S4, 36(SP)
0x9D005658: SW S3, 32(SP)
0x9D00565C: SW S2, 28(SP)
0x9D005660: SW S1, 24(SP)
0x9D005664: SW S0, 20(SP)
功能结束
0x9D0057CC: LW RA, 52(SP)
0x9D0057D0: LW S7, 48(SP)
0x9D0057D4: LW S6, 44(SP)
0x9D0057D8: LW S5, 40(SP)
0x9D0057DC: LW S4, 36(SP)
0x9D0057E0: LW S3, 32(SP)
0x9D0057E4: LW S2, 28(SP)
0x9D0057E8: LW S1, 24(SP)
0x9D0057EC: LW S0, 20(SP)
0x9D0057F0: JR RA
0x9D0057F4: ADDIU SP, SP, 56
开始时,堆栈指针(SP)会增加,以在堆栈上留出更多空间。由于堆栈从高位地址开始并向下移动,因此从堆栈指针中减去56即可移动堆栈。这可以通过ADDIU命令并添加负值来完成。
然后是令人惊讶的部分。 SW命令将数据从工作寄存器移至存储器。可以看出,S0到S7被复制了。根据MIPS文档所说,在使用S工作寄存器之前,需要先清空它们。然后,此行为与文档保持一致。
SW命令将数据从工作寄存器移动到存储器地址。这是我的问题得到回答的地方。列出的地址例如是20(SP)。这意味着SP +20。然后,该机制允许相对于SP寻址数据。通过添加到SP,这会将数据地址相对于堆栈指针移动到堆栈中。 20(SP)例程类似于子命令,因为内核在执行SW之前会计算SP + 20。
然后,当函数执行其操作时,它将使用现在可用的自由电阻。
最后,当操作完成时,使用LW命令将位于堆栈中的数据移回到工作寄存器中。与SW命令类似,堆栈的寻址是通过相对偏移量完成的。为了包装功能56,将其添加回堆栈指针以释放正在使用的存储器。