Mac OS X上的弱符号链接

11

目前我在Mac OS X 10.6.7和Xcode 4.0.2上遇到了一个弱链接的问题。

$ gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

根据开发者文档,我们可以使用gcc attribute((weak_import))来进行弱连接符号。

然而,以下示例代码总是会抛出编译错误,如下所示:

weak.c:

#include <stdlib.h>
#include <stdio.h>

extern int SayHello() __attribute__((weak));

int main()
{
    int result;

    if (SayHello!=NULL)
    {
        printf("SayHello is present!\n");
        result=SayHello();
    }
    else
        printf("SayHello is not present!\n");
}

错误信息如下:

$ gcc weak.c 
Undefined symbols for architecture x86_64:
  "_f", referenced from:
      _main in cceOf2wN.o
     (maybe you meant: __dyld_func_lookup)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

即使使用选项 -undefined dynamic_lookup,在运行时仍会抛出错误:

$ gcc -undefined dynamic_lookup weak.c 
$ ./a.out 
dyld: Symbol not found: _SayHello
  Referenced from: /private/tmp/o/./a.out
  Expected in: dynamic lookup

Trace/BPT trap

nm -m 命令对于 "a.out" 文件的输出如下:

$ nm -m a.out  | grep Hello

(undefined) external _SayHello (dynamically looked up)

如下所预期的:

(undefined) weak external _SayHello (dynamically looked up)

然而,在Ubuntu上使用gcc编译(Ubuntu/Linaro 4.4.4-14ubuntu5)4.4.5时,它按预期工作:

weak.c:

#include <stdlib.h>
#include <stdio.h>

extern int SayHello() __attribute__((weak));

int main()
{
    int result;

    if (SayHello!=NULL)
    {
        printf("SayHello is present!\n");
        result=SayHello();
    }
    else
        printf("SayHello is not present!\n");
}

 

$ gcc weak.c 
$ ./a.out 
SayHello is not present!

SayHello 的二进制符号为:

$ nm a.out | grep Hello
w SayHello

"w" 符号是一个未被标记为弱对象符号的弱符号。

我测试了旧版的Xcode 3.2,结果符合预期。

有谁可以帮我解决这个问题吗?这是ld的一个bug吗?

我发现更有趣的事情。当我创建一个虚拟库来导出动态库中的SayHello符号时,它的效果就如预期。

dummy.c:

int SayHello() {
    return;
}

 

$ gcc -dynamiclib -o libdummy.dylib dummy.c 
$ gcc weak.c libdummy.dylib 
$ ./a.out 
SayHello is present!

如果"libdummy.dylib"不存在:

$ rm libdummy.dylib 
$ ./a.out 
SayHello is not present!

正常工作!弱符号现在在nm消息中,如预期所示:

$ nm -m a.out | grep Hello

                 (undefined) weak external _SayHello (from libdummy)

你知道XCode使用的是哪个版本的gcc吗?你的答案可能就在那里... - Chris Frederick
1
嗨,Christopher,gcc的版本是i686-apple-darwin10-gcc-4.2.1(GCC)4.2.1(Apple Inc. build 5666)(点3)。我认为这可能是gcc 4.2.1(build 5666)(点3)中ld的一个错误。 - Robin
我遇到了重复符号(typeid(T))的问题,其中T包含在多个编译单元中。只在gcc 4.2.1 (build 5666) (dot 3) (XCode 4)发生,而在gcc 4.2.1 (build 5664) (XCode 3)中没有出现这种情况。我猜想它可能是在星期一构建的... - Tobias
也许是因为你使用了 __attribute__((weak)) 而不是 __attribute__((weak_import))?我正在寻找类似问题的解决方法。 - C0deH4cker
1
实际上,我刚刚发现了似乎是问题所在。 "Xcode <4.5中的链接器忘记在DYLD_INFO数据中将弱引用标记为弱引用。" http://glandium.org/blog/?p=2764 - C0deH4cker
1个回答

0
今天在GCC 12和Clang 14上仍然存在错误,如果没有-undefined dynamic_lookup选项:
Undefined symbols for architecture arm64:
  "_SayHello", referenced from:
      _main in weak-518bb6.o
ld: symbol(s) not found for architecture arm64

但是如果设置了选项,它可以正常工作:

% gcc-12 -undefined dynamic_lookup  -o weak weak.c && ./weak
ld: warning: -undefined dynamic_lookup may not work with chained fixups
SayHello is not present!
% cc -undefined dynamic_lookup  -o weak weak.c && ./weak
ld: warning: -undefined dynamic_lookup may not work with chained fixups
SayHello is not present!

gcc-12 (Homebrew GCC 12.2.0) 12.2.0
Apple clang version 14.0.0 (clang-1400.0.29.102)

C0deH4cker 在评论中提到了这个链接。它详细介绍了问题,包括一些解决方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接