

リンクして実行形式ファイルを生成するとたくさんのセクションが配置されますよね。（形式によるか。。）  
そのなかの

.text  
.data  
.bss  
.rodata

上記の中の上からのセクションからアドレス0x00000000へマップする前提でリンクさせたいです。

つまり、

.text size = 10  
.data size = 10  
.bss size = 10  
.rodata size = 10

だとしたら

.textセクションがアドレス0x0000  
.dataセクションがアドレス0x0000 + 10  
.bssセクションがアドレス0x0000 + 10 * 2  
.rodataセクションがアドレス0x0000 + 10 *3

から配置されるという前提でリンクさせたいです。  
（このあと各セクションをobjcopyで取り出しつなげることでrawバイナリにして使います。  
これで作ったrawバイナリプログラムはアドレス0x0000からマップしてあげればうごくはず。。）

void main(void){}

gcc -O0 -m32 -Wl,-static -nostdlib test.c -T リンカスクリプトファイル名

動的リンクさせると実行時リンカ？とかのせいでセクション増えてややこしくなるので静的にリンクさせます。  
スタートアップルーチン、標準ライブラリは使わないので-nostdlibで禁止にさせる。

リンクスクリプトはコマンド ld --verboseで取得します。

リンカスクリプトにてエントリポイントが_startに設定されているのでmainに書き換えます。  
（実行環境によるみたいですが私のCentOSだと  
_start()→__libc_start_main()→main()の順番で呼ばれる）

これでコンパイル＆リンクができるようになります。

では、、、

ld --verboseで取得したリンカスクリプトを改造していきます。

やりたいこと

1： .text,:data,:bss,:rodataセクションが前からアドレス0からマップされる前提でリンクさせたい。  
逆にこれら以外のセクションはいらないのでそのように設定します。

こちらが設定後のファイル（長いので一部）

[code]

    ENTRY(main)
    SEARCH_DIR("=/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
    SECTIONS
    {
      /* Read-only sections, merged into text segment: */
      PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x000000)); . = SEGMENT_START("text-segment", 0x000000);
      .interp         : {}
      .note.gnu.build-id : {}
      .hash           : { }
      .gnu.hash       : {  }
      .dynsym         : { }
      .dynstr         : { }
      .gnu.version    : { }
      .gnu.version_d  : { }
      .gnu.version_r  : {}
      .rela.dyn       :{}
      .rela.plt       :{    }
      .init           :
      {
      }
      .plt            : {  }
    .plt.got        : {  }
    .plt.sec        : { }
      .text           :
      {
        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
        *(.text.exit .text.exit.*)
        *(.text.startup .text.startup.*)
        *(.text.hot .text.hot.*)
        *(.text .stub .text.* .gnu.linkonce.t.*)
        /* .gnu.warning sections are handled specially by elf32.em.  */
        *(.gnu.warning)
      }
      .fini           :  {}
      /*PROVIDE (__etext = .);
      PROVIDE (_etext = .);
      PROVIDE (etext = .);*/
      .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
      .rodata1        : { *(.rodata1) }
      .eh_frame_hdr : {  }
      .eh_frame       : ONLY_IF_RO { }
      .gcc_except_table   : ONLY_IF_RO { }
      .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
      /* These sections are generated by the Sun/Oracle C++ compiler.  */
      .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
      .exception_ranges*) }
      /* Adjust the address for the data segment.  We want to adjust up to
         the same address within the page on the next page up.  */
    
      . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
    
      /* Exception handling  */
    //  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
    //  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
    //  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
    //  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
      /* Thread Local Storage sections  */
      .tdata      : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
      .tbss       : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
      .preinit_array     :
      {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(.preinit_array))
        PROVIDE_HIDDEN (__preinit_array_end = .);
      }
      .init_array     :
      {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
        KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
        PROVIDE_HIDDEN (__init_array_end = .);
      }
      .fini_array     :
      {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
        KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
        PROVIDE_HIDDEN (__fini_array_end = .);
      }
      .ctors          :
      {
    
      }
      .dtors          :
      {
        KEEP (*crtbegin.o(.dtors))
        KEEP (*crtbegin?.o(.dtors))
        KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
        KEEP (*(SORT(.dtors.*)))
        KEEP (*(.dtors))
      }
      .jcr            : { KEEP (*(.jcr)) }
      .data.rel.ro : {  }
      .dynamic        : { }
      .got            : { }
    /*  . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, . );*/
      .got.plt        : { *(.got.plt)  *(.igot.plt) }
      .data           :
      {
        *(.data .data.* .gnu.linkonce.d.*)
        SORT(CONSTRUCTORS)
      }
      .data1          : { *(.data1) }
      _edata = .; PROVIDE (edata = .);
      . = .;
      __bss_start = .;
      .bss            :
      {
       *(.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);
      }
    
    
