【问题标题】:MIPS ASSEMBLY How to use if's and else's translation from C to MIPS AssemblyMIPS ASSEMBLY 如何使用 if 和 else 从 C 到 MIPS 程序集的翻译
【发布时间】:2021-04-07 07:05:57
【问题描述】:

所以我有这段 C 代码,我必须翻译成程序集

    int a[10]={0,1,2,3,4,5,6,7,8,9};
    int i, j, k;
    i = 1;
    goto abc;
def:
        j = 1;
        k = 4;
    goto ghi;
    i = 2;
abc:
    goto def;
ghi:
    if (i==j){
        a[2] = a[3];
    }else{
        a[2] = a[4];
    }
    while(k>0){
        a[k] = 7;
        k = k - 1;
    }
    if((i>k) && (i<10)){
        if((k==6) || (j>=i)){
            a[9] = 400;
        }else{
            a[9] = 500;
        }
    }
    switch(j){
        case 0: a[6] = 4; break;
        case 1: a[6] = 5; break;
        case 2: a[6] = 6; break;
        case 3: a[6] = 7; break;
    }
    

我只能将 goto 部分转换为程序集,因为我不知道如何将 if 的 else 和 switch 命令转换为 MIPS 程序集 这是我到目前为止所做的事情

.text
main:
    li  $t0, 1
    lw  $t0, variableI      ## i = 1
    j abc               ## goto abc
def:
    li  $t0, 1
    lw  $t0, variableJ      ## j=1
    li  $t0, 4
    lw  $t0, variableK      ## k=4
    j ghi               ## goto ghi
    li  $t0, 2
    lw  $t0, variableI      ## i = 2
abc:
    j def               ## goto def
ghi:
    
    

.data
variableI:  .word
variableJ:  .word
variableK:  .word
vetorA:     .word 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

没有必要为我翻译所有代码,只需要很好地解释如何使用 if 和 else,因为我在网上没有找到任何真正好的解释。

【问题讨论】:

    标签: c assembly mips translate


    【解决方案1】:

    在线指令集手册将涵盖所有内容。以及编译器。

    unsigned int fun ( unsigned int a, unsigned int b, unsigned int c )
    {
        unsigned int r;
        
        r = 0;
        if(a==5)
        {
            r=6;
        }
        return(r);
    }
    
    mips-elf-gcc -O2 -c -fno-delayed-branch so.c -o so.o
    mips-elf-objdump -d so.o
    
    so.o:     file format elf32-bigmips
    
    
    Disassembly of section .text:
    
    00000000 <fun>:
       0:   24020005    li  $2,5
       4:   10820004    beq $4,$2,18 <fun+0x18>
       8:   00000000    nop
       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
      18:   24020006    li  $2,6
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    等于和不等于很容易,bne,beq...

    在这种情况下,编译器通常会生成与此相反的内容

    return reg = 0;
    compare input reg with 5
    if NOT equal then branch to skip
    return reg = 6
    skip:
    return
    

    但并非总是如此,gcc 会这样做

       0:   24020005    li  $2,5
       4:   10820004    beq $4,$2,18 <fun+0x18>
       8:   00000000    nop
    

    r2 是返回寄存器,现在用 5 作为临时寄存器加载它,以便进行比较。将输入 reg (r4) 与 5 进行比较,如果相等则跳转到地址 18。如果不相等则继续。

    如果不相等则

       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
    

    将 0 放入返回寄存器 r2 并返回。这条路径相当于

    r = 0;
    return(r);
    

    如果等于5则

      18:   24020006    li  $2,6
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    将 6 放入 r2 并返回

    对于这个示例 C 代码,编译器对解决方案非常暴力,除了不会产生更多分支以具有单个退出点(非典型)。

    unsigned int fun ( unsigned int a, unsigned int b )
    {
        unsigned int r;
        
        r = a;
        switch(b)
        {
            case 5: r+=3; break;
            case 7: r^=3; break;
        }
        return(r);
    }
    

    有时你会看到工具生成一个跳转表,这取决于架构和其他因素,在这种情况下不会发生,但如果你有 switch(b&3) 然后四种可能的情况,我尝试了 gcc没有做跳表。

    但真正的开关是什么?在这种情况下,在所有情况下,它只不过是 if(括号中的参数,在这种情况下只是 b 本身) b 是 5 否则 b 是 7 。 switch 是一个 if-then-else 树,通常编译器会费心去实现它。

    00000000 <fun>:
       0:   24030005    li  $3,5
       4:   00801025    move    $2,$4
       8:   10a30009    beq $5,$3,30 <fun+0x30>
       c:   00000000    nop
      10:   24030007    li  $3,7
      14:   14a30004    bne $5,$3,28 <fun+0x28>
      18:   00000000    nop
      1c:   38820003    xori    $2,$4,0x3
      20:   03e00008    jr  $31
      24:   00000000    nop
      28:   03e00008    jr  $31
      2c:   00000000    nop
      30:   24820003    addiu   $2,$4,3
      34:   03e00008    jr  $31
      38:   00000000    nop
    

    r = a

       4:   00801025    move    $2,$4
    

    如果 b == 5 那么

       0:   24030005    li  $3,5
    
       8:   10a30009    beq $5,$3,30 <fun+0x30>
       c:   00000000    nop
    

    r+=3 并返回

      30:   24820003    addiu   $2,$4,3
      34:   03e00008    jr  $31
      38:   00000000    nop
    

    (否则)如果 b==7

      10:   24030007    li  $3,7
      14:   14a30004    bne $5,$3,28 <fun+0x28>
      18:   00000000    nop
    

    r ^=3 并返回

      1c:   38820003    xori    $2,$4,0x3
      20:   03e00008    jr  $31
      24:   00000000    nop
    

    else return (r 设置为前面)

      28:   03e00008    jr  $31
      2c:   00000000    nop
    

    所以它是一棵简单的 if-then-else 树,其中有一个非蛮力无序的东西,r = a 被放置在 if b == 5 混合在一起的中间。

    unsigned int fun ( unsigned int a )
    {
        unsigned int r;
        
        r = 0;
        if(a<5)
        {
            r = 3;
        }
        return(r);
    }
    
    
    00000000 <fun>:
       0:   2c840005    sltiu   $4,$4,5
       4:   14800004    bnez    $4,18 <fun+0x18>
       8:   00000000    nop
       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
      18:   24020003    li  $2,3
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    因为 mips 是如何工作的,或者至少是我为之编译的 mips

    如果小于无符号则设置

       0:   2c840005    sltiu   $4,$4,5
    

    由于 C 的编写方式,我们实际上可以丢弃带有 if 小于问题的 a 变量。因此,如果 r4 (a) 小于 5,则“设置”r4(非零)

    所以现在小于变成了一个相等或不相等的问题

    if(r4 is not equal to zero) 结合上面的意思是如果a小于5那么

       4:   14800004    bnez    $4,18 <fun+0x18>
       8:   00000000    nop
    

    返回 3

      18:   24020003    li  $2,3
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    否则返回0

       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
    

    Mips 不像大多数其他指令集那样喜欢/使用标志。大多数其他人会有一个比较指令,它执行减法并设置一堆标志,但不将减法存储到寄存器中,然后后续指令将使用这些标志。 mips 使用无标志的理念,因此进行比较并在同一指令中对其进行操作。以另一种架构为例:

    00000000 <fun>:
       0:   e3500004    cmp r0, #4
       4:   93a00003    movls   r0, #3
       8:   83a00000    movhi   r0, #0
       c:   e12fff1e    bx  lr
    

    将 a 与 4 进行比较,如果小于或相同,则 r = 3 如果更高的 r = 0 并返回。这在某种程度上也是非常不典型的,因为此处显示的指令集 (arm) 允许按指令条件执行,而不仅仅是分支是有条件的,而 mov 和 add 则不是。

    而且这个比较典型

    00000000 <_fun>:
       0:   0a00            clr r0
       2:   2d97 0002 0004  cmp 2(sp), $4
       8:   8301            blos    c <_fun+0xc>
       a:   0087            rts pc
       c:   15c0 0003       mov $3, r0
      10:   0087            rts pc
    

    这几乎是一对一的蛮力

    r = 0

       0:   0a00            clr r0
    

    比较a(传入堆栈)和4

       2:   2d97 0002 0004  cmp 2(sp), $4
    

    如果更低或相同,则分支到地址 c:

       8:   8301            blos    c <_fun+0xc>
    

    如果 5 或更高,则返回(r = 0)

       a:   0087            rts pc
    

    如果小于5(小于等于4)则返回3

       c:   15c0 0003       mov $3, r0
      10:   0087            rts pc
    

    (目标在右边 mov $3,r0 表示 r0 = 3。$ 表示常量)

    【讨论】:

    • 嗯,谢谢你,先生,这真是太棒了!帮了我很多
    • 如果可以解决问题,请考虑accepting the answer
    【解决方案2】:

    从没想过我会再次使用这些知识!希望这会有所帮助。

    查看参考表并了解说明的作用会有所帮助。一般ifelse 可以用“branch if equal”(beq)或“branch if not equal”(bne)模拟。请查看以下参考以了解这些说明。

    另外,whileswitch 使用相同的指令 - 只需考虑代码应该如何流动。

    查看此参考以获取有关如何使用说明的更多详细信息,以及我未提及的其他内容。我会提到大多数指令应该使用寄存器,加载/保存单词,分支,基本跳转,数学等。

    https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_help.html

    【讨论】:

    • 所以第一个 if (i==j){ a[2] = a[3]; }else{ a[2] = a[4]; } 会变成类似 la $t0, vetorA lw $t1, variavelI lw $t2, variavelJ beq $t1,$t2, L2 ## case beq== false he did this lw $t1, 8($t0) sw $t1 , 16($t0) ## a[2] = a[4] j L2_fim L2: ##case beq==true 来到这里 lw $t1, 8($t0) sw $t1, 12($t0) # # a[2] = a[3] L2_fim: 你能告诉我这是否正确吗?
    猜你喜欢
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多