6

アセンブリで記述されたベアメタル ARM の起動コードがあり、それがどのように機能するかを理解しようとしています。バイナリは外部フラッシュに書き込まれ、起動時にその一部を RAM にコピーしています。このウィキペディアのエントリを読んでも、このコンテキストでの移転の概念はまだ正確にはわかりませんでした。RAM は低アドレス ウィンドウにマップされ、フラッシュは高アドレス ウィンドウにマップされます。ここでリンク レジスタの値をテストする理由を誰か説明してもらえますか?

/* Test if we are running from an address, we are not linked at */
       bl check_position
 check_position:
        mov     r0, lr                  
        ldr     r1, =check_position
        cmp     r0, r1                  /* ; don't relocate during debug */
        beq     relocated_entry 
4

2 に答える 2

5

私の推測では、アプリケーションは RAM から実行されます。アプリケーションをデバッグするとき、この作成者はおそらく何らかのブートローダーや jtag を使用して、テスト アプリを RAM に直接ロードしているため、コピーして実行する理由はありません (クラッシュを引き起こす可能性があります)。

このようなことを行うもう 1 つの理由は、無限ループを回避するためです。たとえば、フラッシュから起動したい (通常はそうしなければならない) が RAM から実行する場合、最も簡単な方法は、フラッシュ全体またはフラッシュの一部全体を RAM にコピーし、RAM の先頭に分岐することです。これを行うと、「アプリをRAMとブランチにコピーする」ループを再度実行して、2回目(クラッシュする可能性があります)を回避するために、フラッシュからこのループを実行しているか、テストしていないかのようなものがあります。

于 2013-03-28T00:03:00.110 に答える
4

ここでリンク レジスタの値をテストする理由を説明できる人はいますか?

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疑似操作はそれほど頻繁に使用されないため、人々は慣れていない可能性があります。

于 2013-03-28T00:20:41.300 に答える