UCC编译器学习笔记20

UCC 编译器内部用英文单词 generate 来表示中间代码的生成,而用 emit 来表
汇编代码的生成,这里我们统一翻译为“生成”。

第 30 至 34 行的代码用于保存寄存器的值,第 35 行用于在栈空间中预留内存空
间,用来存放局部变量和临时变量,这部分工作被称为“Prologue 序言”,即在函数开始执
行时要处理的工作。而图 6.1.1 第 53 至 57 行被称为“Epilogue 尾声”,用于恢复原先保存的
寄存器值,第 58 行的汇编指令 ret 用于从栈中取出返回地址并返回。而函数 f 的返回值在第
50 至 51 行进行计算,并保存于寄存器 eax。

/**

 * Emit  assembly code for the translation unit

 */

void EmitTranslationUnit(AstTranslationUnit transUnit)

{

    if(ASMFileName){

        ASMFile = fopen(ASMFileName, "w");

        ASMFileName = NULL;

    }else{

        ASMFile = CreateOutput(Input.filename, ExtName);

    }

    SwitchTableNum = 1;

    // "# Code auto-generated by UCC\n\n"

    BeginProgram(); //就是做一些准备工作,把寄存器这些准备好

    // ".data\n\n"

    Segment(DATA);               //数据区开始了

    /**************************************************

        .str0:  .string "%d \012"

        .str1:  .string "a + b + c + d = %d.\012"

     **************************************************/

    EmitStrings();                //字符串,浮点数常量,全局变量,都会被UCC给收集起来

    EmitFloatConstants();

    EmitGlobals();

    // ".text\n\n"

    Segment(CODE);               //代码区开始了

    ImportFunctions();

    /************************************

        The key function is

            void EmitFunction(FunctionSymbol fsym)

        in x86.c

     ************************************/

    EmitFunctions(transUnit);

    EndProgram();

    fclose(ASMFile);

}

对应的汇编代码如下所示,还是挺有意思的:

按 C 标准的规定,当“函数的返回值是结构体对象,且该对象的大小
不落在
{1,2,4,8}”时(因为这些大小是基本类型),C 编译器会隐式地为该函数添加一个参数,该参数的类型是指向结构体对象的指针。例如,以下结构体 struct Data 的对象要占 32 字节,C 编译器会为函数GetData 隐式地添加一个 struct Data * recvaddr 参数,图 6.1.2 第 36 至 47 行的 if 语句用于对此进行处理。
struct Data {int dt[8];};
// C 程序员设定的函数接口
struct Data GetData(int num);
//被 C 编译器隐式地改为
void GetData(struct Data * recvaddr, int num);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值