我的程序使用.skip 1000
在内存中创建一个二维数组。然后,使用以下循环,使用stdin
的输入填充该数组:
@@loop to store message in array
@outer for loop over rows
MOV r0,#0 @r0 = i (row index)
msgrowloop:
CMP r0,r2 @compare to nrows
BEQ msgendrowloop
@multiply/accumulate instruction
MLA r7, r3, r0, r6 @calculates the address of the first element in each row
@inner for loop over columns
MOV r1,#0 @r1 = j (column index)
msgcolumnloop:
CMP r1,r3 @compare to ncolumns
BEQ msgendcolumnloop
@@@store from stdin
PUSH {r0-r4}
BL getchar @branch & link to getchar - reads single character from stdin
CMP r0,#-1 @check if we're at the end of file
BEQ msgendrowloop @if so, exit loop
MOV r8, r0 @move character to r8
POP {r0-r4}
@@@store from stdin end
@store r8 in memory and increase r7 by one byte
STRB r8,[r7],#1
ADD r1,r1,#1 @j += 1
B msgcolumnloop
msgendcolumnloop:
ADD r0,r0,#1 @i += 1
B msgrowloop
msgendrowloop:
@rest of the program...
现在,使用此命令我会遇到分段错误,但是如果我将stdin函数更改为此:
PUSH {r0-r4}
BL getchar @branch & link to getchar - reads single character from stdin
CMP r0, #-1 @check if we are at end of file
MOV r8, r0 @move character to r8
POP {r0-r4}
BEQ msgendrowloop @exit loop when done
代替此:
PUSH {r0-r4}
BL getchar @branch & link to getchar - reads single character from stdin
CMP r0,#-1 @check if we're at the end of file
BEQ msgendrowloop @if so, exit loop
MOV r8, r0 @move character to r8
POP {r0-r4}
它完美地工作。这里的逻辑令人困惑,因为我的原始代码在逻辑上是合理的。
答案 0 :(得分:0)
将以上评论形式化为答案:
您所看到的行为的基本原因是stdin
函数的第二种形式没有保留堆栈指针(它对堆栈的使用不是“平衡的”)。 PUSH {r0-r4}
通过POP {r0-r4}
进行平衡,该BEQ
将堆栈指针恢复为其在输入该块时所具有的值,但是如果采用POP
分支,则POP {r4-r6,pc}
被跳过,堆栈操作不再平衡。这意味着当另一段代码从堆栈中弹出数据时,如果期望找到更早放入该堆栈的内容,则会弹出错误的值。很有可能是弹出消息,其中涉及程序计数器作为函数返回,并且弹出了一个无意义的地址,因此出现了段错误。
使用调试器来尝试发现这种错误的根本原因是发展技能的好主意。假设我对段错误的原因是正确的,在这种情况下,基本过程将是
r13
pc
中获取堆栈指针并查看内存中的堆栈,来确定正在弹出的PUSH {r4-r6,lr}
中的值是无效的分支地址POP
的{{1}},并确定首先要推送适当的地址PUSH
的末尾与平衡POP
的开始之间已经改变了值(如果所有中间堆栈操作均已正确平衡,则不应这样做) 此外,请注意procedure call standard in the ARM ABI。简而言之:
r0-r3
用于函数自变量和返回值; r0-r3
和r12
是“调用密集型”的,您不能依赖它们在函数调用之间保留它们的值,因此,除非有必要,否则最好不要将它们用于中间存储到; r4-r11
和lr
(r14
)是“调用保留”的,因此您编写的任何函数都必须保留这些(但不必保留r0-r3
或{{1} }); r12
的调用当前使用未对齐的堆栈进行操作。