忘れないうちにメモ
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


備忘録なので特に結論はない