krb
krb

Reputation: 16345

An issue with an ARM assembly function?

I have a simple function written in ARM assembler. The first time it's ran, everything works as desired (it prints BOOT\n). However, the second time the function is executed, nothing is printed.

.globl __printTest
.text
.align 2

__printTest:
 sub sp, #64 /* yes, I know this is too much */

 mov r0, #66
 str r0, [sp]
 mov r0, #79
 str r0, [sp, #1]
 mov r0, #79
 str r0, [sp, #2]
 mov r0, #84
 str r0, [sp, #3]
 mov r0, #10
 str r0, [sp, #4]

 mov r0, #0
 mov r1, sp
 mov r2, #5

 bl _write
 add sp, #64

 bx lr

What could be the issue? I suspect that this somehow screws up the buffer that it no longer works. Write is a function that calls the write syscall on Linux using the svc instruction.

Upvotes: 0

Views: 564

Answers (2)

Nico Erfurth
Nico Erfurth

Reputation: 3453

The problem is that you're not saving lr.

     bl _write
     add sp, #64
     bx lr

bl _write will overwrite lr which then points to add sp, #64, so your bx lr will just result in an endless loop on the last two instructions.

It should work if you modify your code like this:

__printTest:
 push {lr}
 sub sp, #64 /* yes, I know this is too much */
 ....
 bl _write
 add sp, #64
 pop {pc}

As already stated in another answer, you should also use strb instead of str for byte-stores.

Upvotes: 5

Variable Length Coder
Variable Length Coder

Reputation: 8116

This function is pushing 32-bit values into unaligned stack pointer addresses. It should be using strb to write single bytes. For unaligned str, the ARM Architecture Reference Manual says:

if UnalignedSupport() || address<1:0> == ‘00’ then
    MemU[address,4] = R[t];
else // Can only occur before ARMv7
    MemU[address,4] = bits(32) UNKNOWN;

So depending on your configuration, you might be getting junk in your stack if you're hitting the UNKNOWN case.

Upvotes: 2

Related Questions