Why does stmfd/ldmfd jump back to sub?

15,369

Solution 1

There are a couple of issues with your code.

  1. The main code never returns anywhere, which means after your code returns from the sub it will start again at "sub:" because thats your return point. As lr did not change, it will be stuck in a loop between stmfd/ldmfd. You need to call the exit-function of your system.
  2. There is no reason to save r1, r2, lr. You're not changing them in your code, also r0-r3 and r12 are caller saved registers anyway.

Solution 2

Note that you have placed your subroutine directly following the instruction that calls it:

bl  sub
sub:  stmfd sp!,{r1-r2,lr}
      ldr r0,[r1,r2,LSL #2]
      ldmfd sp!,{r1-r2,pc}

So what happens when you return from the first call to sub? It will return to the instruction following the bl, i.e. the stmfd sp!,{r1-r2,lr}. So the subroutine effectively returns to the beginning of itself. And it will keep doing so because there are no additional implicit or explicit writes to lr.

Share:
15,369
Admin
Author by

Admin

Updated on July 14, 2022

Comments

  • Admin
    Admin almost 2 years

    I am doing a project for UNI and have a problem.

    We are learning how to push/pop registers onto stack when calling a subroutine.

    I need to write a subroutine to convert a decimal number 0-15 into a corresponding hex ASCII code, and keep the value of all registers except r0, where the result should be stored. I have a table of ASCII codes, and basically just add the number*4 to the starting address of the ASCII table, and store the value back into r0.

    I get the right result, but the subroutine loops. It keeps jumping from ldmfd to sub endlessly. Any idea why?

    main:
    adr r0,num
    adr r1,ascii
    ldr r2,[r0]
    bl  sub
    sub:  stmfd sp!,{r1-r2,lr}
          ldr r0,[r1,r2,LSL #2]
          ldmfd sp!,{r1-r2,pc}
    
    /* variables here */
    num:    .word 15
    ascii:  .word 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
    /* end variables */