Converting a C Program to Assembly Code

How exactly do I convert this C program to assembly code? I find it difficult to understand this process or how to start it. I am new to this. Any help would be appreciated!

     if(a > b){
        a = a - b;
          b = b - a;
   return a;


Side note: Suppose two positive integers a and b are already set in register R0 and R1.
Can you leave comments explaining how you did this?


source to share

5 answers

If you are using gcc

, you can get the assembly as gcc -S -o a.s a.c

if your source code a.c

. If you are using Visual Studio, you can get it when debugging by selecting the Disassembly window. Here is the output from Visual studio (I named a subprocess / function called "common", which is why "common" appears):

    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  
    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]  


Here the variable is a

first stored in memory, which means b

( dword ptr [b]




The professor who taught me systems programming used what he called "atomic-C" as a stepping stone between C and assembly. Rules for Atom-C (at best from my recollection):

  • only simple expressions are allowed, i.e. a = b + c;

    allowed a = b + c + d;

    because there are two operators there.
  • only simple boolean expressions are allowed in an if statement, i.e. if (a < b)

    allowed but if (( a < b) && (c < d))

    not allowed.
  • only if the operators are not blocking.
  • no for / while or do-while allowed, only goto and label

Thus, the above program will be translated;

     if (a == b) 
         goto label2;

     if (a < b)
         goto label4;

     a = a - b;
     goto label3;

     b = b - a;

     goto label1; 

     return a;


I hope I got it right ... It's been almost twenty years since I had to write Atom-C. Now assuming this is correct, let's start converting some of the atom-C operators to MIPS (assuming that's what you are using). From the link provided by Elliott Frisch, we can translate the subtraction steps almost immediately:

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


I used unsigned subtraction due to the fact that a and b were both positive integers.

The comparison can be done as follows:

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


The problem is that the third parameter of the beq opcode is the movement that the PC moves. We won't know this value until we do a manual build here.

The inequality is greater. If we leave the pseudocode instructions, we first need to use an opcode set on less than

that puts one in the destination register if the first register is less than the second. Once we have done that, we can use branch on equal

as described above.

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


The jumps are simple, they are just j and then the label to jump to. So,

goto label1 becomes j label1


The last thing we need to do is return. The return is done by moving the value we want to the special register V0 and then moving on to the next instruction after calling this function. The problem is that MIPS does not have a register to register the move command (or, if it has forgotten it), so we move from register to RAM and then back. Finally, we use the special register R31, which contains the return address.

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


With this information, the program becomes. And we can also customize jumps that we didn't know before:

 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
 0x0118        SUBU R1, R1, R0                ; b = b - a;
 0x011C        J L1                           ; goto lable1
 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


It's been almost twenty years since I had to do this kind of thing (now if I need an assembly, I just do what others have suggested and let the compiler do the hard work). I'm sure I've made a few mistakes along the way and will be glad for any corrections or suggestions. I just got into this long discussion because I interpreted the OP's question as doing a hand translation - something that someone could do as they were looking into assembly.




I translated this code into a 16-bit NASM build:

    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!

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

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

    push ax;        return A


I used ax

instead r0

and bx

instead ofr1



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
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
       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
       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
       CLR P1.2
       DJNZ R5,BACK1       // repeats the subroutine DLOOP 100 times
       MOV P0,#11111111B

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

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




Try your code here. Just copy it inside the main function, define the variables a

and b

in front of your loop while

, and you're good to go.

You can see how the code is compiled to build with enough explanation, and then you can execute the build code inside a hypothetical processor.



All Articles