将C程序转换为汇编代码

时间:2014-09-29 02:10:22

标签: c assembly

我如何将此C程序转换为汇编代码?我很难理解这个过程或者如何开始它。我是新来的。任何帮助将不胜感激!

while(a!=b){
     if(a > b){
        a = a - b;
       }
        else{
          b = b - a;
    }
  }
   return a;
   }

侧注:假设已在寄存器R0和R1中给出了两个正整数a和b 你能留下评论解释你是怎么做到的吗?

6 个答案:

答案 0 :(得分:10)

如果您使用的是gcc,则如果源代码为gcc -S -o a.s a.c,则可以将程序集设为a.c。如果您使用的是Visual Studio,则可以在调试时通过选择"反汇编"来获取它。窗口。这是Visual Studio的输出(我将subrountine / function命名为" common"这就是为什么" common"出现):

    while(a!=b){
    003613DE  mov         eax,dword ptr [a]  
    003613E1  cmp         eax,dword ptr [b]  
    003613E4  je          common+44h (0361404h)  
         if(a > b){
    003613E6  mov         eax,dword ptr [a]  
    003613E9  cmp         eax,dword ptr [b]  
    003613EC  jle         common+39h (03613F9h)  
            a = a - b;
    003613EE  mov         eax,dword ptr [a]  
    003613F1  sub         eax,dword ptr [b]  
    003613F4  mov         dword ptr [a],eax  
         }
         else{
    003613F7  jmp         common+42h (0361402h)  
             b = b - a;
    003613F9  mov         eax,dword ptr [b]  
    003613FC  sub         eax,dword ptr [a]  
    003613FF  mov         dword ptr [b],eax  
        }
      }
    00361402  jmp         common+1Eh (03613DEh)  
       return a;
    00361404  mov         eax,dword ptr [a]  
    }

此处变量a最初保存在内存中,因此bdword ptr [b])。

答案 1 :(得分:9)

教我系统编程的教授使用了他所谓的原子C'作为C和装配之间的垫脚石。原子C的规则是(据我所知):

  1. 只允许使用简单表达式,即不允许使用a = b + c; a = b + c + d;,因为那里有两个运算符。
  2. if语句中只允许使用简单的布尔表达式,即允许if (a < b)但不允许if (( a < b) && (c < d))
  3. 仅限于陈述,没有其他阻止。
  4. 不允许/ while或do-while被允许,只有转到&标签&#39>
  5. 因此,上述计划将转化为;

     label1:
         if (a == b) 
             goto label2;
    
         if (a < b)
             goto label4;
    
         a = a - b;
         goto label3;
    
     label4:
         b = b - a;
    
     label3:
         goto label1; 
    
     label2:
         return a;
    

    我希望我能做到这一点......自从我上次写下原子C以来已经差不多二十年了。现在假设上面的内容是正确的,让我们开始将一些原子C语句转换为MIPS(假设你正在使用的)汇编。根据Elliott Frisch提供的链接,我们几乎可以立即转换减法步骤:

    a = a - b     becomes R0 = R0 - R1 which is: SUBU R0, R0, R1
    b = b - a     becomes R1 = R1 - R0 which is: SUBU R1, R1, R0
    

    我使用无符号减法,因为a和b都是正整数。

    比较可以这样做:

    if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?
    

    这里的问题是beq操作码的第三个参数是PC移动的位移。在我们完成手工装配之前,我们不会知道这个价值。

    不平等是更多的工作。如果我们遗留伪代码指令,我们首先需要使用set on less than操作码,如果第一个寄存器小于第二个寄存器,则将其放在目标寄存器中。完成后,我们可以使用上面描述的branch on equal

    if(a < b)              becomes    slt R2, R0, R1  
        goto label4                   beq R2, 1, L4?        
    

    跳转很简单,它们只是j然后跳转到的标签。所以,

    goto label1 becomes j label1
    

    我们必须处理的最后一件事是返回。返回是通过移动我们想要的值来完成的 一个特殊的寄存器V0,然后在调用该函数后跳转到下一条指令。问题是MIPS没有寄存器来注册移动命令(或者如果它我忘记了它),所以我们从寄存器移到RAM然后再返回。最后,我们使用保存返回地址的特殊寄存器R31。

    return a     becomes   var = a      which is SW R0, var
                           ret = var    which is LW var, V0
                           jump RA      which is JR R31
    

    有了这些信息,程序就变成了。我们还可以调整之前我们不知道的跳跃:

               L1:
     0x0100        BEQ R0, R1, 8
     0x0104        SLT R2, R0, R1                 ; temp = (a < b)  temp = 1 if true, 0 otherwise
     0x0108        LUI R3, 0x01                   ; load immediate 1 into register R3
     0x010C        BEQ R2, 1, 2                   ; goto label4         
     0x0110        SUBU R0, R0, R1                ; a = a - b
     0x0114        J L3                           ; goto label3
               L4:
     0x0118        SUBU R1, R1, R0                ; b = b - a;
               L3:
     0x011C        J L1                           ; goto lable1
               L2:
     0x0120        SW R0, ret                     ; move return value from register to a RAM location
     0x0123        LW ret, V0                     ; move return value from RAM to the return register.
     0x0124        JR R31                         ; return to caller
    

    我已经差不多二十年了,因为我必须做这样的事情(现在好几天,如果我需要组装,我只是做别人建议的事情,让编译器完成所有繁重的工作)。我确信在此过程中我犯了一些错误,并且会对任何更正或建议感到高兴。我只是进入了这个冗长的讨论,因为我将OP问题解释为手工翻译 - 有人在学习装配时可能会这样做。

    欢呼声。

