Absiel
Absiel

Reputation: 35

ARM Assembly Arrays

I am trying to figure out how arrays work in ARM assembly, but I am just overwhelmed. I want to initialize an array of size 20 to 0, 1, 2 and so on.

A[0] = 0
A[1] = 1

I can't even figure out how to print what I have to see if I did it correctly. This is what I have so far:

.data
.balign 4       @ Memory location divisible by 4
        string: .asciz "a[%d] = %d\n"
        a:      .skip   80      @ allocates 20
.text
.global main
.extern printf

main:
        push    {ip, lr}        @ return address + dummy register
        ldr     r1, =a          @ set r1 to index point of array
        mov     r2, #0          @ index r2 = 0
loop:
        cmp     r2, #20         @ 20 elements?
        beq     end             @ Leave loop if 20 elements
        add     r3, r1, r2, LSL #2      @ r3 = r1 + (r2*4)
        str     r2, [r3]        @ r3 = r2
        add     r2, r2, #1      @ r2 = r2 + 1
        b       loop            @ branch to next loop iteration
print:
        push    {lr}            @ store return address
        ldr     r0, =string     @ format
        bl      printf          @ c printf
        pop     {pc}            @ return address

ARM confuses me enough as it is, I don't know what i'm doing wrong. If anyone could help me better understand how this works that would be much appreciated.

Upvotes: 3

Views: 37431

Answers (2)

Abhishek D K
Abhishek D K

Reputation: 2427

This might help down the line for others who want to know about how to allocate memory for array in arm assembly language here is a simple example to add corresponding array elements and store in the third array.

.global  _start

_start:
      MOV R0, #5              
      LDR R1,=first_array     @ loading the address of first_array[0]
      LDR R2,=second_array    @ loading the address of second_array[0]
      LDR R7,=final_array     @ loading the address of final_array[0]
      MOV R3,#5               @ len of array
      MOV R4,#0               @ to store sum
check: 
      cmp R3,#1               @ like condition in for loop for i>1
      BNE loop                @ if R3 is not equal to 1 jump to the loop label
      B _exit                 @ else exit
loop:
      LDR R5,[R1],#4          @ loading the values and storing in registers and base register gets updated automatically R1 = R1 + 4 
      LDR R6,[R2],#4          @ similarly
      add R4,R5,R6         
      STR R4,[R7],#4          @ storing the values back to the final array 
      SUB R3,R3,#1            @ decrment value just like i-- in for loop
      B check
_exit:
      LDR R7,=final_array     @ before exiting checking the values stored 
      LDR R1, [R7]            @ R1 = 60 
      LDR R2, [R7,#4]         @ R2 = 80
      LDR R3, [R7,#8]         @ R3 = 100
      LDR R4, [R7,#12]        @ R4 = 120
      MOV R7, #1              @ terminate syscall, 1
      SWI 0                   @ execute syscall

.data
first_array:  .word 10,20,30,40  
second_array: .word 50,60,70,80 
final_array:  .word 0,0,0,0,0

Upvotes: 5

old_timer
old_timer

Reputation: 71526

as mentioned your printf has problems, you can use the toolchain itself to see what the calling convention is, and then conform to that.

#include <stdio.h>
unsigned int a,b;
void notmain ( void )
{
  printf("a[%d] = %d\n",a,b);
}

giving

00001008 <notmain>:
    1008:   e59f2010    ldr r2, [pc, #16]   ; 1020 <notmain+0x18>
    100c:   e59f3010    ldr r3, [pc, #16]   ; 1024 <notmain+0x1c>
    1010:   e5921000    ldr r1, [r2]
    1014:   e59f000c    ldr r0, [pc, #12]   ; 1028 <notmain+0x20>
    1018:   e5932000    ldr r2, [r3]
    101c:   eafffff8    b   1004 <printf>
    1020:   0000903c    andeq   r9, r0, ip, lsr r0
    1024:   00009038    andeq   r9, r0, r8, lsr r0
    1028:   0000102c    andeq   r1, r0, ip, lsr #32

Disassembly of section .rodata:

0000102c <.rodata>:
    102c:   64255b61    strtvs  r5, [r5], #-2913    ; 0xb61
    1030:   203d205d    eorscs  r2, sp, sp, asr r0
    1034:   000a6425    andeq   r6, sl, r5, lsr #8

Disassembly of section .bss:

00009038 <b>:
    9038:   00000000    andeq   r0, r0, r0

0000903c <a>:
    903c:   

the calling convention is generally first parameter in r0, second in r1, third in r2 up to r3 then use the stack. There are many exceptions to this, but we can see here that the compiler which normally works fine with a printf call, wants the address of the format string in r0. the value of a then the value of b in r1 and r2 respectively.

Your printf has the string in r0, but a printf call with that format string needs three parameters.

The code above used a tail optimization and branch to printf rather than called it and returned from. The arm convention these days prefers the stack to be aligned on 64 bit boundaries, so you can put some register, you dont necessarily care to preserve on the push/pop in order to keep that alignment

push {r3,lr}
...
pop {r3,pc}

It certainly wont hurt you to do this, it may or may not hurt to not do it depending on what downstream assumes.

Your setup and loop should function just fine assuming that r1 (label a) is a word aligned address. Which it may or may not be if you mess with your string, should put a first then the string or put another alignment statement before a to insure the array is aligned. There are instruction set features that can simply the code, but it appears functional as is.

Upvotes: 0

Related Questions