2

I'm new to assembly programing and I'm programing for ARM. I'm making a program with two subroutines: one that appends a byte info on a byte vector in memory, and one that prints this vector. The first address of the vector contains the number of elements that follows, up to 255. As I debug it with GDB, I can see that the "appendbyte" subroutine works fine. But when it comes to the "printvector" one, there are some problems. First, the element loaded in register r1 is wrong (it loads 0, when it should be 7). Then, when I read the registers values with GDB after I use the "printf" function, a lot of register get other values that weren't supposed to change, since I didn't modify them, I just used "printf". Why is "printf" modyfing the values.

I was thinking something about the align. I'm not sure if i'm using the directive correctly.

Here is the full code:

    .text
    .global main    
    .equ    num, 255    @ Max number of elements

main:
    push    {lr}

    mov r8, #7
    bl appendbyte
    mov r8, #5
    bl appendbyte
    mov r8, #8
    bl appendbyte
    bl imprime

    pop {pc}

.text
.align  

printvector:
    push {lr}

    ldr r3, =vet @ stores the address of the start of the vector in r3
    ldr r2, [r3], #1 @ stores the number of elements in r2

.align  
loop:
    cmp r2, #0 @if there isn't elements to print
    beq fimimprime @quit subroutine
    ldr r0, =node   @r0 receives the print format
    ldr r1, [r3], #1 @stores in r1 the value of the element pointed by r3. Increments r3 after that.
    sub r2, r2, #1 @decrements r2 (number of elements left to print)
    bl printf @call printf
    b loop @continue on the loop

.align  
endprint:
    pop {pc}

.align  
appendbyte:
    push {lr}

    ldr r0, =vet    @stores in r0 the beggining address of the vector
    ldr r1, [r0], #1    @stores in r1 the number of elements and makes r0 point to the next address
    add r3, r0, r1  @stores in r3 the address of the first available position
    str r8, [r3]    @put the value at the first available position
    ldr r0, =vet    @stores in r0 the beggining address of the vector
    add r1, r1, #1  @ increment the number of elements in the vector
    str r1, [r0]    @ stores it in the vector

    pop {pc}

.data           @ Read/write data follows
.align          @ Make sure data is aligned on 32-bit boundaries
vet:    .byte 0
    .skip   num     @ Reserve num bytes

.align
node:   .asciz "[%d]\n"

.end

The problems are in

    ldr r1, [r3], #1

and

    bl printf

I hope I was clear on the problem. Thanks in advance!

Gustavo Amgarten
  • 396
  • 4
  • 20

2 Answers2

3

The ARM ABI specifies that registers r0-r3 and r12 are to be considered volatile on function calls. Meaning that the callee does not have to restore their value. LR also changes if you use bl, because LR will then contain the return address for the called function.

More information can be found on ARMs Information Center entry for the ABI or in the APCS (ARM Procedure Call Standard) document.

Nico Erfurth
  • 3,362
  • 22
  • 26
  • Thank you, I read about how function calls can edit r0-r3 and using r4 and r5 as variables registers seems to work, though I'm still having problem with only loading zero values from the andresses of the vector. Thanks! – Gustavo Amgarten Oct 14 '13 at 14:41
0
printvector:
    push {lr}

    ldr r3, =vet @ stores the address of the start of the vector in r3
    ldr r2, [r3], #1 @ stores the number of elements in r2

.align  
loop:
    cmp r2, #0 @if there isn't elements to print
    beq fimimprime @quit subroutine
    ldr r0, =node   @r0 receives the print format
    ldr r1, [r3], #1 @stores in r1 the value of the element pointed by r3. Increments r3 after that.
    sub r2, r2, #1 @decrements r2 (number of elements left to print)
    bl printf @call printf
    b loop @continue on the loop

.align  
endprint:
    pop {pc}

that is definitely not how you use align. Align is there to...align the thing that follows on some boundary (specified in an optional argument, note this is an assembler directive, not an instruction) by padding the binary with zeros or whatever the padding is. So you dont want a .align in the code flow, between instructions. You have done that between the ldr r1, and the cmp r2 after loop. Now the align after b loop is not harmful as the branch is unconditional but at the same time not necessary as there is no reason to align there the assembler is generating an instruction flow so the bytes cant be unaligned. Where you would use .align is after some data declaration before instructions:

.byte 1,2,3,4,5,
.align
some_code_branch_dest:

In particular one where the assembler complains or the code crashes.

old_timer
  • 69,149
  • 8
  • 89
  • 168