18

私は Atmel SAM7S256 マイクロコントローラー用のソフトウェアをゼロから作成している大学のプロジェクトに取り組んでいます。今回はリンカー スクリプトとアセンブリ言語の知識が必要なため、以前に使用した他の MCU よりも詳細です。

SAM7/ARM プロジェクトをゼロから開始する方法を完全に理解するために、SAM7S チップのサンプル プロジェクトを精査してきました。注目すべき例は、Miro Samek の「Building Bare-Metal ARM Systems with GNU」チュートリアル(この質問のコードの出典) ですまた、sourceware.org からリンカとアセンブラのドキュメントを読むのにも多くの時間を費やしました。

次のリンカ スクリプトの大部分を理解できて、とてもうれしく思います。ロケーション カウンターに関して、私には理解できないことが 1 つだけあります。以下は、上記のチュートリアルで提供されるリンカー スクリプトです。

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_vectors)

MEMORY {                                       /* memory map of AT91SAM7S64 */
    ROM (rx)  : ORIGIN = 0x00100000, LENGTH = 64k
    RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 16k
}

/* The sizes of the stacks used by the application. NOTE: you need to adjust */
C_STACK_SIZE   = 512;
IRQ_STACK_SIZE = 0;
FIQ_STACK_SIZE = 0;
SVC_STACK_SIZE = 0;
ABT_STACK_SIZE = 0;
UND_STACK_SIZE = 0;

/* The size of the heap used by the application. NOTE: you need to adjust   */
HEAP_SIZE = 0;

SECTIONS {

    .reset : {
        *startup.o (.text)  /* startup code (ARM vectors and reset handler) */
        . = ALIGN(0x4);
     } >ROM

    .ramvect : {                        /* used for vectors remapped to RAM */
        __ram_start = .;
        . = 0x40;
    } >RAM

    .fastcode : {
        __fastcode_load = LOADADDR (.fastcode);
        __fastcode_start = .;

        *(.glue_7t) *(.glue_7)
        *isr.o (.text.*)
        *(.text.fastcode)
        *(.text.Blinky_dispatch)
        /* add other modules here ... */

        . = ALIGN (4);
        __fastcode_end = .;
    } >RAM AT>ROM

    .text : {
        . = ALIGN(4);
        *(.text)                                   /* .text sections (code) */
        *(.text*)                                 /* .text* sections (code) */
        *(.rodata)           /* .rodata sections (constants, strings, etc.) */
        *(.rodata*)         /* .rodata* sections (constants, strings, etc.) */
        *(.glue_7) /* glue arm to thumb (NOTE: placed already in .fastcode) */
        *(.glue_7t)/* glue thumb to arm (NOTE: placed already in .fastcode) */

        KEEP (*(.init))
        KEEP (*(.fini))

        . = ALIGN(4);
        _etext = .;                         /* global symbol at end of code */
    } >ROM

    .preinit_array : {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(SORT(.preinit_array.*)))
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
    } >ROM

    .init_array : {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
    } >ROM

    .fini_array : {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(.fini_array*))
        KEEP (*(SORT(.fini_array.*)))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >ROM

    .data : {
        __data_load = LOADADDR (.data);
        __data_start = .;
        *(.data)                                          /* .data sections */
        *(.data*)                                        /* .data* sections */
        . = ALIGN(4);
        _edata = .;
    } >RAM AT>ROM

    .bss : {
        __bss_start__ = . ;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;                     /* define a global symbol at bss end */
        __bss_end__ = .;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );
    PROVIDE ( __end__ = _ebss );

    .heap : {
        __heap_start__ = . ;
        . = . + HEAP_SIZE;
        . = ALIGN(4);
        __heap_end__ = . ;
    } >RAM

    .stack : {
        __stack_start__ = . ;

        . += IRQ_STACK_SIZE;
        . = ALIGN (4);
        __irq_stack_top__ = . ;

        . += FIQ_STACK_SIZE;
        . = ALIGN (4);
        __fiq_stack_top__ = . ;

        . += SVC_STACK_SIZE;
        . = ALIGN (4);
        __svc_stack_top__ = . ;

        . += ABT_STACK_SIZE;
        . = ALIGN (4);
        __abt_stack_top__ = . ;

        . += UND_STACK_SIZE;
        . = ALIGN (4);
        __und_stack_top__ = . ;

        . += C_STACK_SIZE;
        . = ALIGN (4);
        __c_stack_top__ = . ;

        __stack_end__ = .;
    } >RAM

    /* Remove information from the standard libraries */
    /DISCARD/ : {
        libc.a ( * )
        libm.a ( * )
        libgcc.a ( * )
    }
}

例全体 (.ramvect、.fastcode、および .stack セクションなど) には、 などのシンボル定義があります__ram_start = .;。これらのアドレスは、MCU の RAM 内の正しい位置を初期化するために、スタートアップ アセンブリ コードと初期化 C コードによって使用されます。

私が理解に問題を抱えているのは、これらのシンボル定義がどのようにして正しい値が割り当てられるかということです。これは起こります。スクリプトは正しいですが、方法がわかりません。

私が理解しているように、セクション内でロケーション カウンターを使用すると、セクション自体の仮想メモリ アドレス (VMA) からの相対オフセットのみが含まれます。

