Invalid pointer error in insert sort in ARM assembly

I am trying to translate a simple insert-to-assembly sorting algorithm, but something about this particular configuration is throwing a program error invalid pointer

.

Here's the C version I'm using:

int n, array[100], c, d, t;
for (c = 1; c < n - 1; c++) {
    d = c;
    while (d > 0 && array[d] < array[d - 1]) {
        t = array[d];
        array[d] = array[d - 1];
        array[d - 1] = t;
        d--;
    }
}

      

This is the C structure that is used:

typedef struct { 
    int *list;
    int size;
    int maxSize;
} list; 

      

Here is my build file:

.syntax unified

.text

.align 8
.global insert_ARM
.func insert_ARM, insert_ARM
.type insert_ARM, %function

insert_ARM:
    push {r4-r11, ip, lr}

@ setup
    ldr r4, [r0, #4]
    sub r4, r4, 1    @ r4 = n-1
    mov r5, #1       @ c=1
    mov r6, #16      @ d=0, which starts at #16
    mov r7, #0       @ t=0

for:

   @ d = c ; needs these lines to do the assembly equivalent, which is * 4.
    mov r6, r5      @ d = c
    LSL r6, #2      @ uses logical shift left: multiplies r6 by 4 to get the correct index
    add r6, r6, 16  @ add 16 because that where the array starts

while:

    @ condition 1: d > 0
    cmp r6, #0      @ if d <= 0, get out of there
    ble forLoopStatements

    @ condition 2: array[d] < array[d-1]
    @ first, I need to define array[d] and array[d-1]
    @ r8 = array[d] and r9 = array[d-1]
    sub r10, r6, #4 @ r10 = d-1
    ldr r9, [r0, r10]   @ r9 = array[d-1]
    ldr r8, [r0, r6]    @ r8 = array[d]
    cmp r9, r8      @ comparing array[d-1] with array[d]
    bge forLoopStatements   @ if array[d] >= array[d-1], get out of there

    @ while effects
    @ note that r8 should still be array[d] here.
    str r9, [r0, r6]    @ array[d] = array[d-1]
    str r8, [r0, r10]   @ array[d-1] = t @ BUG HERE.

    sub r6, r6, #4  @ d--; // does -4 for ARM
    bal while       @ repeat loop


forLoopStatements:
    @ (c<n-1; c++)
    add r5, r5, #1  @ c++
    cmp r5, r4      @ compares c with n-1
    blt for     @ if c < n-1, loop again


end:
    mov r0, r10

    pop {r4-r11, ip, lr}

    BX lr
.endfunc

.end

      

It seems that

str r8, [r0, r10]   @ array[d-1] = t

      

which triggers a trip at some point.

Edit: I found that the r8 numbers during this command are incorrect, since immediately using something like

mov r8, #4

      

before the store will prevent the error (but of course makes the results incorrect).

When checking the contents of r0, it happens that the update is out of range because other members of the structure are changed in the process. Array index 0 is +16.

+3


source to share


3 answers


You found a problem in translation to assembly. Note, however, the following issues:



  • The outer loop should run before c < n

    instead c < n - 1

    . As coded, the last element of the array is never moved.

  • it would be more readable to use 2 nested loops for

    :

    int n, array[100], c, d, t;
    for (c = 1; c < n; c++) {
        for (d = c; d > 0 && array[d] < array[d - 1]; d--) {
            t = array[d];
            array[d] = array[d - 1];
            array[d - 1] = t;
        }
    }
    
          

+1


source


Everyone has a different approach to coding. Mine is different from yours, but I would like to share my ideas. I would start with as simple work as possible in order to work something and build from there. Here is some sample code for forloop.

/* forloop.s */

/* int n, array[100], c, d, t;
   for (c=1; c<n-1; c++)
   address of array = r0 = .word ( Raspbian Jessie = 32 bits )
   n = r4 = array size
   c = r5 = 1word = 4memory_bytes = index into array
   d = r6 = c = address in array
   array[d] = r10 = data
*/

.data

.balign 4
array:
    .word 6, 3, 7, 8, 5, 2, 1, 9, 4
size:
    .word (size - array)

.text

.global main

main:
    push  {r4-r12, lr}        @ save registers for OS
    ldr   r0, =array          @ load address of array in r0
    ldr   r4, =size           @ load address of size in r4
    ldr   r4, [r4]            @ load size in r4
    sub   r4, #4              @ substract 1 word from r4 (n=n-1)
    mov   r5, #4              @ move 4 in r5 (c=1word=4memory_bytes)

for:                          @ (c=1; c<n-1; c++)

    add   r6, r0, r5          @ d (r6) = array address (r0) + (c=4)
@ while:                      @ while loop would go here
    ldr   r10, [r6], #-4      @ r10 = array[d], d=d-4
    ldr   r11, [r6]           @ r11 = array[d-1]
    @...  @ while code
    cmp   r0,  r6             @ is d > 0 ...
    @...  @continue while loop code

    @ back to forloop code
    cmp   r5, r4              @ compare (subtract) r5 (c) from r4 (n)
    add   r5, #4              @ add 1 word to r5 (c++)
    blt   for                 @ end of for loop (c<n-1)

end:
    mov   r0, #0              @ set exit code
    pop   {r4-r12, lr}        @ restore enviroment for return to OS
    bx    lr                  @ return to OS

      

Build and wire the code and run it and check the completion status.

as -o forloop.o forloop.s
gcc -o forloop forloop.o
./forloop; echo $?

      

This works for me on Raspberry Pi. I don't know much about gdb

, but it might help, as Jetter suggested. (See the Commands section of http://cs107e.github.io/guides/gdb/ for more details .)



pi@RPi0:~/pgm/Asm $ gdb -tui forloop  # Text User Interface
---Type <return> to continue, or q <return> to quit--- [Enter]
(gdb) layout asm
(gdb) start        @ start is required
(gdb) layout reg
(gdb) Ctl-x o      @ Selects registers as Up & Down arrow to see all
(gdb) si           @ single step
(gdb) [Enter]      @ repeat single step
(gdb) run          @ run program to end
(gdb) q            @ quit gdb

      

Move the down arrow to see the case cpsr

. The number on the left is the flags 8=Negative, 6=Zero&Carry, 4=Zero, 2=Carry, 1=oVerflow

.

Another approach to debugging a build program on hand is to use the linux printf command. Here's myprint.s.

/* myprint.s */

.data

.balign 4
format:
    .asciz " %2d  %2d  %2d  %2d  %2d  %2d  %2d  %2d  %2d\n"

.balign 4
array:
    .word 6, 3, 7, 8, 5, 2, 1, 9, 4
size:
    .word (size - array)

.text

.global main

print:    @ --- a printf function to print the value in the array ---
    push  {r0-r12, lr}        @ save registers for OS
    mrs   r10,  cpsr          @ save flag settings
    ldr   r11,  =array        @ To print the array[0-8], the array
    ldm   r11,  {r1-r9}       @  address is loaded in r11 and stored
    push  {r4-r10}            @  in reg r1-r9, printf gets args# from
    ldr   r0,   =format       @  format, 3 print from r1-r3, rest from
    bl    printf              @  stack.
    pop   {r4-r10}            @ adjust stack, restore r10 (flags)
    msr   cpsr_f, r10         @ restore saved flags
    pop   {r0-r12, pc}        @ restore reg and return

main:
    push  {r4-r12, lr}        @ save registers for OS
    bl    print               @ --- can be placed anywhere in code ---
    ldr   r0, =array          @ load address of array in r0
    ldr   r4, =size           @ load address of size in r4
    ldr   r4, [r4]            @ load size in r4
    sub   r4, #4              @ substract 1word from r4 (n=n-1)
    mov   r5, #4              @ move 4 in r5 (c=1word=4memory_bytes)

for:                          @ (c=1; c<n-1; c++)
    add   r6, r0, r5          @ d=r6 = array address (r0) + (c=4)

while:                        @ while loop would go here
    ldr   r10, [r6], #-4      @ r10 = array[d], d=d-4
    ldr   r11, [r6]           @ r11 = array[d-1]
    cmp   r10, r11            @ is array[d] < array[d-1]
    bge   forloop_code        @ if not, continue forloop code
    mov   r7,  r11            @ move array[d-1] into t (r7)
    str   r10, [r6], #4       @ store array[d] into array[d-1], (d-1)+4=d
    str   r7,  [r6], #-4      @ store t-array[d-1] into array[d], d-4=(d-1)
    cmp   r6,  r0             @ is d>0 (addr(array[d-1]) > addr(array[0]))?
    bgt   while               @ yes, check if array[d-1] < array[d-2]

forloop_code:                 @ back to forloop code
    bl    print               @ --- can be placed anywhere in code ---
    cmp   r5, r4              @ compare (subtract) r5 (c) from r4 (n)
    add   r5, #4              @ add 1 word to r5 (c++)
    blt   for                 @ end of for loop (c<n-1)

end:
    pop   {r4-r12, lr}        @ restore registers for OS
    mov   r0, #0              @ set exit code
    bx    lr                  @ return to OS


as -o myprint.o myprint.s
gcc -o myprint myprint.o
./myprint; echo $?
  6   3   7   8   5   2   1   9   4
  3   6   7   8   5   2   1   9   4
  3   6   7   8   5   2   1   9   4
  3   6   7   8   5   2   1   9   4
  3   5   6   7   8   2   1   9   4
  2   3   5   6   7   8   1   9   4
  1   2   3   5   6   7   8   9   4
  1   2   3   5   6   7   8   9   4
  1   2   3   4   5   6   7   8   9
0

      

Another thought is to put your code together C

and use gdb

to see how the C code is in assembly. These were interesting projects, I was not aware of insert sort.

+1


source


I understood that. Apart from cleaning up my code, I just needed to translate

while ( d > 0 )

      

and

cmp r6, #16      @ if d <= 0, get out of there
ble forLoopStatements

      

instead

cmp r6, #0      @ if d <= 0, get out of there
ble forLoopStatements

      

to keep the minimum index at 0.

0


source







All Articles