Apple ldのalias_listオプションの挙動が良く分かりません その2

前回に引き続き。

% 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.
% ld -v
@(#)PROGRAM:ld  PROJECT:ld64-97.17
llvm version 2.9svn, from Apple Clang 1.7 (build 77)

次の4ファイルを準備してそれに対してalias_listオプションを使ってみます。

/* h.h */
struct S {
    int *i;
};
/* main.c */
#include "h.h"
#include <stdio.h>

extern int i;
struct S bar = { &i };

extern void check(struct S*);

int main()
{
    printf("*bar.i = %d\n",*bar.i);

    check(&bar);
    return 0;
}
/* lib.c */
#include "h.h"
#include <stdio.h>
#include <assert.h>

extern struct S hogefuga;

void check(struct S *p)
{
    printf("*(p->i) = %d\n",*(p->i));
    printf("*hogefuga.i = %d\n",*hogefuga.i);

    assert(p == &hogefuga);
}
/* define_i.c */
int i = 42;

さて、今回は、lib.cの"hogefuga"シンボルを、main.cの"bar"シンボルへとリネームするべく、alias_listオプションに渡すファイルを次のように書きます。

% cat alias
_bar _hogefuga

これを使って2バージョンのコンパイルをします。

% gcc -Wall -c main.c lib.c
% gcc -Wall -c define_i.c
% gcc -shared define_i.o -o define_i.so
% gcc -o static main.o lib.o define_i.o -Wl,-alias_list,alias
% gcc -o shared main.o lib.o define_i.so -Wl,-alias_list,alias
% nm static
0000000100000ee2 s  stub helpers
0000000100001050 D _NXArgc
0000000100001058 D _NXArgv
                 U ___assert_rtn
0000000100000ea7 s ___func__.2336
0000000100001068 D ___progname
0000000100000000 A __mh_execute_header
0000000100001070 D _bar
0000000100000e0d T _check
0000000100001060 D _environ
                 U _exit
0000000100001070 D _hogefuga
0000000100001078 D _i
0000000100000ddc T _main
                 U _printf
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000da0 T start

これは上手くいきそうですね!!

% nm shared
0000000100000ee2 s  stub helpers
0000000100001058 D _NXArgc
0000000100001060 D _NXArgv
                 U ___assert_rtn
0000000100000ea7 s ___func__.2336
0000000100001070 D ___progname
0000000100000000 A __mh_execute_header
0000000100001050 D _bar <-
0000000100000e0d T _check
0000000100001068 D _environ
                 U _exit
0000000100001078 D _hogefuga <-
                 U _i
0000000100000ddc T _main
                 U _printf
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000da0 T start

!? 2つのシンボルのアドレスが異なっています…。

% ./static
*bar.i = 42
*(p->i) = 42
*hogefuga.i = 42
% ./shared
*bar.i = 42
*(p->i) = 42
zsh: segmentation fault  ./shared

やはりsharedの方は失敗しました。

ちなみに、リンカスクリプトが渡せるldでは次のように書き

hogefuga = bar;
EXTERN(bar);

EXTERNが必要かどうかは分かりませんが…、同様にコンパイルしてあげるとどちらも正しく動きます。