Friday, 25 December 2015

C to Assembly conversion using ARM DS-5

Converting a C program to Assembly Program using ARM DS-5.

The best way to learn ARM assembly is by converting a C language program to Assembly.

1.First we'll set the Environment Variable. Press Winkey+R to open Run. Type SystemPropertiesAdvanced and press Enter


Click Environment Variables .Meanwhile open DS-5 vx.xx Command Prompt from Start Menu.





2.Click New...  in User variables . Set variable name as Path and Variable Name as dispalyed in DS-5 command prompt.In my case it is C:\Program Files\DS-5 v5.22.0\bin


Click OK when finished.

3.Now close and reopen DS-5 command prompt.
Use select_default_toolchain to change the compiler. Here I chose ARM Compiler 5


4.Now open Notepad and type the following source code.

void main()
{
int a[5],i;

for(i=0;i<5;i++)
       {
       a[i]=0;
       }
      
}


stdio.h is not necessary as printf,scanf aren't used. Save it as somename.c .In my case I named it as Ex1.c.The C file is in D:\C2ASM .Keep the file in a location as you wish.Using the command armcc -S somename.c generates somename.s which contains the assembly code.

Commands

D:
cd C2ASM
armcc -S Ex1.c



Warnings can be ignored. Now open  Ex1.s file. Now the check the highlighted code and ignore the remaining. You come across new instructions such as STR(Store) ,CMP(Compare),BX(Branch with exchange),BLT(Branch if less than) etc.,




        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        SUB      sp,sp,#0x14        ; Allocate 5*4 = 20B = 0x14 for array a
        MOV      r0,#0              ; i=0
        MOV      r1,r0              ; Load 0 in r1
        MOV      r2,sp              ; Starting address of array a is stored in r2
|L0.16|
        STR      r1,[r2,r0,LSL #2] ; 0-->address[r2 + 4*r0] or *a+4*i or a[i]=0 in C
        ADD      r0,r0,#1          ; r0=r0+1 or i=i+1 or i++
        CMP      r0,#5             ; Compare i and 5
        BLT      |L0.16|           ; if i < 5 jump to |L0.16|
        ADD      sp,sp,#0x14       ; De-allocate memory for array a
        BX       lr                ; Return
        ENDP

Note: Size of int is 4 B and hence 4 memory locations are need.To understand the working of BLT ,knowledge of conditional execution of ARM instructions and CPSR , SPSR registers is required.

Alternate way to perform C to assembly conversion:

1.Create a new C project.Add a new C file to the project and add code as shown below


Build project and open the .axf file in Debug folder.Click Disassembly Tab


Scroll through and search for main . The remaining code is related to C Run time and it is one of the reasons why code written in C is larger than in assembly.


A few more programs....

1.Calculating sum of 6 numbers

C code:
void main()
{
       int i,a[6];
       volatile int sum=0;
       for(i=0;i<6;i++)
              sum+=a[i];
      
}

Equivalent Assembly Code:

        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        SUB      sp,sp,#0x1c                    ; allocate space for sum and a[5] ie 24 B = 0x1C
        MOV      r0,#0                          ; i=0
        MOV      r1,sp                          ; pointer for a
        STR      r0,[sp,#0x18]                  ; 0 --> sum
|L1.16|
        LDR      r2,[r1,r0,LSL #2]              ; r2 <-- a[i]
        LDR      r3,[sp,#0x18]                  ; r3 <-- sum
        ADD      r0,r0,#1                       ; i++
        ADD      r2,r2,r3                       ; r2<--a[i]+sum 
        CMP      r0,#6                          ; Compare i and 6
        STR      r2,[sp,#0x18]                  ; r2 -->sum
        BLT      |L1.16|                        ; Is i<6 then jump to L1.16
        ADD      sp,sp,#0x1c                    ; Un allocate space
        BX       lr                             ; return
        ENDP


2.To compute the value of f(x) = x3 + 3x2 + 3x + 1 using function.

C code:
//  To perform f(x) = x^3+3x^2+3x+1

int func(int);

void main()
{
volatile int x,p;
/* volatile keyword prevents the compiler from performing optimizations on variables */
p=func(x);
}

int func(int x)
{
int f;
f=x*x*x +3*x*x +3*x +1;
return f;
}

Equivalent Assembly Code:


        AREA ||.text||, CODE, READONLY, ALIGN=2

func PROC
        ADD      r2,r0,#3         ; r2 = r0 +3            x+3
        MUL      r2,r0,r2         ; r2 = r0 * r2          x*(x+3)
        ADD      r1,r0,r0,LSL #1  ; r1 = r0 + 2*r0        3x
        MLA      r0,r2,r0,r1      ; r0 = r2 * r0 + r1     x*x(x+3)+3x ie x^3+3x^2+3x
        ADD      r0,r0,#1         ; r0 = r0 + r1          x^3 + 3x^2 + 3x + 1
        BX       lr               ; Return to main
        ENDP

main PROC
        PUSH     {r3,lr}          ; Push r3 and lr to stack
        LDR      r0,[sp,#0]       ; r0 <-- x
        BL       func             ; Call func
        STR      r0,[sp,#0]       ; x is no more needed,So save f in same location occupied by x
        POP      {r3,pc}
        ENDP

3.Switch case statement

C code:

void main()
{
volatile int a;
volatile char b;
switch(a)
       {
       case 1: b= 'R';
               break;
             
       case 2: b= 'A';
               break;

       case 3: b= 'M';
               break;
             
       default: b='Y';
             
       }
}
Equivalent Assembly Code:

        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        PUSH     {r3,lr}
       
        LDR      r0,[sp,#0]       ; r0 <-- a
       
        CMP      r0,#1            ; compare r0 and 1
        MOVEQ    r0,#0x52         ; r0 <--'R' if (r0 = 1 ie a = 1)
        BEQ      |L0.44|          ; Jump to |L0.44|
       
        CMP      r0,#2            ; compare r0 and 2
        MOVEQ    r0,#0x41         ; r0 <--'A' if (r0 = 2 ie a = 2)
        BEQ      |L0.44|          ; Jump to |L0.44|
       
        CMP      r0,#3            ; compare r0 and 3
        MOVNE    r0,#0x59         ; default case r0 <-- 'Y'
        MOVEQ    r0,#0x4d         ; r0 <--'M' if (r0 = 3 ie a = 3)
|L0.44|
        STRB     r0,[sp,#0]       ; r0 --> b
        POP      {r3,pc}
        ENDP

ASCII values R-0x52 , A - 0x41 , M -0x4d ,Y-0x49 
You can see from the examples that some variables go out of scope and memory is de-allocated even when the function doesn't go out scope.

In example 2 , variable x loses its scope and gets de-allocated as soon as it is loaded to r0 register.The location is used by f later.
In example 3, variable a loses its scope and gets de-allocated as soon as it is loaded to r0 register. The location is used by b later.

The ARM compiler optimizes the code to a great extent to minimize memory usage.
ARM is based on load-store architecture unlike Intel x86 and hence when any operation needs to be performed ,
                >Operands are loaded into the registers
                >Operations are performed and stored in registers
                >From registers the result is stored in the memory
Big calculations involving numerous operations are performed in this way.ARM compiler effectively uses only 16 registers out of which 3 registers are reserved for Stack pointer,Link register and Program Counter. 


ARM instruction set is covered elaborately in this PPT



No comments:

Post a Comment