ここでリンク レジスタの値をテストする理由を説明できる人はいますか?
のbl check_position値をPC+4リンク レジスタに配置し、制御をcheck_positionPC 相対に転送します。ARM での bl これまでのところ、すべてがPC相対的です。
は、リテラル プールldr r1,=check_positionから値を取得します。Ref1 実際のコードは次のようになります。
ldr r1,[pc, #offset]
...
offset:
.long check_position # absolute address from assemble/link.
したがって、R0には PC 相対バージョンがR1含まれ、 には絶対アセンブル バージョンが含まれます。ここでは、それらを比較します。算術を使用して差を計算し、ゼロ以外の場合はそれに分岐することもできます。または、コードを絶対的な宛先にコピーすることもできます。Ref2 コードがリンクされたアドレスで実行されている場合、とは同じです。これは一部です。R0R1pseudo codebl
mov lr,pc ; pc is actually two instruction ahead.
add pc,pc,#branch_offset-8
重要なのは、 の更新を含め、BLに基づいてすべてを行うことです。このトリックを使用する代わりに、 を使用できますが、が 8 バイト先になります。もう 1 つの方法は、 を使用することです。これにより、アセンブラーにすべてのアドレス計算を実行させることができます。PClrmov R0,PCPCadr R0,check_position
/* Test if we are running from an address, we are not linked at */
check_position:
adr r0, check_position
ldr r1, =check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
ARMv6 バージョンは次のようになります。
/* Test if we are running from an address, we are not linked at */
check_position:
adr r0, check_position
movw r1, #:lower16:check_position
movt r1, #:upper16:check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
どちらの場合も、コードはより単純で、1 ワード小さく、レジスタを上書きしないlrため、他の目的に使用できます。
Ref1: gnu-assembler マニュアルのArm op-codesと.ltorgを参照してください。
Ref2:これはまさに Linuxhead.Sが ARM に対して行っていることです。
編集: ARM ARM を確認しましたが、PC は明らかに現在の命令+8であり、コードがこのようになった理由を示しています。adrバージョンの方が直接的で読みやすいと思いますが、adr疑似操作はそれほど頻繁に使用されないため、人々は慣れていない可能性があります。