2017-07-22 2 views
3

Ich versuche, einen einfachen Einfügesortieralgorithmus in Assembly zu übersetzen, aber etwas über diese bestimmte Konfiguration verursacht das Programm einen invalid pointer Fehler zu erhalten.Ungültiger Zeiger Problem beim Einfügen sortieren in ARM-Assembly

Hier ist die C-Version, die ich verwende:

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--; 
    } 
} 

Dies ist eine C-Struktur, die verwendet wird:

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

Hier ist meine Assembly-Datei:

.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's 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 

Es scheint

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

, die an einem bestimmten Punkt eine Auslösung verursacht.

Edit: Ich fand heraus, dass r8-Zahlen in dieser Instruktion irgendwie falsch sind, sofort da etwas mit wie

mov r8, #4 

vor dem Laden, um die Fehler verhindert (aber natürlich macht die Ergebnisse falsch).

Bei der Untersuchung des Inhalts von r0 kommt es vor, dass das Update den Bereich verlässt, weil andere Mitglieder der Struktur im Prozess geändert werden. Array-Index 0 ist bei +16.

+0

Verwenden Sie einen Debugger, um den Wert von 'r0' und' r8' an diesem Punkt zu prüfen und festzustellen, was falsch ist. Dann finde heraus, wie es diesen Wert bekommen hat. Es ist unklar, was Ihre Struktur ist und wo 'r0' zeigt. Sie sagen, es enthält einen Zeiger auf ein Array, aber stattdessen hat es einen Index? – Jester

+0

typedef struct {int * list; int Größe; int maxSize; } Liste; so * Liste ist in R0. Ich versuche, es mit dem Sortieralgorithmus zu ändern. – Rez

+0

Dann fehlt die Ladung des 'listen' Mitglieds. Was ist 'sortedList_index_0' und warum hat es einen Offset von' 16'? – Jester

Antwort

1

Sie gefunden das Problem in der Übersetzung in die Montage. Beachten Sie jedoch die folgenden Probleme:

  • Die äußere Schleife sollte den ganzen Weg bis c < n statt c < n - 1 laufen. Wie codiert, wird das letzte Element des Arrays niemals verschoben.

  • wäre es besser lesbar sein 2 for Schleifen verschachtelt zu verwenden:

    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; 
        } 
    } 
    
0

Ich habe es herausgefunden. Neben meinen Code aus Reinigung, ich brauche nur

while (d > 0) 

als

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

statt

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

zu übersetzen den minimalen Index zu halten, auf 0

1

Jeder hat einen anderen Ansatz Code writting. Meine ist anders als deine, aber ich möchte meine Ideen teilen. Ich würde mit so einfach wie möglich beginnen, damit etwas von dort funktioniert. Hier ist ein Beispielcode für eine 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 

Zusammensetzen und verknüpfen Sie den Code und den Lauf und überprüfen Sie den Endstatus.

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

Es funktioniert für mich auf dem Raspberry Pi. Ich weiß nicht viel über gdb, aber das kann helfen, wie von Jester vorgeschlagen. (Siehe mittlerer Abschnitt „Befehle“ auf http://cs107e.github.io/guides/gdb/ für weitere Informationen.)

[email protected]:~/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 

den Pfeil nach unten Bewegen Sie die cpsr Register zu sehen. Die linke Zahl ist die Flagge 8=Negative, 6=Zero&Carry, 4=Zero, 2=Carry, 1=oVerflow.

Ein anderer Ansatz zum Debuggen von Assembly-Programmen auf Arm ist die Verwendung des Befehls linux printf. Hier ist meinprint.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 

Ein anderer Gedanke wäre Ihr C Code zu montieren und verwenden gdb zu sehen, wie C-Code in der Montage. Das war ein interessantes Projekt, ich wusste nichts über Einfügung.

Verwandte Themen