How do I use branching in a loop in ARM Assembly?











up vote
0
down vote

favorite












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.










share|improve this question




















  • 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 at 12:16






  • 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 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 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 at 9:53















up vote
0
down vote

favorite












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.










share|improve this question




















  • 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 at 12:16






  • 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 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 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 at 9:53













up vote
0
down vote

favorite









up vote
0
down vote

favorite











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.










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 at 14:34









cooperised

1,222812




1,222812










asked Nov 19 at 11:15









eddiewastaken

1768




1768








  • 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 at 12:16






  • 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 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 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 at 9:53














  • 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 at 12:16






  • 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 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 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 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 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 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 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 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 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 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 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 at 9:53












1 Answer
1






active

oldest

votes

















up vote
0
down vote













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




  1. To find the line of code that generates the segfault, which probably looks something like POP {r4-r6,pc}

  2. To establish, by taking the stack pointer from r13 and looking at the stack in memory, that the value that's being popped into pc is an invalid branch address

  3. To find the PUSH {r4-r6,lr} that balances this POP, and ascertain that an appropriate address was pushed in the first place

  4. To notice that the stack pointer had changed in value between the end of the PUSH and the start of the balancing POP (which it should not do if all intermediate stack operations have been properly balanced)

  5. 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 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);

  • 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.






share|improve this answer





















    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',
    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
    });


    }
    });














    draft saved

    draft discarded


















    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








    up vote
    0
    down vote













    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




    1. To find the line of code that generates the segfault, which probably looks something like POP {r4-r6,pc}

    2. To establish, by taking the stack pointer from r13 and looking at the stack in memory, that the value that's being popped into pc is an invalid branch address

    3. To find the PUSH {r4-r6,lr} that balances this POP, and ascertain that an appropriate address was pushed in the first place

    4. To notice that the stack pointer had changed in value between the end of the PUSH and the start of the balancing POP (which it should not do if all intermediate stack operations have been properly balanced)

    5. 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 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);

    • 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.






    share|improve this answer

























      up vote
      0
      down vote













      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




      1. To find the line of code that generates the segfault, which probably looks something like POP {r4-r6,pc}

      2. To establish, by taking the stack pointer from r13 and looking at the stack in memory, that the value that's being popped into pc is an invalid branch address

      3. To find the PUSH {r4-r6,lr} that balances this POP, and ascertain that an appropriate address was pushed in the first place

      4. To notice that the stack pointer had changed in value between the end of the PUSH and the start of the balancing POP (which it should not do if all intermediate stack operations have been properly balanced)

      5. 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 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);

      • 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.






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        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




        1. To find the line of code that generates the segfault, which probably looks something like POP {r4-r6,pc}

        2. To establish, by taking the stack pointer from r13 and looking at the stack in memory, that the value that's being popped into pc is an invalid branch address

        3. To find the PUSH {r4-r6,lr} that balances this POP, and ascertain that an appropriate address was pushed in the first place

        4. To notice that the stack pointer had changed in value between the end of the PUSH and the start of the balancing POP (which it should not do if all intermediate stack operations have been properly balanced)

        5. 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 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);

        • 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.






        share|improve this answer












        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




        1. To find the line of code that generates the segfault, which probably looks something like POP {r4-r6,pc}

        2. To establish, by taking the stack pointer from r13 and looking at the stack in memory, that the value that's being popped into pc is an invalid branch address

        3. To find the PUSH {r4-r6,lr} that balances this POP, and ascertain that an appropriate address was pushed in the first place

        4. To notice that the stack pointer had changed in value between the end of the PUSH and the start of the balancing POP (which it should not do if all intermediate stack operations have been properly balanced)

        5. 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 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);

        • 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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 at 13:25









        cooperised

        1,222812




        1,222812






























            draft saved

            draft discarded




















































            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.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            If I really need a card on my start hand, how many mulligans make sense? [duplicate]

            Alcedinidae

            Can an atomic nucleus contain both particles and antiparticles? [duplicate]