首页 > *nix技术, 应用程序, 跟踪调试 > gcc中的weak和alias

gcc中的weak和alias

2013年1月20日 发表评论 阅读评论 13,862 次浏览

在看glibc源代码的时候,能看到很多对函数的属性修饰,比如weak_alias(注:我当前看的是2.17版本的glibc源代码)宏里的weak和alias:

/* Define ALIASNAME as a weak alias for NAME.
   If weak aliases are not available, this defines a strong alias.  */
# define weak_alias(name, aliasname) _weak_alias (name, aliasname)
# define _weak_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));

glibc里一个实际的gettimeofday()应用

#else

# include <sysdep.h>
# include <errno.h>

int
__gettimeofday (struct timeval *tv, struct timezone *tz)
{
  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
}
libc_hidden_def (__gettimeofday)

#endif
weak_alias (__gettimeofday, gettimeofday)
libc_hidden_weak (gettimeofday)

对于weak、alias以及另外一个同类属性weakref,先来看官方介绍

alias (“target”)
The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified. For instance,

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias (“__f”)));

defines `f’ to be a weak alias for `__f’. In C++, the mangled name for the target must be used. It is an error if `__f’ is not defined in the same translation unit.

Not all target machines support this attribute.
weak
The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.
weakref
weakref (“target”)
The weakref attribute marks a declaration as a weak reference. Without arguments, it should be accompanied by an alias attribute naming the target symbol. Optionally, the target may be given as an argument to weakref itself. In either case, weakref implicitly marks the declaration as weak. Without a target, given as an argument to weakref or to alias, weakref is equivalent to weak.

static int x() __attribute__ ((weakref (“y”)));
/* is equivalent to… */
static int x() __attribute__ ((weak, weakref, alias (“y”)));
/* and to… */
static int x() __attribute__ ((weakref));
static int x() __attribute__ ((alias (“y”)));

A weak reference is an alias that does not by itself require a definition to be given for the target symbol. If the target symbol is only referenced through weak references, then the becomes a weak undefined symbol. If it is directly referenced, however, then such strong references prevail, and a definition will be required for the symbol, not necessarily in the same translation unit.

The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.

At present, a declaration to which weakref is attached can only be static.

貌似已经解释得很清楚了,如下:
alias:表示当前符号是另外一个(目标target)符号的别称。比如:

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));

alias修饰的是符号f,指定的目标符号是__f,也就是说符号f是符号__f的别称。

weak:表示当前符号是个弱类型符号(weak symbol),而非全局符号。看个示例:
1,首先,准备一个库文件(以静态库为例,后文将提到为什么不以动态库为例):

[root@localhost weak_test1]# cat /etc/issue
CentOS release 6.2 (Final)
Kernel \r on an \m

[root@localhost weak_test1]# uname -a
Linux localhost.localdomain 2.6.32-220.el6.i686 #1 SMP Tue Dec 6 16:15:40 GMT 2011 i686 i686 i386 GNU/Linux
[root@localhost weak_test1]# vi mylib.c
[root@localhost weak_test1]# cat !$
cat mylib.c
#include <stdio.h>

void foo()
{
    printf("lib test\n");
}

void foo() __attribute__ ((weak));
[root@localhost weak_test1]# gcc -c mylib.c
[root@localhost weak_test1]# ar crv libmylib.a mylib.o
a - mylib.o

可以看到libmylib.a库里定义了一个函数foo(),并且是weak弱类型。

2,编写一个应用程序(由两个源文件myapp.c与myfoo.c构成):

[root@localhost weak_test1]# vi myapp.c
[root@localhost weak_test1]# cat !$
cat myapp.c
#include <stdio.h>

int main()
{
    foo();
    return 0;
}
[root@localhost weak_test1]# vi myfoo.c 
[root@localhost weak_test1]# cat !$
cat myfoo.c
#include <stdio.h>

void foo()
{
    printf("app test\n");
}

源文件myfoo.c调用的foo()函数可以来自libmylib.a库,也可以来自应用程序的另外一个源文件,连接并执行:

[root@localhost weak_test1]# gcc myapp.c myfoo.c libmylib.a -o myapp_weak
[root@localhost weak_test1]# ./myapp_weak 
app test

打印显示的是app test,即调用的是应用程序自身的函数foo()。

3,如果应用程序本身不提供函数foo(),那么情况是怎样:

[root@localhost weak_test1]# gcc myapp.c libmylib.a -o myapp
[root@localhost weak_test1]# ./myapp
lib test

打印显示的是lib test,即调用了libmylib.a库里的weak弱类型函数foo()。

4,试试去掉库里的weak修饰:

[root@localhost weak_test1]# vi mylib.c 
[root@localhost weak_test1]# cat mylib.c 
#include <stdio.h>

void foo()
{
    printf("lib test\n");
}

//void foo() __attribute__ ((weak));
[root@localhost weak_test1]# gcc -c mylib.c;ar crv libmylib.a mylib.o
r - mylib.o
[root@localhost weak_test1]# gcc myapp.c myfoo.c libmylib.a -o myapp
[root@localhost weak_test1]# ./myapp
app test

去掉weak修饰后也没问题?那weak属性到底有啥用?试试把libmylib.a放前面:

[root@localhost weak_test1]# gcc myapp.c libmylib.a myfoo.c -o myapp
/tmp/ccIjvazY.o: In function `foo':
myfoo.c:(.text+0x0): multiple definition of `foo'
libmylib.a(mylib.o):mylib.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
[root@localhost weak_test1]# gcc libmylib.a myapp.c myfoo.c -o myapp
[root@localhost weak_test1]# gcc libmylib.a myfoo.c myapp.c -o myapp
[root@localhost weak_test1]# gcc myfoo.c libmylib.a myapp.c -o myapp
[root@localhost weak_test1]# gcc myfoo.c myapp.c libmylib.a -o myapp

对比一下,加上weak修饰:

[root@localhost weak_test1]# vi mylib.c
[root@localhost weak_test1]# cat mylib.c
#include <stdio.h>

void foo()
{
    printf("lib test\n");
}

void foo() __attribute__ ((weak));
[root@localhost weak_test1]# gcc -c mylib.c;ar crv libmylib.a mylib.o
r - mylib.o
[root@localhost weak_test1]# gcc myapp.c libmylib.a myfoo.c -o myapp
[root@localhost weak_test1]# gcc libmylib.a myapp.c myfoo.c -o myapp
[root@localhost weak_test1]# gcc libmylib.a myfoo.c myapp.c -o myapp
[root@localhost weak_test1]# gcc myfoo.c libmylib.a myapp.c -o myapp
[root@localhost weak_test1]# gcc myfoo.c myapp.c libmylib.a -o myapp
[root@localhost weak_test1]# ./myapp
app test

去掉weak修饰后,只有一个杯具的报错了,难道是和库文件排放位置相关?不用库函数,直接用源代码试试:

[root@localhost weak_test1]# vi mylib.c 
[root@localhost weak_test1]# cat mylib.c 
#include <stdio.h>

void foo()
{
    printf("lib test\n");
}

//void foo() __attribute__ ((weak));
[root@localhost weak_test1]# gcc myapp.c myfoo.c mylib.c -o myapp
/tmp/ccbKVCYU.o: In function `foo':
mylib.c:(.text+0x0): multiple definition of `foo'
/tmp/cc3DKEyS.o:myfoo.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
[root@localhost weak_test1]# gcc myapp.c mylib.c myfoo.c -o myapp
/tmp/ccosX9JJ.o: In function `foo':
myfoo.c:(.text+0x0): multiple definition of `foo'
/tmp/ccyyg6us.o:mylib.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

报错(必然的),加上:

[root@localhost weak_test1]# vi mylib.c
[root@localhost weak_test1]# cat mylib.c 
#include <stdio.h>

void foo()
{
    printf("lib test\n");
}

void foo() __attribute__ ((weak));
[root@localhost weak_test1]# gcc myapp.c myfoo.c mylib.c -o myapp
[root@localhost weak_test1]# gcc myapp.c mylib.c myfoo.c -o myapp

啥结论?看来weak修饰符的原本含义是让weak弱类型的函数可以被其它同名函数覆盖(即不会发生冲突),如果没有其它同名函数,就使用该weak函数,类似于是默认函数;
但是,受到“库”这一特别存在的影响,weak弱类型对库变得“不太可靠”了,而且根据Weak definitions aren’t so weak来看,对于新版本的glibc,weak修饰符仅针对静态库产生影响。

weakref:可以说是weak与alias的结合版本(见上面英文引用),但在当前,被weakref修饰的符号必须是static的。

转载请保留地址:http://www.lenky.info/archives/2013/01/2195http://lenky.info/?p=2195


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.