ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c语言if语句是如何变成汇编代码的?

2021-11-23 13:32:02  阅读:185  来源: 互联网

标签:语句 汇编 node 代码 else tok gen rax


1. 要编译的测试代码: 

int a;
int b = 3;

int main(void)
{
    if (3)
        a = 4;
    else
        b = 5;
}

 

2. 词法分析

  词法分析将c源代码解析成一个个的token。

  关键的,将if两个字符解析成一个if token,后续语法分析的输入就从两个字符减少为1个token,减小了语法分析的难度。

 

3. 语法分析

if (equal(tok, "if")) {
    Node *node = new_node(ND_IF, tok);
    tok = skip(tok->next, "(");
    node->cond = expr(&tok, tok);
    tok = skip(tok, ")");
    node->then = stmt(&tok, tok);
    if (equal(tok, "else"))
      node->els = stmt(&tok, tok->next);
    *rest = tok;
    return node;
  }

 

如果当前处理的token是if,则

3.1 创建新的类型为ND_IF的node。

 

3.2 跳过if后面的"("。

 

3.3 调用expr函数解析if语句()中的表达式,并将解析结果存储在node->cond。

 

3.4 跳过“)”。

 

3.5 调用stmt处理then语句块中的语句,这里是处理"a = 4;",将解析结果存储在node->then。

 

3.6 如果if语句还有else部分,则调用stmt处理else语句块中的语句,这里是处理"b = 5;",将解析结果存储在node->els。

 

3.7 node->cond,node->then,node->els都为node节点。

 

4. 代码生成

switch (node->kind) {
  case ND_IF: {
    int c = count();
    gen_expr(node->cond);
    cmp_zero(node->cond->ty);
    println("  je  .L.else.%d", c);
    gen_stmt(node->then);
    println("  jmp .L.end.%d", c);
    println(".L.else.%d:", c);
    if (node->els)
      gen_stmt(node->els);
    println(".L.end.%d:", c);
    return;
  }
...

 

如果当前处理的node节点类型为ND_IF,则

4.1 gen_expr

这个函数处理if语句的条件部分,这里是处理3。判断node节点为NUM,会生成汇编语句"mov     rax, 3",将3载入rax寄存器。

 

4.2 cmp_zero

cmp_zero会生成汇编语句"cmp     eax, 0",比较3和0。

 

4.3 println(" je .L.else.%d", c);

该语句会生成汇编代码" je .L.else.1",当上条比较语句中eax为0时会执行跳转,跳转到else分支运行。这里由于eax为3,所以不跳转。

 

4.4 gen_stmt(node->then);

这条语句会将then分支中的语句解析为汇编源码,这里是"a = 4;",这条语句是表达式语句,所以会调用gen_expr函数。

 

4.4.1 gen_expr

"lea     rax, a",将a的地址载入rax寄存器中。

"push rax",将rax入栈。

"mov     rax, 4",将4载入rax寄存器中。

"pop     rdi",将变量a的地址载入rdi寄存器。

"mov     [rdi], eax",将4写入变量a。

 

4.5 println(" jmp .L.end.%d", c);

执行完then分支代码后跳转到下一条语句处执行。

 

4.6 println(".L.else.%d:", c);

插入一条标签,表示else分支代码的开始,如果if语句条件为0会跳转到这。

 

4.7 gen_stmt(node->els);

生成else分支代码,处理"b = 5;"。

"lea     rax, b",将变量b的地址载入rax寄存器。

"push    rax",将rax寄存器入栈。

"mov     rax, 5",将5载入rax寄存器。

"pop     rdi",将b的地址载入rdi寄存器。

"mov     [rdi], eax",将5写入变量b中。

 

4.8 println(".L.end.%d:", c);

插入一条标签,表示if语句的结束,then分支语句执行完成后跳转到这里。

 

 

 

 

标签:语句,汇编,node,代码,else,tok,gen,rax
来源: https://www.cnblogs.com/iszhang/p/15592778.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有