【追記】さらにその後,「『7f454c46 01010100 00000000 00000000』の時点でelfファイルであることは判るが,Linuxで作られたかは0x0114バイトは見ないと判らないはず,この人は『バイナリ萌え』ではない!」との突っ込みを頂きました.
0xcafebabe の話を知った大学生の頃,危うくバイナリ萌えの暗黒面に落ちそうになったものの,軽うじて生還して今は普通人として暮らしています.
というわけでバイナリ萌えでない私にとっては,上の「Linuxで作られたかは0x0114バイトは見ないと判らない」はすごく不思議だった.だって ELF って 8 バイト目に OS/ABI あるじゃん.で,ELFOSABI_LINUX (= 0x03) って定義されてるじゃん.そこ見ればいいんじゃないの?
…と思って手近にあった Vine Linux に転がっているバイナリを調べてみると,8 バイト目は軒並 0x00 なのであった.0x00 は ELFOSABI_NONE であり ELFOSABI_SYSV である.で,確かに readelf すると
% readelf -a /bin/ls | grep OS/ABI OS/ABI: UNIX - System V
と表示されるのであった.むー.
さてそれではどうやって Linux のものだと判定すればよいのか,そしてそれはなぜ「0x0114バイトは見ないと判らない」のか,ちょっと調べてみることにした.
調べたのは file コマンド.
% file /bin/ls /bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1, for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
てな感じで Linux だと判定してくれるので,きっと何か手がかりがあるだろう.
というわけで FreeBSD の /usr/src/contrib/file/readelf.c あたりを眺めてみると,donote() の中で判定しているようだ.ELF のプログラムヘッダのうち NOTE タイプのものを探して,その先頭 Elf32_Nhdr サイズ分 (ただし 32 ビット ELF の場合.定義は file/readelf.h の中で,実際のサイズは 12 バイト) スキップしたところに 'G', 'N', 'U', '\0' という 4 バイトがあることを確認し,その次の 1 バイトを調べている.そこが 0x00 だったら GNU/Linux であるという判定をしているようだ.ちなみにそこに出てくる値としては
#define GNU_OS_LINUX 0 #define GNU_OS_HURD 1 #define GNU_OS_SOLARIS 2
が定義されている.ちょwww HURD って単語久々にみたわwwwwwwwww
NOTE タイプのプログラムヘッダがどこにあるかというと,
% readelf -a /bin/ls (略) Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align (略) NOTE 0x000108 0x08048108 0x08048108 0x00020 0x00020 R 0x4 (略)
てな感じになっていて,先頭からのオフセット 0x108 バイトのところから始まるらしい.ここから Elf32_Nhdr 分の 12 バイト進んだ 0x114 の,さらに 'G', 'N', 'U', '\0' の分の 4 バイト進んだところ,つまりオフセット 0x118 バイトのところを見るとようやく Linux かどうかがわかる,という仕組みのようだ.実際に見てみると,
% hexdump -c /bin/ls | grep ^0000110 0000110 001 \0 \0 \0 G N U \0 \0 \0 \0 \0 002 \0 \0 \0
となる.うーん,なるほど.
ついでに書いとくと,NOTE タイプのプログラムヘッダは必ずしも 0x108 から始まるわけじゃなくて,例えば /bin/rpm なんかは
NOTE 0x000094 0x08048094 0x08048094 0x00020 0x00020 R 0x4
なのであった.つまりオフセット 0xa4 (= 0x94 + 12 + 4) を見る必要があるってことでいいかな?
% hexdump -c /bin/rpm | grep ^00000a0 00000a0 G N U \0 \0 \0 \0 \0 002 \0 \0 \0 002 \0 \0 \0
よさげである.
というわけで,どうやら「Linuxで作られたかは0x0114バイトは見ないと判らないはず,この人は『バイナリ萌え』ではない!」という突っ込みもバイナリ萌えとしてはまだツメが甘いようです.うーむ,バイナリアン恐るべし.ついて行けん.
で,最初の話に戻るんですが,これらのファイルってどうして OS/ABI に ELFOSABI_LINUX を使わないんでしょう? 逆に言うと ELFOSABI_LINUX ってどういうときに使われてるんでしょう? 教えて偉い人.
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12
2002 : 01 02 03 04 05 06 07 08 09 10 11 12
2001 : 01 02 03 04 05 06 07 08 09 10 11 12
2000 : 01 02 03 04 05 06 07 08 09 10 11 12
1999 : 01 02 03 04 05 06 07 08 09 10 11 12
1998 : 01 02 03 04 05 06 07 08 09 10 11 12
1997 : 01 02 03 04 05 06 07 08 09 10 11 12
1996 : 01 02 03 04 05 06 07 08 09 10 11 12
最終更新時間: 2012-02-13 02:02
* [baby touch] 『あまり使われないのは、システムコールとかの"実装"に依存し... (2007-11-06 21:15:48)