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

通常、コンパイラは 1 つのソースファイルから RO、RW、ZI の 3 つのセクションを生成します。 これらの領域には、ソースファイルのすべてのコーとデータが保持されます。 1 つの関数項目またはデータ項目を固定アドレスに配置するには、その関数またはデータを、入力ファイルの他の部とは別にリンカに処理させる必要があります。

リンカでセクションを特定のアドレスに配置できるようにするには、方法が 2 つあります。

関数または変数を特定のアドレスに配置するには、その固有のセクションに配置する必要があります。 それを実行するには、方法がいくつかあります。

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

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

  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 が絶対アドレス 0x20000 に配置されます。gSquared は、実行領域 ER$$.ARM.__AT_0x00005000 およびロード領域 LR$$.ARM.__AT_0x00005000 に配置されます。

メモリマップは次のように表示されます。

...
  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           15    .ARM.__AT_0x00005000  main.o

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

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

  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 に配置する
        }
        RAM 0x200000 (0x1FF00-0x2000)   ; RW データと ZI データを 0x200000 に配置する
        {
            *(+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
    aarmlink --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: 0x00001778, Max: 0x00020000, ABSOLUTE)
...
    Execution Region ER3 (Base: 0x00010000, Size: 0x00000004, Max: 0x00002000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x00010000   0x00000004   Data   RW           15    foo                 main.o
...

Note

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

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

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

  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 に配置する
        }
        RAM 0x200000 (0x1FF00-0x2000)   ; RW データと ZI データを 0x200000 に配置する
        {
            *(+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 オプションを指定すると、イメージのメモリマップが表示されます。

メモリマップを見ると、アドレス 0x11000ER2 実行領域に変数が配置されていることがわかります。

...
    Execution Region ER2 (Base: 0x00001598, Size: 0x0000ea6c, Max: 0xffffffff, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x00001598   0x0000000c   Code   RO            3    .text               function.o
    0x000015a4   0x0000ea5c   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_0x00020000 を含んだ別個のロード領域 LR$$.ARM.__AT_0x00010000 に配置されます。

Show/hide関連項目

Copyright © 2010-2012 ARM. All rights reserved.ARM DUI 0474GJ
Non-ConfidentialID051612