質問: 0x0000000000600e10 + 0x230 ``` ですが、文字通りにとれば、DATAセグメントが0x0000000000601040で終わるとすると、その下のDYNAMICセグメントの開始アドレス0x0000000000600e28と被ってしまうはずです。 ELFはどのようにメモリにロードされているのでしょうか? よろしくお願いします。
回答: 1つ目の質問ですが、実メモリ上のdataセグメントの開始アドレスは、`ld`で使われるデフォルトのリンカースクリプトの指定で並べ替えられているようです。こちらのブログの記事を読ませていただいて、分かり易かったので案内させていただきます。 ELF実行ファイルのメモリ配置はどのように決まるのか 私の環境(Ubuntu 17.04 64ビット)でも `ld --verbose`でリンカースクリプトを確認したところ、全内容の精査まではしていないものの、それっぽくなっていました。 以下の指摘事項ですが、 > > 図2の3行目では開始アドレスは0x006010000となっており、ELFファイルが保持する情報と一致していない > > > (※0x00601000 の間違いですよね?)これはOracleのサイトでのELFの説明(ただし、Solaris/SunOS用)にヒントとなる記述がありました。 Program Header (Linker and Libraries Guide) ここの「Base Address」の節で、以下の記述があります。 > > To compute the base address, you determine the memory address associated with the lowest p_vaddr value for a PT_LOAD segment. You then obtain the base address by truncating the memory address to the nearest multiple of the maximum page size. Depending on the kind of file being loaded into memory, the memory address might not match the p_vaddr values. > > > この文の後半、You then obtain...の文で「メモリアドレスの最大のページサイズの倍数に切り捨てることでベースアドレスを取得できる。メモリーにロードされたファイルの種類によっては、メモリーアドレスはp_vaddr の値に合致しない」とのことです。linuxのページサイズは4KiB(0x1000)なので、その倍数単位でベースアドレスになっていることに合致します。 また、android のlibcの代替であるCランタイムbionic のローダーのコード中の説明で、 linker/linker_phdr.cpp - platform/bionic > > Finally, the real load addrs of each segment is not p_vaddr. Instead the > > loader decides where to load the first segment, then will load all others > > relative to the first one to respect the initial range layout. > > > との記述があります。いずれもlinux 64ビット版そのものではないですが、メモリ上にセグメントを割り当てる上でページサイズは意識せざるを得ないでしょうから、ELF形式の実行ファイルのローダーの挙動として参考になるかと思います。 まとめると、`Elf64_Phdr->p_vaddr` は 0x00600e10 なのに 実アドレス 0x00601000 からロードされるのは、ページサイズを意識した境界にローダーが配置する為で、更になぜ 0x00601000なのかと言えば、リンカースクリプトでそのように指定しているから、と言うことが言えるかと思います。