7.2.4 特定アドレスへの関数とデータの配置方法

関数およびデータを特定のアドレスに配置するために使用するさまざまな方法があります。

必要な場所では通常、コンパイラは 1 つのソースファイルから RO、RW、ZI、XO の 4 つのセクションを生成します。これらのセクションには、ソースファイルのすべてのコードとデータが保持されています。

特定アドレスへの関数とデータの配置

1 つの関数項目またはデータ項目を固定アドレスに配置するには、その関数またはデータを、入力ファイルの他の部分とは別にリンカに処理させる必要があります。

リンカでセクションを特定のアドレスに配置できるようにするには、以下の方法があります。
  • 目的のアドレスに実行領域を定義するスキャッタファイルは、1 つのセクションだけを選択するセクション記述を使用して作成できます。
  • 特別な名前付きセクションの場合、リンカはセクション名から配置アドレスを取得できます。これらの特別な名前のセクションは、__at セクションと呼ばれます。
関数または変数を特定のアドレスに配置するには、その固有のセクションに配置する必要があります。それを実行するには、方法がいくつかあります。
  • 関数またはデータ項目を、その関数やデータ項目しかない個別のソースファイル内に配置する。
  • __attribute__((at(address))) を使用して、別個のセクションの特定のアドレスに変数を配置する。
  • __attribute__((section("name"))) を使用して、名前付きセクションに関数や変数を配置する。
  • アセンブリ言語から AREA ディレクティブを使用します。アセンブリコードで配置可能な最小単位は AREA です。
  • --split_sections コンパイラオプションを使用して、ソースファイルの関数ごとに 1 つの ELF セクションを生成します。
    このオプションを指定すると、関数間でアドレス、データ、および文字列リテラルを共有する可能性が減るため、一部の関数でコードのサイズがわずかに増加します。ただし、 armlink --remove を指定することによって、リンカは使用されていない関数を削除できるため、最終イメージの合計サイズを小さくすることができます。

スキャッタロードを使用せずに特定のアドレスに変数を配置する方法の例

この例では、コードとデータを特定のアドレスに配置するようにソースコードを変更する方法を紹介しています。なお、スキャッタファイルは必要としません。

スキャッタファイルを使用せずにコードおよびデータを特定のアドレスに配置するには、以下の手順に従います。
  1. 以下のコードを含む main.c という名前のソースファイルを作成します。
    #include <stdio.h>
    
    extern int sqr(int n1);
    int gSquared __attribute__((at(0x5000)));  // 0x5000 に配置
    int main()
    {
        gSquared=sqr(3);
        printf("Value squared is: %d\n", gSquared);
    }
  2. 以下のコードを含む function.c という名前のソースファイルを作成します。
    int sqr(int n1)
    {
        return n1*n1;
    }
  3. ソースをコンパイルし、リンクします。
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --map function.o main.o -o squared.axf
    --map オプションを指定すると、イメージのメモリマップが表示されます。また、--autoat はデフォルトです。
この例では、__attribute__((at(0x5000))) によって、グローバル変数 gSquared が絶対アドレス 0x5000 に配置されます。gSquared は、実行領域 ER$$.ARM.__at_0x00005000 およびロード領域 LR$$.ARM.__at_0x00005000 に配置されます。

アドレスは 0x5000 としてソースファイルに指定されていますが、領域名およびセクション名のアドレスは 8 桁の 16 進数値に正規化されます。
メモリマップは次のように表示されます。
…
  Load Region LR$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000000, Max: 0x00000004, ABSOLUTE)

    Execution Region ER$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000004, Max: 0x00000004, ABSOLUTE, UNINIT)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x00005000   0x00000004   Zero   RW           13    .ARM.__at_0x00005000  main.o

スキャッタロードを使用して名前付きセクションに変数を配置する方法の例

この例では、スキャッタファイルを使用して、コードとデータを特定のセクションに配置するようにソースコードを変更する方法を紹介しています。

