Apple ldのalias_listオプションの挙動が良く分かりません
本エントリで何がしたいか
Appleのldは、リンカスクリプトを受け取る事が出来ません。(多分…)
ところで、リンカスクリプト中のシンボル同士の代入を用い、シンボルのrenamingをしたいといった事は稀に良くあることだと思うのですが、じゃあリンカスクリプト使えない時にそれをどうしましょう…という話を書いています。
Apple ldにはaliasとalias_listという「それっぽい」オプションがあるのでこれを使えば動くのではないかなーと思うのですが、どうも上手く動かないように思われるケースがあるので以下に記します。
% gcc --version i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3) Copyright (C) 2007 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.
の元で以下コンパイルしています。
h.h
struct In { int i; }; struct S { struct In in; int d; };
lib1.c
#include "h.h" #include <stdio.h> #include <assert.h> extern struct S lib1_s; extern struct In lib1_in; void f(int v) { puts("-- f --"); printf("&lib1_s = %p\n",&lib1_s); printf("&lib1_in = %p\n",&lib1_in); printf("lib1_s.in.i = %d\n",lib1_s.in.i); printf("lib1_in.i = %d\n",lib1_in.i); printf("lib1_s.d = %d\n",lib1_s.d); assert(v == lib1_s.d); }
main.c
#include "h.h" #include <stdio.h> struct S main_s; struct In main_in; extern void f(int); int main() { main_in.i = 42; main_s.in = main_in; main_s.d = 84; printf("&main_s = %p\n",&main_s); printf("&main_in = %p\n",&main_in); f(main_s.d); return 0; }
alias_listオプションを使いつつ、実行可能ファイルを作ります
いや、そもそもalias_listオプションて何?という話ですね。
man ld(あと、http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/ld.1.html) から抜粋すると
-alias symbol_name alternate_symbol_name Create an alias named alternate_symbol_name for the symbol symbol_name. By default the alias symbol has global visibility. This option was previous the -idef:indir option. -alias_list filename The specified filename contains a list of aliases. The symbol name and its alias are on one line, separated by whitespace. Lines starting with # are ignored.
今回は、lib1.cのシンボル、lib1_sをmain1_sへ、lib1_inをmain1_inへ書き換えてみよう(特に意味はありませんが)。少なくともassertで死ぬ事はないでしょう。という考えです。
次のようなファイルを作り、alias_listと共にgccに渡します。
#alias _main_s _lib1_s _main_in _lib1_in
% gcc -Wall -c -g -O0 main.c lib1.c % gcc main.o lib1.o -Wl,-alias_list,alias % ./a.out &main_s = 0x10000107c &main_in = 0x100001078 -- f -- &lib1_s = 0x100001078 &lib1_in = 0x100001078 lib1_s.in.i = 42 lib1_in.i = 42 lib1_s.d = 42 Assertion failed: (v == lib1_s.d), function f, file lib1.c, line 18. zsh: abort ./a.out
ギョエピー!!!!
Linuxでリンカスクリプトを使ってやってみる
% gcc --version gcc 4.4.3 % ld --version GNU ld 2.20.1-system.20100303
次のようなリンカスクリプトを準備
lib1_s = main_s; EXTERN(main_s); lib1_in = main_in; EXTERN(main_in);
EXTERNが本当にこの例で必要かどうかは分かりませんが…。
さて、今度はldがリンカスクリプトを受け取れるのでこれを使って生成してあげると
% gcc -Wall -c -g -O0 main.c lib1.c % gcc main.o lib1.o linker.script % ./a.out &main_s = 0x804a024 &main_in = 0x804a02c -- f -- &lib1_s = 0x804a024 &lib1_s.in = 0x804a024 &lib1_in = 0x804a02c lib1_s.in.i = 42 lib1_in.i = 42 lib1_s.d = 84
とこっちでは上手く動いている事が分かります。