把C语言编译成汇编是什么样子:5、如何用低级的汇编程序实现高级语言中【结构体】功能?

128 阅读1分钟

根据第4节数组的实现原理,我猜测,结构体变量的分配和管理也类似数组的管理,就是编译器提前分配计算好的结构体变量所占用的内存大小,并且分配好以栈帧为基地址的相对地址,下面来验证一下!

老规矩,先上一段简单的c语言代码:

#include<stdio.h>
struct Data{
    int a;
    double b;
};
int main(){
    // 结构体
    struct Data data;
    data.a = 15;
    data.b = 88.99;
    int i = data.a;
    double j = data.b;    
    return 0;
}

下面是上述c语言代码对应的汇编程序:

  movl	$15, -16(%rbp) # int数据15放到rbp - 16的内存处
	movsd	.LC0(%rip), %xmm0 # .LCO处的double数据放入xmm0寄存器,
	movsd	%xmm0, -8(%rbp) # double数据再从xmm0放到rbp-8地址处
	movl	-16(%rbp), %eax
	movl	%eax, -28(%rbp) # rbp-16处的整型数据15,放到rbp-28处
	movsd	-8(%rbp), %xmm0
	movsd	%xmm0, -24(%rbp) # 刚才的rbp -8的数据,再放到rbp-24的内存地址处
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
        
        。。。。。
        
        .LC0:
	.long	687194767
	.long	1079394140

果然不出我们所料,就是编译器算好了结构体变量的长度,每个内部变量应该在哪个地址处,然后用简单的汇编指令直接操作了rbp - xxx处的内存数据。

所以说,最关键的东西还是编译器内部计算变量地址、长度的逻辑,如何保证别算错,别覆盖。这个工作还是有些复杂的,编译器的实现原理也是很复杂的,据说C++编译器的代码,比linux代码还要复杂,当然了,主要也是因为C++支持的特性实在太多了,c++里面“回字能有88种写法~”。但是对于我们来说,编译器怎么给变量算地址这件事并不重要,我们只要知道,C语言中的struct结构体,就是靠这几条汇编指令实现的就好了。以后专修编译原理的时候,再去详细了解编译器的计算方式。目前先了解到汇编对于我来说就足够了