忘れないうちにメモ
Linuxで普通に実行ファイルつくると.commentセクションとデバッグインフォメーションの
二箇所にコンパイラのバージョンが入ってる。これはobjdumpやreadelfで観測できる。
なぜこんなテクニックを知る必要があるかというとバグ報告で嘘のコンパイラバージョンを
報告してくる輩はけしてレアではないからである
1つめ。.comment セクションを objdumpで表示
これはCentOS 6.4 でコンパイルした、ただの Hello World プログラム。
なんでバージョンが複数出てくるかというと、一般に実行ファイルには
コンパイル時にいくつかのcrtファイルが静的リンクされるのだが、
それらは、OSのマイナー版アップ時にgccバージョンが上がった時に、
リコンパイルされないことが多いので、a.outとずれちゃうんだね。
一般に一番新しいバージョンが a.out のコンパイルに使われたもので
それ以外はリンクされてるcrtをコンパイルしたときのもの。
つぎ、readelfでdebug info読んだもの。こっちのほうがストレートに
a.outの情報だけが出てきて便利。ただし、デバッグ情報必要なので
使えない時はつかえない。
ところで、gccがどうやって .commentセクションに書き込んでいるか調べたのだが、これが結構面白い
gcc -s hello.c すると、以下の様なアセンブリソースが現れる。
ここで、 .identという pseudo assembler directiveを使っていることがわかった。
マニュアルを見ると
http://www.sourceware.org/binutils/docs-2.12/as.info/Ident.html#Ident
なんて書いてあるが、なに、うそっぱちである。信じてはいけない。
ためしに、ここに Gachapin here!! とか書くと
のように、.commentセクションに文字列が増えたことが確認できる。
(gcc 4.4.7 の文字列が消えないのは 4.4.7でコンパイルされてるcrtも含んでいるため)
なお、リンクされてる crt一覧をとりたいときは以下のようにする
備忘録なので特に結論はない
Linuxで普通に実行ファイルつくると.commentセクションとデバッグインフォメーションの
二箇所にコンパイラのバージョンが入ってる。これはobjdumpやreadelfで観測できる。
なぜこんなテクニックを知る必要があるかというとバグ報告で嘘のコンパイラバージョンを
報告してくる輩はけしてレアではないからである
1つめ。.comment セクションを objdumpで表示
% objdump -s -j .comment a.out
a.out: file format elf64-x86-64
Contents of section .comment:
0000 4743433a 2028474e 55292034 2e342e36 GCC: (GNU) 4.4.6
0010 20323031 32303330 35202852 65642048 20120305 (Red H
0020 61742034 2e342e36 2d342900 4743433a at 4.4.6-4).GCC:
0030 2028474e 55292034 2e342e37 20323031 (GNU) 4.4.7 201
0040 32303331 33202852 65642048 61742034 20313 (Red Hat 4
0050 2e342e37 2d332900 .4.7-3).
これはCentOS 6.4 でコンパイルした、ただの Hello World プログラム。
なんでバージョンが複数出てくるかというと、一般に実行ファイルには
コンパイル時にいくつかのcrtファイルが静的リンクされるのだが、
それらは、OSのマイナー版アップ時にgccバージョンが上がった時に、
リコンパイルされないことが多いので、a.outとずれちゃうんだね。
一般に一番新しいバージョンが a.out のコンパイルに使われたもので
それ以外はリンクされてるcrtをコンパイルしたときのもの。
つぎ、readelfでdebug info読んだもの。こっちのほうがストレートに
a.outの情報だけが出てきて便利。ただし、デバッグ情報必要なので
使えない時はつかえない。
% readelf -wi a.out | grep -i producer
< c> DW_AT_producer : (indirect string, offset: 0x0): GNU C 4.4.7 20120313 (Red Hat 4.4.7-3)
ところで、gccがどうやって .commentセクションに書き込んでいるか調べたのだが、これが結構面白い
gcc -s hello.c すると、以下の様なアセンブリソースが現れる。
.file "hello.c"
.section .rodata
.LC0:
.string "hello"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
.section .note.GNU-stack,"",@progbits
ここで、 .identという pseudo assembler directiveを使っていることがわかった。
マニュアルを見ると
http://www.sourceware.org/binutils/docs-2.12/as.info/Ident.html#Ident
.ident
This directive is used by some assemblers to place tags in object files. as simply accepts the directive for source-file compatibility with such assemblers, but does not actually emit anything for it.
なんて書いてあるが、なに、うそっぱちである。信じてはいけない。
ためしに、ここに Gachapin here!! とか書くと
% objdump -s -j .comment a.out
a.out: file format elf64-x86-64
Contents of section .comment:
0000 4743433a 2028474e 55292034 2e342e36 GCC: (GNU) 4.4.6
0010 20323031 32303330 35202852 65642048 20120305 (Red H
0020 61742034 2e342e36 2d342900 4743433a at 4.4.6-4).GCC:
0030 2028474e 55292034 2e342e37 20323031 (GNU) 4.4.7 201
0040 32303331 33202852 65642048 61742034 20313 (Red Hat 4
0050 2e342e37 2d332900 47616368 6170696e .4.7-3).Gachapin
0060 20686572 65212100 here!!.
のように、.commentセクションに文字列が増えたことが確認できる。
(gcc 4.4.7 の文字列が消えないのは 4.4.7でコンパイルされてるcrtも含んでいるため)
なお、リンクされてる crt一覧をとりたいときは以下のようにする
gcc hello.c -Wl,-t
/opt/rh/devtoolset-2/root/usr/libexec/gcc/x86_64-redhat-linux/4.8.0/ld:
mode elf_x86_64
/usr/lib/../lib64/crt1.o
/usr/lib/../lib64/crti.o
/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.0/crtbegin.o
/tmp/ccfPagMG.o
/lib64/libgcc_s.so.1
/lib64/libc.so.6
(/usr/lib64/libc_nonshared.a)elf-init.oS
/lib64/ld-linux-x86-64.so.2
/lib64/libgcc_s.so.1
/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.0/crtend.o
/usr/lib/../lib64/crtn.o
備忘録なので特に結論はない
- 関連記事
-
- glibc history git (2013/12/21)
- a.out からコンパイラバージョンを取得する方法 (2013/11/26)
- ioctl の man page が fix された (2013/11/18)
ちょうど今日ヤボ用 .ident って実際なにするんだろーと思ってたんで大変タイムリーでした。うそっぱち、ってのは "does not actually emit anything for it" がということでしょうか。たしかに大変微妙な記述な気がしますけど、前文と矛盾しないように解釈すると、「現在指定されてるセクションには何も書かれないよ」って意味としか取れないような気がするので、最悪ではないような気もします。
2013-11-27 水 10:41:56 |
URL |
shinh #sqCyeZqA [ 編集]
あれ、そういう意味なのか。てっきり、どっかヨソのアセンブラは意味のあるtagをemitするけどgasは構文としては受け付けるけどなんもしねーよ。って主張してるのかと思ってました。
英語わからなくてすいません。
英語わからなくてすいません。
2013-11-27 水 17:06:43 |
URL |
kosaki #- [ 編集]
いややっぱりその文章は元の kosaki さんの解釈で正しいような気しかしませんね…こちらこそすいません。
最近の binutils だとずいぶん正しい記述になってるみたいです。
sourceware.org/binutils/docs-2.23.1/as/Ident.html#Ident
最近の binutils だとずいぶん正しい記述になってるみたいです。
sourceware.org/binutils/docs-2.23.1/as/Ident.html#Ident
2013-11-28 木 12:25:23 |
URL |
shinh #sqCyeZqA [ 編集]