我正在尝试将简单的插入排序算法转换为汇编,但有关此特定配置的某些操作会导致程序出现invalid pointer
错误。
这是我正在使用的C版本:
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--;
}
}
这是一个正在使用的C结构:
typedef struct {
int *list;
int size;
int maxSize;
} list;
这是我的汇编文件:
.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
好像是
str r8, [r0, r10] @ array[d-1] = t
会在某个时刻导致旅行。
编辑:我发现在这个指令中r8的数字在某种程度上是不正确的,因为立即使用
之类的东西mov r8, #4
在商店阻止错误之前(但当然会使结果不正确)。
在检查r0的内容时,发生了更新的范围,因为结构中的其他成员正在被修改。数组索引0为+16。
答案 0 :(得分:1)
您在汇编转换中发现了问题。但请注意以下问题:
外部循环应该一直运行到c < n
而不是c < n - 1
。编码时,数组的最后一个元素永远不会被移动。
使用2个嵌套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 :(得分:1)
每个人都有不同的写代码方法。我与你的不同,但我想分享我的想法。我会从尽可能简单的开始,从那里开始工作和构建。以下是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
汇编并链接代码并运行它并检查结束状态。
as -o forloop.o forloop.s
gcc -o forloop forloop.o
./forloop; echo $?
它适用于Raspberry Pi。我不太了解gdb
,但这可能有点像Jester所建议的那样有用。 (有关详细信息,请参阅中间部分&#34;命令&#34;在http://cs107e.github.io/guides/gdb/。)
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
向下移动箭头以查看cpsr
寄存器。最左边的数字是标记8=Negative, 6=Zero&Carry, 4=Zero, 2=Carry, 1=oVerflow
。
另一种调试arm程序集程序的方法是使用linux printf命令。这是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
另一个想法是汇总你的C
代码并使用gdb
来查看汇编中的C代码。这是一个有趣的项目,我不知道插入排序。
答案 2 :(得分:0)
我明白了。除了清理我的代码,我只需要翻译
while ( d > 0 )
作为
cmp r6, #16 @ if d <= 0, get out of there
ble forLoopStatements
而不是
cmp r6, #0 @ if d <= 0, get out of there
ble forLoopStatements
将最小索引保持为0。