C编译器剖析_6.3.6 汇编代码生成_为“取地址”产生汇编指令

来源:互联网 发布:跳跃网络怎么样 编辑:程序博客网 时间:2024/06/07 17:47

6.3.6  为“取地址”产生汇编指令

    在这一小节中,我们来讨论一下以下两条中间指令的翻译:

    (1)取地址指令<ADDR,DST,SRC1,NULL>       

       例如 <ADDR,t0,  number, NULL>,表示取number的地址并保存到临时变量t0中

    (2)对象清零指令< CLR,DST,SRC1,NULL>     

       例如<CLR,arr,16,NULL>,表示把arr所占16字节的内存清零

    我们先举一个例子来说明,对于图6.3.14第4行局部数组arr的初始化来说,我们可以先通过第11行的CLR中间指令把数组arr所占16字节内存清零,然后再通过第12行的MOV指令对arr[0]进行赋值。第21至26行是CLR指令对应的汇编代码,我们调用在汇编中调用库函数memset实现了对象清零的操作。而对于第5行的“ptr1 = &num1;”而言,我们可以通过第13行的ADDR中间指令来取num1的地址,并保存于临时变量t0中,再通过第14行的MOV指令对ptr1进行赋值。第28行“leal  num1,%eax”是ADDR指令对应的汇编代码。


图6.3.14 取地址和对象清零的例子

    与取地址指令有关的中间指令还有第17行的DEREF指令和第18行的IMOV指令,我们已在前面的章节中介绍过这两条中间指令的翻译。通过这两条中间指令,我们可以实现第7行的C语句“*ptr1 = *ptr2;”所需的语义。

    接下来,我们来看看用于产生相应汇编代码的函数EmitAddress和函数EmitClear,如图6.3.15所示。第5行调用AllocateReg函数为ADDR指令里的临时变量DST分配一个寄存器,第7行产生汇编指令把SRC1的地址加载到DST对应的寄存器中,第8行调用ModifyVar来设置临时变量DST的回写标志位,表示“其在内存中的值”与“在寄存器中的值”已经不一致。


6.3.15     EmitAddress()和EmitClear()

    图6.3.15第10至35行用于为CLR指令产生汇编代码,当要清零的对象大小为{1,2,4}字节时,我们可以在第15至22行产生mov汇编指令来实现清零,否则我们就通过第32行产生汇编代码,在其中调用memset函数来实现对象清零。由于在汇编指令模板X86_CLEAR中使用了寄存器eax,我们需要在第28行调用SpillReg函数对寄存器eax进行回写。

    至此,我们完成了为各中间指令产生汇编代码的工作。

    最后,让我们再看一下Compile函数,如图6.3.16所示,这是我们从第3章开始一路走来的路线图,我们历经了“语法分析”、“语义检查”、“中间代码生成及优化”和“汇编代码生成”这几个阶段。


图6.3.16  Compile()


0 0