実行ファイル中のデータ領域は、見た目には何の区切りも構造もない。しかし、Load Commandsを見ると幾つかの領域に区分けされているのが分かる。segmentとsectionはその区分けの単位だ。segmentはメモリにマップするときに使用する単位であり、1つないし複数のsectionを内包している。sectionは使用目的ごとに区分けされた領域である。
例えば、__TEXTというsegmentには、「__TEXT,__text」と「__TEXT,__cstring」という2つのsectionがある。この2つのsectionは__TEXTセグメントとしてまとめてメモリ上にマップされる*が、それぞれ役割が異なり前者のsectionはCPUによって実行されるコードが、後者のsectionには文字列定数が格納されている。
Load Commandsでは実行ファイルの任意のオフセットを指定でき、原理的には複数のアーキテクチャで同一のsegmentを共有することは可能である。しかし、少なくとも現在のMac OS Xのld*はsegmentやsectionを共有することでファイルサイズを節約するといったことはせず、アーキテクチャにかかわらず同じデータでもCPUの種別ごとに毎回segment、sectionを作成し格納している(実行例4)。
% cat main.c
#include <stdio.h>
int main()
{
printf("hello, world\n");
}
% grep -abc "hello, world" a.out
2
マップはあくまでディスク上のセクタと仮想メモリ上のアドレスを関連づけるだけであり、マップされたからといって実メモリに即ロードされるわけではないことに注意。また、仮想メモリのページングはこのsegmentやsectionといった区分に関係なく、PowerPCなら4KB、x86なら8KBの固定サイズのページごと行われる。
CコンパイラとしてはGCCを、アセンブラとしてはgasを利用しているが、ldだけはbinutilsのldではなくMach由来のldを利用している。これは、Mach-OやMAB(Universal Binary)を正しく扱うためだ。
Copyright © ITmedia, Inc. All Rights Reserved.