簡體   English   中英

將C程序轉換為匯編代碼

[英]Convert C program into assembly code

我究竟如何將這個 C 程序轉換成匯編代碼? 我很難理解這個過程或者如何開始它。 我是新來的。 任何幫助,將不勝感激!

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

旁注:假設兩個正整數 a 和 b 已經在寄存器 R0 和 R1 中給出。
你能留下評論解釋你是如何做到的嗎?

如果您使用的是gcc ,並且您的源代碼是ac ,則可以將程序集作為gcc -S -o as ac ac 如果您使用的是 Visual Studio,則可以在調試時通過選擇“反匯編”窗口來獲取它。 這是 Visual Studio 的輸出(我將子程序/函數命名為“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] )也是如此。

教我系統編程的教授使用他所謂的“atomic-C”作為 C 和匯編之間的墊腳石。 atomic-C 的規則是(據我所知):

  1. 只允許簡單的表達式,即a = b + c; 允許a = b + c + d; 不允許,因為那里有兩個運營商。
  2. if 語句中只允許使用簡單的布爾表達式,即允許if (a < b)但不允許if (( a < b) && (c < d))
  3. 只有 if 語句,沒有 else 塊。
  4. 不允許 for / while 或 do-while,只有 goto 和 label 的

所以,上面的程序將轉化為;

 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;

我希望我說對了……距離我上次不得不寫 atomic-C 已經快二十年了。 現在假設以上是正確的,讓我們開始將一些 atomic-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操作碼的set on less than如果第一個寄存器小於第二個,則在目標寄存器中放置一個。 一旦我們這樣做了,我們就可以像上面描述的那樣branch on equal使用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 問題解釋為手工翻譯——有人在學習匯編時可能會這樣做。

干杯。

我已將該代碼轉換為 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

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

http://ctoassembly.com

嘗試在此處執行您的代碼。 只需將它復制到主函數中,在while循環之前定義ab變量,就可以了。

您可以通過大量的解釋了解如何將代碼編譯為匯編代碼,然后您可以在假設的 CPU 中執行匯編代碼。

雖然這是編譯器的任務,但如果你想讓你的手變臟,那么看看Godbolt

這是一款出色的編譯器資源管理器工具,可讓您將 C/C++ 代碼逐行轉換為匯編代碼。

如果您是初學者並且想知道“C 程序如何轉換為程序集?” 然后我在這里寫了一篇詳細的文章。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM