3

UNI のプロジェクトを行っていますが、問題があります。

サブルーチンを呼び出すときにレジスタをスタックにプッシュ/ポップする方法を学習しています。

10 進数 0 ~ 15 を対応する 16 進数 ASCII コードに変換するサブルーチンを作成しr0、結果を格納する必要がある を除くすべてのレジスタの値を保持する必要があります。私は ASCII コードのテーブルを持っています。基本的にnumber*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 */
4

3 に答える 3

10

サブルーチンを呼び出す命令の直後にサブルーチンを配置したことに注意してください。

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

では、最初の呼び出しから に戻るとどうなるsubでしょうか? blの次の命令、つまり に戻りstmfd sp!,{r1-r2,lr}ます。したがって、サブルーチンは効果的にそれ自体の先頭に戻ります。への追加の暗黙的または明示的な書き込みがないため、これは引き続き行われlrます。

于 2013-04-05T12:51:57.267 に答える
5

コードにはいくつかの問題があります。

  1. メイン コードはどこにも戻りません。つまり、コードがサブから戻った後、「sub:」から再び開始されます。これが戻りポイントだからです。lr は変更されていないため、stmfd/ldmfd 間のループに陥ります。システムの exit-function を呼び出す必要があります。
  2. r1、r2、lr を保存する理由はありません。コードでそれらを変更していません。また、r0-r3 と r12 は呼び出し元が保存したレジスタです。
于 2013-04-05T13:45:50.400 に答える
-1

私は ARM アセンブリの専門家ではありませんが、少なくともローカル コンパイラの出力を読むことはできます。

gcc はlrスタックに格納しないことを好むようです (これは理にかなっています。レジスタのポイントは、可能な場合はスタック アクセスを回避することです)。

代わりに、サブルーチンはリンク レジスタで分岐を実行して終了します。

bx  lr

注: bx(分岐交換) 命令は Thumb 対応のプロセッサでのみ使用できるようです。

于 2013-04-05T12:41:22.607 に答える