简体   繁体   中英

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM