ldにおける変更

ldを使ってシンボルの置き換えをしているわけですが、これまで手元のバージョン(ld 2.20.1-system.20100303)だと、次のような振舞をしていました。

/* test.c */
extern int a;

int main()
{
  printf("a = %d\n",a);
  return 0;
}
/* def_b.c */
int b = 42;
/* lscript */
a = b;
EXTERN(b);

上記3つのファイルが在る時に

ld --version
GNU ld (GNU Binutils for Ubuntu) 2.20.1-system.20100303                      
Copyright 2009 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では

gcc -c test.c def_b.c -- test.oとdef_b.oを作る
ld -r test.o def_b.o lscript -o partial.o
nm partial.o

00000000 D a     
00000000 D b     
00000000 T main  
U printf

ldのr(relocatable)オプションについてはここ( http://www.kpitgnutools.com/manuals/ld.html#IDX88 )などを。

ところが、ldの比較的新しいバージョン(以下はbinutilsから取って来た)

./ld-new --version
GNU ld (GNU Binutils) 2.21                                                   
Copyright 2010 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を使うと、

./ld-new -r lscript def_b.o test.o -o partial2.o

00000000 A a     
00000000 D b     
00000000 T main  
U printf

このようにシンボルaが絶対アドレスを取るように成ってしまいます。

partial2.oはこの後問題が発生して

gcc partial.o -o exe1
./exe1 => 42

gcc partial2.o -o exe2
./exe2 => Segmantation Fault

nm exe2
  00000000 A a
  0804a014 D b

となります。この変更はどの段階で入ったんでしょうかっていうのが。。。

ldに対するrオプションが本質的では恐らくなくて、例えば

gcc lscript test.o def_b.o -- ただしこのgccはリンク時に新しいldを使うものとする
nm a.out
0804a014 A a
0804a014 D b

となるんですね。だから、リンカスクリプトの解釈が変わったんじゃないかなーという。

少なくとも、ld 2.20.51-system.20100908からはこうなってますね。