My program creates a 2d array in memory with .skip 1000
. It then populates that array with an input from stdin
using this loop:
@@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...
Now, using this I get a segmentation error, but if I change my stdin function to this:
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
Instead of this:
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}
It works perfectly. The logic here is confusing as my original code seems logically sound.
Formalising the comments above into an answer:
The basic reason for the behaviour you're seeing is that the second form of your stdin
function does not preserve the stack pointer (its use of the stack is not 'balanced'). The PUSH {r0-r4}
is balanced by the POP {r0-r4}
which restores the stack pointer to the value that it had on entry to the block, but if the BEQ
branch is taken then the POP
is skipped and the stack operations are no longer balanced. That means that when another bit of code pops data from the stack, expecting to find the things it pushed there earlier, it pops the wrong values. Most likely there is a pop involving the program counter as a function return, and it's popping a nonsense address, hence the segfault.
It is a good idea to develop skills with using a debugger to try and find the root cause of a bug like this for yourself. Assuming that I'm right about the cause of the segfault, the basic procedure in this case would be
POP {r4-r6,pc}
r13
and looking at the stack in memory, that the value that's being popped into pc
is an invalid branch address PUSH {r4-r6,lr}
that balances this POP
, and ascertain that an appropriate address was pushed in the first place PUSH
and the start of the balancing POP
(which it should not do if all intermediate stack operations have been properly balanced) Furthermore please do pay attention to the procedure call standard in the ARM ABI . In a nutshell:
r0-r3
are used for function arguments and return values; r0-r3
and r12
are 'call-clobbered' and you can't rely on them keeping their values across function calls, so it's a good idea not to use them for intermediate storage unless you have to; r4-r11
and lr
( r14
) are 'call-preserved' so any function you write must preserve these (but need not preserve r0-r3
or r12
); getchar
currently operates with a misaligned stack.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.