したがって、たとえば、行__ram_start = .;では、__ram_start に 0x0 の値が割り当てられると予想されます。これは、.ramvect セクションの最初に位置カウンターの値が割り当てられているためです。ただし、初期化コードが正しく機能するためには (実際に機能します)、__ram_start を 0x00200000 (RAM の開始アドレス) として割り当てる必要があります。

行が代わりに__ram_start = ABSOLUTE(.);または__ram_start = ADDR(.ramvect);.

__fastcode_startと についても同様__stack_start__です。それらをすべてアドレス 0x0 として定義することはできません。そうしないと、プログラムが機能しません。しかし、ここにリンクされているドキュメントは、それが起こっていることを示唆しているようです。ドキュメントからの引用は次のとおりです。

ノート: 。実際には、現在含まれているオブジェクトの先頭からのバイト オフセットを参照します。通常、これは SECTIONS ステートメントであり、その開始アドレスは 0 であるため、. 絶対アドレスとして使用できます。もしも 。ただし、セクション記述内で使用される場合は、絶対アドレスではなく、そのセクションの先頭からのバイト オフセットを参照します。

したがって、これらのシンボル割り当て中のロケーション カウンター値は、対応するセクション VMA からのオフセットである必要があります。したがって、これらの「_start」シンボルはすべて0x0 に設定されているはずです。これはプログラムを壊します。

だから明らかに私は何かが欠けています。ロケーション カウンター値を (セクション内の) シンボルに割り当てると、デフォルトで ABSOLUTE() が使用されるという単純な結果になると思います。しかし、これを確認する明確な説明をどこにも見つけることができませんでした。

誰かがこれを解決できる場合は、事前に感謝します。

4

3 に答える 3

10

私は自分の質問に対する答えを見つけたかもしれないと思います。私が正しいかどうかはわかりませんが、実際に理にかなっていると考えることができたのはこれが初めてです。考え直したのは、ドキュメントのこのページでした。特にこの引用:

アドレスとシンボルはセクション相対または絶対です。セクション相対シンボルは再配置可能です。`-r' オプションを使用して再配置可能な出力を要求すると、さらにリンク操作を行うと、セクション相対シンボルの値が変更される場合があります。一方、絶対シンボルは、以降のリンク操作を通じて同じ値を保持します。

そしてこの引用:

組み込み関数 ABSOLUTE を使用すると、相対式になる式を強制的に絶対式にすることができます。たとえば、出力セクションの末尾のアドレスに設定された絶対シンボルを作成するには、 次のようにします.data

 SECTIONS
   {
     .data : { *(.data) _edata = ABSOLUTE(.); }
   }

ABSOLUTE使用されていない場合は_edata.data セクションに関連します。

前に読んだことはありましたが、今回は新しい視点から見ました。

したがって、私の誤解は、相対バイトオフセットアドレスが割り当てられたときに、ベースアドレス情報が失われている間、シンボルがそのオフセットの値に設定されるだけだと考えていたと思います。

それは私の元の質問からのこの引用に基づいていました:

ノート: 。実際には、現在含まれているオブジェクトの先頭からのバイト オフセットを参照します。通常、これは SECTIONS ステートメントであり、その開始アドレスは 0 であるため、. 絶対アドレスとして使用できます。もしも 。ただし、セクション記述内で使用される場合は、絶対アドレスではなく、そのセクションの先頭からのバイト オフセットを参照します。

代わりに、現在起こっていることを理解しているのは、ベース アドレス情報が失われていないということです。シンボルには、ベース アドレスからのオフセットの値が割り当てられるだけではありません。シンボルは最終的に絶対アドレスに解決されますが、そのベース アドレスが変更される可能性がない場合に限ります。

__stack_start__ = . ;のようなものを に変更する必要があると思っていましたが__stack_start__ = ABSOLUTE(.) ;、これは機能しますが、今では不要だと思います。さらに、この回答の最初の引用から、ELF ファイルを再リンクできることがわかりました。

その__stack_start__ = ABSOLUTE(.) ;ため、リンカー スクリプトを実行して ELF 実行可能ファイルを作成し、それを再リンクして .stack セクションを別の場所に移動した場合、__stack_start__シンボルは最初のリンクと同じ絶対アドレスを指しているため、正しくありません。

これはおそらく理解するのが難しいですが、できる限り明確に書いています。私は正しい考えに近づいていると思いますが、これを確認または否定するには、このことについて実際に知っている人が必要です.

于 2013-01-09T08:49:02.817 に答える
6

セクションの配置は、右中括弧 ( >RAM AT>ROM) の後のメモリ領域によって決まります。したがって、実行アドレスは RAM の 0x00200000 以降ですが、ロード アドレスは ROM (フラッシュ) の 0x00100000 になります。起動コードは、.fastcode出力セクションをロードから実行アドレスにコピーする必要があります。これがシンボルの目的です。

AT91SAM7S は RAM または ROM のいずれかをアドレス 0 に再マップするため、これらがアドレス 0 である必要はないことに注意してください。通常、AT91SAM7S は ROM がマップされた状態で起動し、起動コードがそれを RAM に切り替えます。

于 2012-12-13T11:06:58.053 に答える