ARM程序集 - stmfd/ldmfd

Neb*_*vic 3 assembly arm

我正在为UNI做一个项目并遇到问题.我们正在学习如何在调用子程序时将寄存器推送到堆栈.我需要编写一个子程序,将十进制数0-15转换为相应的十六进制ASCII码,并保留除r0之外的所有寄存器的值,其中应存储结果.我有一个ASCII码表,基本上只需要将数字*4添加到ASCII表的起始地址,然后将值存回r0.我得到了正确的结果,但子程序循环.它不断从"ldmfd"命令跳到"sub".知道为什么吗?

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 */
Run Code Online (Sandbox Code Playgroud)

Mic*_*ael 9

请注意,您已将子例程直接放在调用它的指令之后:

bl  sub
sub:  stmfd sp!,{r1-r2,lr}
      ldr r0,[r1,r2,LSL #2]
      ldmfd sp!,{r1-r2,pc}
Run Code Online (Sandbox Code Playgroud)

那么当你从第一次通话回来时会发生什么sub?它将返回到后面的指令bl,即stmfd sp!,{r1-r2,lr}.因此子程序有效地返回到它自身的开头.它将继续这样做,因为没有额外的隐式或显式写入lr.


Nic*_*rth 5

您的代码有两个问题。

  1. 主代码永远不会返回任何位置,这意味着您的代码从sub返回之后,它将再次从“ sub:”开始,因为那是您的返回点。由于lr不变,因此它将卡在stmfd / ldmfd之间的循环中。您需要调用系统的退出功能。
  2. 没有理由保存r1,r2,lr。您无需在代码中更改它们,而且r0-r3和r12还是调用者保存的寄存器。