リンカスクリプトでシンボル単位にアドレスを指定する方法

リンカスクリプトでシンボル単位にアドレスを指定する方法

Posted at January 26,2018 12:03 AM
Tag:[C/C++]

リンカスクリプトでシンボル単位にアドレスを指定する方法を紹介します。

1.問題点

C/C++で下記の簡単なサンプルを作りました。

#include <stdio.h>
 
int a;
int b[10];
char c[10];
 
int main(void) {
    printf("&a:%p\n", &a);
    printf("&b:%p\n", &b);
    printf("&c:%p\n", &c);
 
    a = 100;
    b[0] = 1;
    c[0] = 'x';
 
    printf("a=%d\n", a);
    printf("b[0]=%d\n", b[0]);
    printf("c[0]=%c\n", c[0]);
    return 0;
}

実行結果

% ./a.out
&a:0x10020180
&b:0x10020184
&c:0x10020318
a=100
b[0]=1
c[0]=x

この実行ファイルのマップは次のようになっています(マップを出力するにはgccまたはg++に"-Wl,-M"を設定)。

 .bss           0x0000000010020180      0x1fc /tmp/ccuc7H46.o
                0x0000000010020180                a
                0x0000000010020184                b
                0x0000000010020318                c

このa,b,cの3つのシンボル(変数)について個別にアドレスを指定したいのですが、方法がわかりません。

ということで、リンカスクリプトでシンボル単位にアドレスを指定する方法を紹介します。

2.シンボル単位にアドレスを指定する

シンボル単位にアドレスを指定するには、下記赤色(リンカスクリプト抜粋)の部分を追加します。

  .bss :
  {
   *(.bss)
     a = ABSOLUTE(0);
     b = ABSOLUTE(4);
     c = ABSOLUTE(100);
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 64 / 8 : 1);
  }

シンボルにアドレスを指定するフォーマットは次のとおりです。

SECTIONS
{
  <section> :
  { *(<section>)
    <symbol> = ABSOLUTE(<address>);
  }
}

アドレスにはセクション内の相対アドレスを設定します。

今回の設定では、

SECTIONS
{
 :
  .bss :
  {
   *(.bss)
     a = ABSOLUTE(0);
     b = ABSOLUTE(4);
     c = ABSOLUTE(100);
 :
  }
 :
}

という風に、ABSOLUTEに.bssセクションからの相対アドレスを設定することで期待する動作になりました。

aの"0"は、.bssセクションから+0番地、bの"4"は、.bssセクションから+4番地、cの"100"は、.bssセクションから+100番地になります。

実行結果

% ./a.out
&a:0x10020178
&b:0x1002017c
&c:0x100201dc
a=100
b[0]=1
c[0]=x

アドレスはうまく設定されているようですが、マップ上のアドレスは相対指定した値がそのまま入っています。

 .bss           0x000000001002037c        0x0 /usr/lib/gcc/ppc64-redhat-linux/4.8.5/../../../../lib64/crtn.o
                0x0000000000000000                a = 0x0
                0x0000000000000004                b = 0x4
                0x0000000000000064                c = 0x64

nmコマンドではアドレスが割り当てられています。

% nm ./a.out
 :
0000000010020178 B a
000000001002017c B b
0000000010020178 b completed.8008
0000000010020000 W data_start
0000000010020038 d deregister_tm_clones
0000000010020068 d frame_dummy
0000000010020078 D main
                 U printf@@GLIBC_2.4
0000000010020048 d register_tm_clones
00000000100201dc B c
 :

ちなみに下記のように絶対アドレスを設定すると、

SECTIONS
{
 :
  .bss :
  {
   *(.bss)
     a = ABSOLUTE(0x10020178);
     b = ABSOLUTE(0x1002017c);
     c = ABSOLUTE(0x100201dc);
 :
  }
 :
}

ビルドはOKですが、Segmentation faultになります。設定アドレスが.bssセクションのアドレスに加算されてしまうためです。

実行結果

% ./a.out
&a:0x200402f0
&b:0x200402f4
&c:0x20040354
Segmentation fault (コアダンプ)

ということで、シンボルにアドレスを指定する場合は現在のアドレスからの相対アドレスになります。

3.参考サイト

参考サイトは下記です。ありがとうございました。

関連記事
トラックバックURL


コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)