スキャッタファイルを使用して、コードとデータを特定のセクションに配置するようにソースコードを変更するには
  1. 以下のコードを含む main.c という名前のソースファイルを作成します。
    #include <stdio.h>
    extern int sqr(int n1);
    int gSquared __attribute__((section("foo")));  // セクション foo に配置
    int main()
    {
        gSquared=sqr(3);
        printf("Value squared is: %d\n", gSquared);
    }
  2. 以下のコードを含む function.c という名前のソースファイルを作成します。
    int sqr(int n1)
    {
        return n1*n1;
    }
  3. 以下のロード領域を含んだ scatter.scat という名前のスキャッタファイルを作成します。
    LR1 0x0000 0x20000
    {
        ER1 0x0 0x2000
        {
            *(+RO)                ; 残りのコードと読み出し専用データ
        }
        ER2 0x8000 0x2000
        {
            main.o
        }
        ER3 0x10000 0x2000
        {
            function.o
            *(foo)                ; gSquared を ER3 に配置する
        }
        ; RW データと ZI データを 0x200000 に配置する
        RAM 0x200000 (0x1FF00-0x2000)
        {
            *(+RW, +ZI)
        }
        ARM_LIB_STACK 0x800000 EMPTY -0x10000
        {
        }
        ARM_LIB_HEAP  +0 EMPTY 0x10000
        {
        }
    }
    このプログラムは、セミホスティングライブラリとリンクされるため、ARM_LIB_STACK 領域と ARM_LIB_HEAP 領域が必要です。
  4. ソースをコンパイルし、リンクします。
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --map --scatter=scatter.scat function.o main.o -o squared.axf
    --map オプションを指定すると、イメージのメモリマップが表示されます。また、--autoat はデフォルトです。
この例では、__attribute__((section("foo"))) によって、グローバル変数 gSquaredfoo というセクションに配置されます。セクション foo は、ER3 実行領域に配置されます。
メモリマップは次のように表示されます。
  Load Region LR1 (Base: 0x00000000, Size: 0x00001570, Max: 0x00020000, ABSOLUTE)
…
    Execution Region ER3 (Base: 0x00010000, Size: 0x00000010, Max: 0x00002000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x00010000   0x0000000c   Code   RO            3    .text               function.o
    0x0001000c   0x00000004   Data   RW           15    foo                 main.o
…

スキャッタファイルから *(foo) を省略した場合、セクションは同じ種類の領域に配置されます。この例では RAM ということになります。

スキャッタロードを使用して特定のアドレスに変数を配置する方法の例

この例では、スキャッタファイルを使用して、コードとデータを特定のアドレスに配置するようにソースコードを変更する方法を紹介しています。

スキャッタファイルを使用して、コードとデータを特定のアドレスに配置するようにソースコードを変更するには
  1. 以下のコードを含む main.c という名前のソースファイルを作成します。
    #include <stdio.h>
    extern int sqr(int n1);
    // アドレス 0x10000 に配置する
    const int gValue __attribute__((section(".ARM.__at_0x10000"))) = 3;
    int main()
    {
        int squared;
        squared=sqr(gValue);
        printf("Value squared is: %d\n", squared);
    }
  2. 以下のコードを含む function.c という名前のソースファイルを作成します。
    int sqr(int n1)
    {
        return n1*n1;
    }
  3. 以下のロード領域を含んだ scatter.scat という名前のスキャッタファイルを作成します。
    LR1 0x0
    {
        ER1 0x0
        {
            *(+RO)                      ; 残りのコードと読み出し専用データ
        }
        ER2+0
        {
            function.o
            *(.ARM.__at_0x10000)        ; gValue を 0x10000 に配置する
        }
        ; RW データと ZI データを 0x200000 に配置する
        RAM 0x200000 (0x1FF00-0x2000)
        {
            *(+RW, +ZI)
        }
        ARM_LIB_STACK 0x800000 EMPTY -0x10000
        {
        }
        ARM_LIB_HEAP  +0 EMPTY 0x10000
        {
        }
    }
    このプログラムは、セミホスティングライブラリとリンクされるため、ARM_LIB_STACK 領域と ARM_LIB_HEAP 領域が必要です。
  4. ソースをコンパイルし、リンクします。
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --no_autoat --scatter=scatter.scat --map function.o main.o -o squared.axf
    --map オプションを指定すると、イメージのメモリマップが表示されます。
メモリマップを見ると、アドレス 0x10000 ER2 実行領域に変数が配置されていることがわかります。
…
    Execution Region ER2 (Base: 0x00001578, Size: 0x0000ea8c, Max: 0xffffffff, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x00001578   0x0000000c   Code   RO            3    .text               function.o
    0x00001584   0x0000ea7c   PAD
    0x00010000   0x00000004   Data   RO           15    .ARM.__at_0x10000   main.o…
この例では、ER1 のサイズが不明です。そのため、gValue は、ER1 または ER2 に配置される可能性があります。gValue を確実に ER2 へと配置するには、対応するセレクタを ER2 に含めたうえで、--no_autoat コマンドラインオプションでリンクする必要があります。--no_autoat を省略した場合、gValue は、実行領域 ER$$.ARM.__at_0x.ARM.__at_0x10000 を含んだ別個のロード領域 LR$$.ARM.__at_0x10000 に配置されます。
非機密扱いPDF file icon PDF 版ARM DUI0474LJ
Copyright © 2010-2015 ARM.All rights reserved.