MikeySg
MikeySg

Reputation: 19

Translating from C to ARM Assembly--keep getting segmentation fault, confusion with ldr and str?

I'm new to ARM assembly and am trying to translate some easy code snippets from C to assembly. I'm not sure if I am using ldr and str correctly (although I feel like ive tried everything) and I keep getting seg fault when I try to run it.

The C code is

int main() {
    int x = 10;
    int y = 5;
    int z = 20;

    int min = y;

    if (x < min) {min = x;}
    if (z < min) {min = z;}

    return min;
}

My assembly code:

.global main
.text

main:
    push {ip, lr}

    mov r0, #10
    mov r1, #5
    mov r2, #20

    str r3, [r1]

    cmp r0, r3
    bge done
    str r0, [r3]

    cmp r2, r3
    bge done
    str r2, [r3]

done:
    ldr r0, [r3]
    pop {ip, pc}

Upvotes: 1

Views: 276

Answers (3)

artless-noise-bye-due2AI
artless-noise-bye-due2AI

Reputation: 22420

The C code is

int main() {
    int x = 10;
    int y = 5;
    int z = 20;

    int min = y;

    if (x < min) {min = x;}
    if (z < min) {min = z;}

    return min;
}

Don't use ldr and str as these store a registers value to memory. For example str rX, [rY] means to use the value of 'rY' as a memory address to store the value of 'rX'. There is no need to use memory when you have many available registers. For example,

mov   r0, #5    ; min = y = #5
mov   r1, #10   ; x = 10
mov   r2, #20   ; z = 20
cmp   r1, r0    ; if (x < min)
movlt r0, r1    ;  min = x
cmp   r2, r0    ; if (z < min)
movlt r0, r2    ;  min = z
mov   pc, lr    ; return min (is r0)

is close if not complete. Please review my register use as some maybe transposed. As well you might consider if you need signed or unsigned. Your original used bge done which will not work if 'x > y > z'. You need to use 'less than' as per the 'C' code.

I would suggest not using a compiler to start with for very simple code like this. If you have many variables, then start with a compiler. After you attempt something, see what the compiler does. You may have a better structural idea than the compiler in some cases; probably not for a numerical problem like this. If you go to the compiler right away it will be more difficult to think of alternate attacks on coding the function. Often ideas from both your original attempt and the compiler will combine for something quite nice.

Upvotes: 1

cooperised
cooperised

Reputation: 2599

TonyK's answer covers the source of your mistakes pretty well. It strikes me that it might benefit you to see how a compiler would deal with the compilation of a simple program like this; seeing the compiler allocate space on the stack for these variables, and seeing how it uses LDR and STR correctly, could well help you to learn.

If you're using gcc, try adding -S -O1 to the compiler options to enable mild optimisation (-O1) and to request assembly language as the output (-S). The output will interleave the original C code into the generated assembly language, which will hopefully make it easier to understand.

Upvotes: 0

TonyK
TonyK

Reputation: 17114

OK, for each of your variables, you have to decide where you are going to store it:

  • you can store it in a register, which is OK as long as you have enough spare registers;
  • you can store it at a fixed address, which is fine for global and static variables but no good for local variables;
  • you can store it on the stack, which is where local variables are generally stored if there aren't enough registers to go round. This is more work, as you have to load it and store it every time you want to access it.

Your function is mixing these up disastrously. You store x,y,z, in registers r0,r1,r2, but then you treat y as if it was stored at the address 5, whereas it is in fact stored in the register r1. You don't want to use the memory access instruction str r3, [r1] here, because nothing is in memory; just mov r3,r1 is enough.

The rest of the code is similarly dysfunctional, but I won't go into details. Your function is simple enough that you have more than enough registers to go round, so I suggest you re-write it to use registers for all variables. No ldr/str instructions at all, just mov instructions.

And look at the assembly code generated by your C compiler to get a feel for more complicated situations where some or all variables have to be stored on the stack.

Good luck!

Upvotes: 1

Related Questions