Home > database >  Converting my C Program to ARM Assembly
Converting my C Program to ARM Assembly

Time:03-28

I have been assigned to convert this program to arm assembly v8.

int power(int x, int y){
    if (x == 0){
        return 0;
    }
    else if (y < 0){
        return 0;
    }
    else if (y == 0){
        return 1;
        
    }
    else {
        return x * power(x, y - 1);
    }
}

Although I'm not very familiar with ARM assembly language and would like to know where to start.

I have attempted to research a bit on this but ultimately found very little on the internet about ARM.

CodePudding user response:

The magic command is arm-linux-gnueabi-gcc -S -O2 -march=armv8-a power.c.

  • I used arm-linux-gnueabi-gcc since I work on an X86-64 machine and gcc does not have ARM targets available. If you are on an arm system, you should be able to use regular gcc instead. If not it will error, but no harm done.
  • -S tells gcc to output assembly.
  • The -O2 is optional and just helps to optimize the code slightly and reduce debug clutter from the result.
  • -march=armv8-a tells it to use the ARM v8 target while compiling. I chose armv8-a somewhat arbitrarily. According to the docs all of the ARM v8 are armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv8.6-a, armv8-m.base, armv8-m.main, and armv8.1-m.main. I have no idea what the differences are so you may want to choose a different one.
  • power.c just tells it which file to compile. Since we don't specify an output file (Ex: -o output.asm), the assembly will be outputted to power.s.

If you are not compiling on an arm machine that has provides the desired target with regular gcc, you can use arm-linux-gnueabi-gcc instead. If you do not have it installed, you can install it with:

sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi

Output

If anyone is curious, this is the output I received when I tried it on my machine.

        .arch armv8-a
        .eabi_attribute 20, 1
        .eabi_attribute 21, 1
        .eabi_attribute 23, 3
        .eabi_attribute 24, 1
        .eabi_attribute 25, 1
        .eabi_attribute 26, 2
        .eabi_attribute 30, 2
        .eabi_attribute 34, 1
        .eabi_attribute 18, 4
        .file   "testing.c"
        .text
        .align  2
        .global power
        .syntax unified
        .arm
        .fpu softvfp
        .type   power, %function
power:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        clz     r2, r0
        mov     r3, r0
        lsr     r2, r2, #5
        orrs    r2, r2, r1, lsr #31
        bne     .L4
        cmp     r1, #0
        mov     r0, #1
        bxeq    lr
.L3:
        subs    r1, r1, #1
        mul     r0, r3, r0
        bne     .L3
        bx      lr
.L4:
        mov     r0, #0
        bx      lr
        .size   power, .-power
        .ident  "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
        .section        .note.GNU-stack,"",%progbits

How can I get started.

Here is my thought process for how I was able to solve this problem. Looking at the problem I could tell it would probably be in two parts:

  1. How can that code be compiled to assembly?

    For the first part I found this answer which provided the command gcc -S -fverbose-asm -O2 foo.c. After testing it, I decided to remove the -fverbose-asm since only seemed to provide clutter for a program this small.

  2. How can I set the compiler target to ARM v8?

    After a quick google search I found that gcc lets you specify the target architecture with -march=xxx. My next step was to find a list of ARM architectures that I could select from. After finding gcc.gnu.org/onlinedocs/gcc/ARM-Options.html, I selected armv8-a since it sounded the most correct. When I tried it out, gcc told me that the target architecture could not be found. This was not really a surprise since I am on x86-64 and usually compilers come with the compatible targets to reduce the space required. I knew this likely meant I would need to identify the apt package which provided the arm targets so I searched around until I found this answer which filled in the rest of the information I needed.

CodePudding user response:

Compiler explorer is the friend in a such simple cases.

ARMv8-a Clang Assembly with the compiler option -O1 for keeping the recursion:

# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):                             // @power(int, int)
        stp     x29, x30, [sp, #-32]!           // 16-byte Folded Spill
        str     x19, [sp, #16]                  // 8-byte Folded Spill
        mov     x29, sp
        mov     w19, w0
        mov     w0, wzr
        cbz     w19, .LBB0_5
        tbnz    w1, #31, .LBB0_5
        cbz     w1, .LBB0_4
        sub     w1, w1, #1
        mov     w0, w19
        bl      power(int, int)
        mul     w0, w0, w19
        b       .LBB0_5
.LBB0_4:
        mov     w0, #1
.LBB0_5:
        ldr     x19, [sp, #16]                  // 8-byte Folded Reload
        ldp     x29, x30, [sp], #32             // 16-byte Folded Reload
        ret

ARM GCC (linux) Assembly with the compiler option -O1 for keeping the recursion:

# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
        push    {r4, lr}
        mov     r4, r0
        clz     r0, r0
        lsrs    r0, r0, #5
        orrs    r3, r0, r1, lsr #31
        it      ne
        movne   r0, #0
        beq     .L6
.L1:
        pop     {r4, pc}
.L6:
        movs    r0, #1
        cmp     r1, #0
        beq     .L1
        subs    r1, r1, #1
        mov     r0, r4
        bl      power(int, int)
        mul     r0, r4, r0
        b       .L1

ARM GCC (none) Assembly with the compiler option -O1 for keeping the recursion:

# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
        push    {r4, lr}
        mov     r4, r0
        rsbs    r0, r0, #1
        movcc   r0, #0
        orrs    r3, r0, r1, lsr #31
        movne   r0, #0
        beq     .L6
.L1:
        pop     {r4, lr}
        bx      lr
.L6:
        cmp     r1, #0
        moveq   r0, #1
        beq     .L1
        sub     r1, r1, #1
        mov     r0, r4
        bl      power(int, int)
        mul     r0, r4, r0
        b       .L1

ARM64 GCC Assembly with the compiler option -O1 for keeping the recursion:

# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
        cmp     w1, 0
        ccmp    w0, 0, 4, ge
        bne     .L9
        mov     w0, 0
        ret
.L9:
        stp     x29, x30, [sp, -32]!
        mov     x29, sp
        str     x19, [sp, 16]
        mov     w19, w0
        mov     w0, 1
        cbnz    w1, .L10
.L1:
        ldr     x19, [sp, 16]
        ldp     x29, x30, [sp], 32
        ret
.L10:
        sub     w1, w1, #1
        mov     w0, w19
        bl      power(int, int)
        mul     w0, w19, w0
        b       .L1
  • Related