C 如何引用自动变量。

How does C reference auto variables.

我正在尝试了解编译器如何引用自动变量。我的参考点是带有 XC32 编译器的 PIC32MZ 微控制器。

到目前为止,我了解了全局变量和静态变量的工作原理。编译器将它们放在内存中,然后将地址和大小直接硬编码到代码中。指令将包含地址。所以像 c = a + b 这样的操作,如果它们都是全局变量,看起来会像这样。 (sudo 程序集)

将a的地址移动到工作寄存器。 将 b 的地址移动到另一个工作寄存器。 添加两个工作寄存器。 将结果移动到 c 的地址。

这如何与自动变量一起使用?

看XC32编译器手册,auto变量是存放在栈上的。堆栈的末尾由堆栈指针跟踪。它没有提及稍后如何引用它们。如果变量在内存中的位置发生变化,指令将包含什么地址或命令?

有了动态内存,这个想法就很有意义了。 malloc 的 return 是指向新变量位置的指针,该指针存储在已存在的变量中。

我通过查看我编写的一些代码的反汇编找到了我正在寻找的答案。总体思路符合预期,但我发现细节令人惊讶。

这是函数开头和结尾的一小段。

函数开始

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 被添加回堆栈指针以释放正在使用的内存。