[/code]

例）.gnu.hash : { }

いらないセクションはリンク時に無視するように設定しました。  
こんな感じでできるだけ削っています。

では、先程提示したコマンドを使ってコンパイル＆リンクしてreadelfで  
各セクションを見てきます。

[code]

        [root@localhost sample]# readelf -S a.out
    There are 12 section headers, starting at offset 0x200360:
    
    セクションヘッダ:
      [番] 名前              タイプ           アドレス          オフセット
           サイズ            EntSize          フラグ Link  情報  整列
      [ 0]                   NULL             0000000000000000  00000000
           0000000000000000  0000000000000000           0     0     0
      [ 1] .text             PROGBITS         0000000000000024  00200024
           0000000000000007  0000000000000000  AX       0     0     1
      [ 2] .rodata           PROGBITS         000000000000002c  0020002c
           0000000000000004  0000000000000000   A       0     0     4
      [ 3] .data             PROGBITS         0000000000200080  00200080
           0000000000000004  0000000000000000  WA       0     0     4
      [ 4] .bss              NOBITS           0000000000200084  00200084
           0000000000000004  0000000000000000  WA       0     0     4
      [ 5] .comment          PROGBITS         0000000000000000  00200084
           000000000000002c  0000000000000001  MS       0     0     1
      [ 6] .eh_frame         PROGBITS         0000000000000048  00200048
           0000000000000038  0000000000000000   A       0     0     8
      [ 7] .note.gnu.build-i NOTE             0000000000000000  00200000
           0000000000000024  0000000000000000   A       0     0     4
      [ 8] .eh_frame_hdr     PROGBITS         0000000000000030  00200030
           0000000000000014  0000000000000000   A       0     0     4
      [ 9] .symtab           SYMTAB           0000000000000000  002000b0
           00000000000001e0  0000000000000018          10    15     8
      [10] .strtab           STRTAB           0000000000000000  00200290
           0000000000000064  0000000000000000           0     0     1
      [11] .shstrtab         STRTAB           0000000000000000  002002f4
           0000000000000068  0000000000000000           0     0     1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
      L (link order), O (extra OS processing required), G (group), T (TLS),
      C (compressed), x (unknown), o (OS specific), E (exclude),
      l (large), p (processor specific)
    
    
[/code]

（前提が長くなりました すみません。。。）

ここから質問です。

1：

readelfの表示で出ている”アドレス”とはそのセクションが配置されるべきアドレスですよね。  
.textセクションのアドレスには0x24と書かれてます。  
これはtextセクションをアドレス0x24から配置しないといけないものだと思われますが  
なぜ0x00ではなく0x24になっているのですか？  
.textセクションより前に定義されているnullセクションやらのサイズは0となっています。  
ならば、.textの配置アドレスが0となるべきなのでは、、、と思ったのですが  
（nullが実際にメモリにマップするセクションなのかよく知りませんが、、、）

2：bssセクションのアドレスが0x20000になっていますが  
なんでいきなりぶっとんだ場所になっているのでしょう？  
（リンカスクリプトでそのようにするような設定がある？）

3：  
.textと.rodataの開始アドレス  
.text 0x24  
.rodata 0x2c

.textのサイズが7だから0x24 + 7 = 0x2B。。。  
0x2cになりませんね。この謎の1バイトの差はなんですか？

どうしても分からないので教えていただけると大変たすかります。


CC BY-SA 4.0
2020-12-14T18:24:57.377
72656
2020-12-15T00:17:33.610
2020-12-15T00:17:33.610
37492
37492
question
c centos virtualbox gcc
リンカスクリプト を利用して各セクションの開始アドレスを指定したい