How do I use branching in a loop in ARM Assembly?
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.
assembly raspberry-pi arm
add a comment |
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.
assembly raspberry-pi arm
2
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
3
Stack operations must be balanced. Judging by the code you've shown us, ifr0 == -1
you'll skip thePOP {r0-r4}
.
– Michael
Nov 19 '18 at 13:39
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to saveR0
when callinggetchar()
? If not, you can just usepush {r1-r4}; bl getchar; pop {r1-r4};
andr0
is still the return status. Otherwise,push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.
– artless noise
Nov 19 '18 at 18:34
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53
add a comment |
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.
assembly raspberry-pi arm
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.
assembly raspberry-pi arm
assembly raspberry-pi arm
edited Nov 19 '18 at 14:34
cooperised
1,359813
1,359813
asked Nov 19 '18 at 11:15
eddiewastakeneddiewastaken
17810
17810
2
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
3
Stack operations must be balanced. Judging by the code you've shown us, ifr0 == -1
you'll skip thePOP {r0-r4}
.
– Michael
Nov 19 '18 at 13:39
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to saveR0
when callinggetchar()
? If not, you can just usepush {r1-r4}; bl getchar; pop {r1-r4};
andr0
is still the return status. Otherwise,push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.
– artless noise
Nov 19 '18 at 18:34
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53
add a comment |
2
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
3
Stack operations must be balanced. Judging by the code you've shown us, ifr0 == -1
you'll skip thePOP {r0-r4}
.
– Michael
Nov 19 '18 at 13:39
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to saveR0
when callinggetchar()
? If not, you can just usepush {r1-r4}; bl getchar; pop {r1-r4};
andr0
is still the return status. Otherwise,push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.
– artless noise
Nov 19 '18 at 18:34
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53
2
2
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
3
3
Stack operations must be balanced. Judging by the code you've shown us, if
r0 == -1
you'll skip the POP {r0-r4}
.– Michael
Nov 19 '18 at 13:39
Stack operations must be balanced. Judging by the code you've shown us, if
r0 == -1
you'll skip the POP {r0-r4}
.– Michael
Nov 19 '18 at 13:39
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to save
R0
when calling getchar()
? If not, you can just use push {r1-r4}; bl getchar; pop {r1-r4};
and r0
is still the return status. Otherwise, push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.– artless noise
Nov 19 '18 at 18:34
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to save
R0
when calling getchar()
? If not, you can just use push {r1-r4}; bl getchar; pop {r1-r4};
and r0
is still the return status. Otherwise, push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.– artless noise
Nov 19 '18 at 18:34
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53
add a comment |
1 Answer
1
active
oldest
votes
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
- To find the line of code that generates the segfault, which probably looks something like
POP {r4-r6,pc}
- To establish, by taking the stack pointer from
r13
and looking at the stack in memory, that the value that's being popped intopc
is an invalid branch address - To find the
PUSH {r4-r6,lr}
that balances thisPOP
, and ascertain that an appropriate address was pushed in the first place - To notice that the stack pointer had changed in value between the end of the
PUSH
and the start of the balancingPOP
(which it should not do if all intermediate stack operations have been properly balanced) - To step through the code and try to find the source of the stack imbalance.
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
andr12
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
andlr
(r14
) are 'call-preserved' so any function you write must preserve these (but need not preserver0-r3
orr12
);- The stack should be 8-byte aligned across translation unit boundaries, so it's a good idea always to push and pop even numbers of registers to avoid falling victim to weird undefined behaviour. Your call to
getchar
currently operates with a misaligned stack.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373428%2fhow-do-i-use-branching-in-a-loop-in-arm-assembly%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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
- To find the line of code that generates the segfault, which probably looks something like
POP {r4-r6,pc}
- To establish, by taking the stack pointer from
r13
and looking at the stack in memory, that the value that's being popped intopc
is an invalid branch address - To find the
PUSH {r4-r6,lr}
that balances thisPOP
, and ascertain that an appropriate address was pushed in the first place - To notice that the stack pointer had changed in value between the end of the
PUSH
and the start of the balancingPOP
(which it should not do if all intermediate stack operations have been properly balanced) - To step through the code and try to find the source of the stack imbalance.
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
andr12
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
andlr
(r14
) are 'call-preserved' so any function you write must preserve these (but need not preserver0-r3
orr12
);- The stack should be 8-byte aligned across translation unit boundaries, so it's a good idea always to push and pop even numbers of registers to avoid falling victim to weird undefined behaviour. Your call to
getchar
currently operates with a misaligned stack.
add a comment |
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
- To find the line of code that generates the segfault, which probably looks something like
POP {r4-r6,pc}
- To establish, by taking the stack pointer from
r13
and looking at the stack in memory, that the value that's being popped intopc
is an invalid branch address - To find the
PUSH {r4-r6,lr}
that balances thisPOP
, and ascertain that an appropriate address was pushed in the first place - To notice that the stack pointer had changed in value between the end of the
PUSH
and the start of the balancingPOP
(which it should not do if all intermediate stack operations have been properly balanced) - To step through the code and try to find the source of the stack imbalance.
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
andr12
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
andlr
(r14
) are 'call-preserved' so any function you write must preserve these (but need not preserver0-r3
orr12
);- The stack should be 8-byte aligned across translation unit boundaries, so it's a good idea always to push and pop even numbers of registers to avoid falling victim to weird undefined behaviour. Your call to
getchar
currently operates with a misaligned stack.
add a comment |
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
- To find the line of code that generates the segfault, which probably looks something like
POP {r4-r6,pc}
- To establish, by taking the stack pointer from
r13
and looking at the stack in memory, that the value that's being popped intopc
is an invalid branch address - To find the
PUSH {r4-r6,lr}
that balances thisPOP
, and ascertain that an appropriate address was pushed in the first place - To notice that the stack pointer had changed in value between the end of the
PUSH
and the start of the balancingPOP
(which it should not do if all intermediate stack operations have been properly balanced) - To step through the code and try to find the source of the stack imbalance.
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
andr12
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
andlr
(r14
) are 'call-preserved' so any function you write must preserve these (but need not preserver0-r3
orr12
);- The stack should be 8-byte aligned across translation unit boundaries, so it's a good idea always to push and pop even numbers of registers to avoid falling victim to weird undefined behaviour. Your call to
getchar
currently operates with a misaligned stack.
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
- To find the line of code that generates the segfault, which probably looks something like
POP {r4-r6,pc}
- To establish, by taking the stack pointer from
r13
and looking at the stack in memory, that the value that's being popped intopc
is an invalid branch address - To find the
PUSH {r4-r6,lr}
that balances thisPOP
, and ascertain that an appropriate address was pushed in the first place - To notice that the stack pointer had changed in value between the end of the
PUSH
and the start of the balancingPOP
(which it should not do if all intermediate stack operations have been properly balanced) - To step through the code and try to find the source of the stack imbalance.
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
andr12
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
andlr
(r14
) are 'call-preserved' so any function you write must preserve these (but need not preserver0-r3
orr12
);- The stack should be 8-byte aligned across translation unit boundaries, so it's a good idea always to push and pop even numbers of registers to avoid falling victim to weird undefined behaviour. Your call to
getchar
currently operates with a misaligned stack.
answered Nov 22 '18 at 13:25
cooperisedcooperised
1,359813
1,359813
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373428%2fhow-do-i-use-branching-in-a-loop-in-arm-assembly%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Where does it segfault? Have you used a debugger to find out? The fact that it segfaulted means that your code was not logically sound, of course; but equally, the fact that it no longer segfaults with your modification does not mean that you have fixed it, just that it is no longer broken in the same way...
– cooperised
Nov 19 '18 at 12:16
3
Stack operations must be balanced. Judging by the code you've shown us, if
r0 == -1
you'll skip thePOP {r0-r4}
.– Michael
Nov 19 '18 at 13:39
You can also solve this by only using r0-r3 for intermediates (temporaries) that don't need to be saved over function calls. Do you really need to save
R0
when callinggetchar()
? If not, you can just usepush {r1-r4}; bl getchar; pop {r1-r4};
andr0
is still the return status. Otherwise,push {r0-r4}; bl getchar; cmp r0, #-1; pop {r0-r4};
Using r4-r8 for value to be preserved over a function call as the EABI intends solves the issue without any code.– artless noise
Nov 19 '18 at 18:34
Note also that the ARM ABI requires 8-byte stack alignment across function boundaries involving different translation units. If you can't guarantee 8-byte alignment then you'll get undefined behaviour. You can ensure that the stack remains 8-byte aligned by always pushing and popping even numbers of registers.
– cooperised
Nov 20 '18 at 9:53