gccで本当に使われているデフォルトリンカスクリプトを手に入れる。
結論
ld --verbose
ではなく、gcc -Wl,--verbose
を使いましょう。
環境
$ gcc --version gcc (Ubuntu 8.2.0-7ubuntu1) 8.2.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ld --version GNU ld (GNU Binutils for Ubuntu) 2.31.1 Copyright (C) 2018 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or (at your option) a later version. This program has absolutely no warranty.
$ ld --verbose
というようなコマンドを実行するとデフォルトリンカスクリプトが手に入る。というような記述をしばしば見かけます。(リンカ・ローダ実践開発テクニックとか)
このスクリプトを指定して生成した実行バイナリと、リンカスクリプトを指定しないで生成した実行バイナリは等しいものになると思いますよね?
という訳で、得られたリンカスクリプト*1 (default.ldsとします。)を用いて、以下を実行します。
$ gcc -o hoge hoge.c $ gcc -o hoge_with_lds hoge.c -T default.lds $ diff hoge hoge_with_lds Binary files hoge and hoge_with_lds differ
実行結果が期待通りにならない...
恐らくld --verbose
で得たリンカスクリプトが違うんだろう... *2
ではどうすれば実際に使われているスクリプトを得られるかというと、コンパイル時に-Wlオプションを使って、直接リンカに--verboseオプションを渡すとうまくいきます。
$ gcc -Wl,--verbose
これで得られたスクリプトを用いて再度コンパイル&差分を確認すると、無事差分がなくなりました。
ちなみに実際のスクリプトの差を確認したら以下のようになりました。
$ diff default.lds default_gcc.lds
1c1 < /* Script for -z combreloc -z separate-code: combine and sort reloc sections with separate code segment */ --- > /* Script for -pie -z combreloc -z now -z relro -z separate-code: position independent executable, combine & sort relocs with separate code segment */ 14c14 < PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; --- > PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS; 155,157c155,156 < .got : { *(.got) *(.igot) } < . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); < .got.plt : { *(.got.plt) *(.igot.plt) } --- > .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } > . = DATA_SEGMENT_RELRO_END (0, .); 240a240 >
どうやら オプションごとにデフォルトリンカスクリプトは異なるらしい。
gccコマンドを使用して入手した方は -pie -z combreloc ...
向けみたいですね。
そういえば、ある時から(確かUbuntuでは)位置独立実行形式(PIE)がデフォルトになったと聞いた気がするな...