答案 2 :(得分:1)

我已将该代码转换为16位NASM程序集:

loop:
    cmp ax, bx
    je .end;        if A is not equal to B, then continue executing. Else, exit the loop
    jg greater_than;    if A is greater than B...

    sub ax, bx;     ... THEN subtract B from A...

    jmp loop;       ... and loop back to the beginning!

.greater_than:
    sub bx, ax;     ... ELSE, subtract A from B...

    jmp loop;       ... and loop back to the beginning!

.end:
    push ax;        return A

我使用ax代替r0bx代替r1

答案 3 :(得分:0)

ORG 000H                   // origin
MOV DPTR,#LUT              // moves starting address of LUT to DPTR
MOV P1,#00000000B          // sets P1 as output port
MOV P0,#00000000B          // sets P0 as output port
MAIN: MOV R6,#230D         // loads register R6 with 230D
      SETB P3.5            // sets P3.5 as input port
      MOV TMOD,#01100001B  // Sets Timer1 as Mode2 counter & Timer0 as Mode1 timer
      MOV TL1,#00000000B   // loads TL1 with initial value
      MOV TH1,#00000000B   // loads TH1 with initial value
      SETB TR1             // starts timer(counter) 1
BACK: MOV TH0,#00000000B   // loads initial value to TH0
      MOV TL0,#00000000B   // loads initial value to TL0
      SETB TR0             // starts timer 0
HERE: JNB TF0,HERE         // checks for Timer 0 roll over
      CLR TR0              // stops Timer0
      CLR TF0              // clears Timer Flag 0
      DJNZ R6,BACK
      CLR TR1              // stops Timer(counter)1
      CLR TF0              // clears Timer Flag 0
      CLR TF1              // clears Timer Flag 1
      ACALL DLOOP          // Calls subroutine DLOOP for displaying the count
      SJMP MAIN            // jumps back to the main loop
DLOOP: MOV R5,#252D
BACK1: MOV A,TL1           // loads the current count to the accumulator
       MOV B,#4D           // loads register B with 4D
       MUL AB              // Multiplies the TL1 count with 4
       MOV B,#100D         // loads register B with 100D
       DIV AB              // isolates first digit of the count
       SETB P1.0           // display driver transistor Q1 ON
       ACALL DISPLAY       // converts 1st digit to 7seg pattern
       MOV P0,A            // puts the pattern to port 0
       ACALL DELAY
       ACALL DELAY
       MOV A,B
       MOV B,#10D
       DIV AB              // isolates the second digit of the count
       CLR P1.0            // display driver transistor Q1 OFF
       SETB P1.1           // display driver transistor Q2 ON
       ACALL DISPLAY       // converts the 2nd digit to 7seg pattern
       MOV P0,A
       ACALL DELAY
       ACALL DELAY
       MOV A,B             // moves the last digit of the count to accumulator
       CLR P1.1            // display driver transistor Q2 OFF
       SETB P1.2           // display driver transistor Q3 ON
       ACALL DISPLAY       // converts 3rd digit to 7seg pattern
       MOV P0,A            // puts the pattern to port 0
       ACALL DELAY         // calls 1ms delay
       ACALL DELAY
       CLR P1.2
       DJNZ R5,BACK1       // repeats the subroutine DLOOP 100 times
       MOV P0,#11111111B
       RET

DELAY: MOV R7,#250D        // 1ms delay
 DEL1: DJNZ R7,DEL1
       RET

DISPLAY: MOVC A,@A+DPTR    // gets 7seg digit drive pattern for current value in A
         CPL A
         RET
LUT: DB 3FH                // LUT starts here
     DB 06H
     DB 5BH
     DB 4FH
     DB 66H
     DB 6DH
     DB 7DH
     DB 07H
     DB 7FH
     DB 6FH
END

答案 4 :(得分:0)

https://ctoassembly.com

尝试在此处执行代码。只需将其复制到main函数中,在a循环之前定义bwhile变量,就可以了。

您可以通过大量解释了解如何将代码编译为汇编代码,然后您可以在假设的CPU内执行汇编代码。

答案 5 :(得分:0)

尽管这是编译器的任务,但是如果您想弄脏双手,请查看godbolt

这是一个很棒的编译器资源管理器工具,可让您将C / C ++代码逐行转换为汇编代码。

如果您是初学者,并且想知道“ C程序如何转换为程序集?”然后我在here上写了详细的帖子。