【发布时间】:2021-07-29 18:09:23
【问题描述】:
所以我的程序有问题。它应该读入文本文件 每行都有一个数字。然后它将它存储在一个数组中,使用选择排序对其进行排序,然后将其输出到一个新文件。文件的读取和写入工作正常,但我的排序代码无法正常工作。当我运行程序时,它似乎只存储了一些数字 在数组中,然后是一堆零。
所以如果我的输入是 112323, 32, 12, 19, 2, 1, 23。输出是 0,0,0,0,2,1,23。我很确定问题出在我如何从数组中存储和加载 到寄存器上,因为假设这部分工作,我找不到选择排序算法不工作的任何原因。
好的,感谢您的帮助,我发现我需要更改加载和存储指令,使其与使用的说明符匹配(ldr -> ldrb 和 str -> strb)。但是我需要创建一个适用于 32 位数字的排序算法,那么说明符和加载/存储指令的哪种组合可以让我这样做?还是我必须一次加载/存储 8 位?如果是这样,我该怎么做?
.data
.balign 4
readfile: .asciz "myfile.txt"
.balign 4
readmode: .asciz "r"
.balign 4
writefile: .asciz "output.txt"
.balign 4
writemode: .asciz "w"
.balign 4
return: .word 0
.balign 4
scanformat: .asciz "%d"
.balign 4
printformat: .asciz "%d\n"
.balign 4
a: .space 32
.text
.global main
.global fopen
.global fprintf
.global fclose
.global fscanf
.global printf
main:
ldr r1, =return
str lr, [r1]
ldr r0, =readfile
ldr r1, =readmode
bl fopen
mov r4, r0
mov r5, #0
ldr r6, =a
loop:
cmp r5, #7
beq sort
mov r0, r4
ldr r1, =scanformat
mov r2, r6
bl fscanf
add r5, r5, #1
add r6, r6, #1
b loop
sort:
mov r5,#0 /*array parser for first loop*/
mov r6, #0 /* #stores index of minimum*/
mov r7, #0 /* #temp*/
mov r8, #0 /*# array parser for second loop*/
mov r9, #7 /*# stores length of array*/
ldr r10, =a /*# the array*/
mov r11, #0 /*#used to obtain offset for min*/
mov r12, #0 /*# used to obtain offset for second parser access*/
loop3:
cmp r5, r9 /*# check if first parser reached end of array*/
beq write /* #if it did array is sorted write it to file*/
mov r6, r5 /*#set the min index to the current position*/
mov r8, r6 /*#set the second parser to where first parser is at*/
b loop4 /*#start looking for min in this subarray*/
loop4:
cmp r8, r9 /* #if reached end of list min is found*/
beq increment /* #get out of this loop and increment 1st parser**/
lsl r7, r6, #3 /*multiplies min index by 8 */
ADD r7, r10, r7 /* adds offset to r10 address storing it in r7 */
ldr r11, [r7] /* loads value of min in r11 */
lsl r7, r8, #3 /* multiplies second parse index by 8 */
ADD r7, r10, r7 /* adds offset to r10 address storing in r7 */
ldr r12, [r7] /* loads value of second parse into r12 */
cmp r11, r12 /* #compare current min to the current position of 2nd parser !!!!!*/
movgt r6, r8 /*# set new min to current position of second parser */
add r8, r8, #1 /*increment second parser*/
b loop4 /*repeat */
increment:
lsl r11, r5, #3 /* multiplies first parse index by 8 */
ADD r11, r10, r11 /* adds offset to r10 address stored in r11*/
ldr r8, [r11] /* loads value in memory address in r11 to r8*/
lsl r12, r6, #3 /*multiplies min index by 8 */
ADD r12, r10, r12 /*ads offset to r10 address stored in r12 */
ldr r7, [r12] /* loads value in memory address in r12 to r7 */
str r8, [r12] /* # stores value of first parser where min was !!!!!*/
str r7, [r11] /*# store value of min where first parser was !!!!!*/
add r5, r5, #1 /*#increment the first parser*/
ldr r0,=printformat
mov r1, r7
bl printf
b loop3 /*#go to loop1*/
write:
mov r0, r4
bl fclose
ldr r0, =writefile
ldr r1, =writemode
bl fopen
mov r4, r0
mov r5, #0
ldr r6, =a
loop2:
cmp r5, #7
beq end
mov r0, r4
ldr r1, =printformat
ldrb r2, [r6]
bl fprintf
add r5, r5, #1
add r6, r6, #1
b loop2
end:
mov r0, r4
bl fclose
ldr r0, =a
ldr r0, [r0]
ldr lr, =return
ldr lr, [lr]
bx lr
【问题讨论】:
-
您是否尝试过在调试器中单步执行您的代码?此外,ARM 具有像
[r10, r6, lsl #3]这样的寻址模式,这对于索引 64 位元素的数组很有用。一个字只有 4 个字节,lsl #2。 (godbolt.org/z/xEraef8jY 是一个使用它来验证语法的 C 编译器示例)。但无论如何,这应该比使用lsl和add指令手动执行地址数学更容易。 -
在循环中调用
printf很奇怪,通常你只需要使用调试器,但我认为这很好。您的代码似乎不依赖任何 r0..r3 或 r12 在调用中幸存,并且根据en.wikipedia.org/wiki/Calling_convention#ARM_(A32),所有 r4..r11 都是调用保留的。 -
谢谢!我解决了这个问题。我需要使用 ldrb 和 strb 来正确读取整数。但是我必须读取 32 位整数,所以我想知道我必须做什么才能做到这一点。我只需要更改说明符以及加载和存储指令吗?
标签: sorting assembly arm selection-sort