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












0















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 '18 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 '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













  • 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
















0















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 '18 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 '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













  • 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














0












0








0








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 '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, 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













  • 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





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













  • 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












1 Answer
1






active

oldest

votes


















0














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


    }
    });














    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









    0














    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




























      0














      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


























        0












        0








        0







        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 '18 at 13:25









        cooperisedcooperised

        1,359813




        1,359813






























            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.




            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

            Guess what letter conforming each word

            Port of Spain

            Run scheduled task as local user group (not BUILTIN)