我看與gcc產生的臂組件的代碼,我注意到GCC編譯用下面的代碼的功能鏈接寄存器(拇指/臂)R11關係:R7和與ARM架構調用約定
0x00010504 <+0>: push {r7, lr}
0x00010506 <+2>: sub sp, #24
0x00010508 <+4>: add r7, sp, #0
0x0001050a <+6>: str r0, [r7, #4]
=> 0x0001050c <+8>: mov r3, lr
0x0001050e <+10>: mov r1, r3
0x00010510 <+12>: movw r0, #1664 ; 0x680
0x00010514 <+16>: movt r0, #1
0x00010518 <+20>: blx 0x10378 <[email protected]>
0x0001051c <+24>: add.w r3, r7, #12
0x00010520 <+28>: mov r0, r3
0x00010522 <+30>: blx 0x10384 <[email protected]>
0x00010526 <+34>: mov r3, lr
0x00010528 <+36>: mov r1, r3
0x0001052a <+38>: movw r0, #1728 ; 0x6c0
0x0001052e <+42>: movt r0, #1
0x00010532 <+46>: blx 0x10378 <[email protected]>
0x00010536 <+50>: adds r7, #24
0x00010538 <+52>: mov sp, r7
0x0001053a <+54>: pop {r7, pc}
對我來說有趣的事情是,我看到GCC使用R7將值彈出到PC而不是LR。我看到與R11類似的東西。編譯器將r11和LR推入堆棧,然後將R11彈出到PC。不應該LR作爲返回地址而不是R7或R11。爲什麼在這裏使用R7(這是Thumb模式下的幀指針)? 如果你看看蘋果ios調用約定,它甚至是不同的。它使用其他寄存器(例如r4到r7)到PC返回控制。它不應該使用LR嗎?
或者我在這裏失去了一些東西?
另一個問題是,它看起來像LR,R11或R7值永遠不會是返回地址的立即值。但是一個指向包含返回地址的堆棧的指針。是對的嗎?
另一個奇怪的事情是,編譯器不會爲函數爆出者做同樣的事情。例如,它可能不是使用彈出到PC使用bx LR,但爲什麼?
如果編譯器必須將返回地址存儲在堆棧中,它可以通過直接將*返回地址*直接卸載到PC中來保存'bx lr'。爲此目的,「pop」和「ldm *」被記錄爲互通分支指令。 – EOF
'pop {r7,pc}'不會把'r7'放到'pc'上,因爲你的問題暗示着。它彈出堆棧中的兩個寄存器('sp')。 –
我不知道我是否正確理解你的問題,但是爲了清楚起見,'push {r7,lr}'相當於'stmdb sp !, {r7,lr}',這意味着它會減少'sp',將'r7'存儲爲'[sp]',再次減量'sp',並將'lr'存儲爲'[sp]'。另一方面,'pop {r7,pc}'等同於'stmia sp !, {r7,pc}',意思是它會從'[sp]'加載'pc',增加'sp',加載'r7 '從'[sp]'開始,然後再次增加'sp'。因爲'pc'被加載,它會有效地分支。函數體中使用'r7'(其中'r0-r3'存儲參數),所以需要堆疊以保存值。 – rjp