strong_alias && weak_alias && __attribute__
为了查看linux下malloc的实现函数,下载了Glibc的源码文件,可是找不到实现的函数在哪里。
看文件名 应该是在malloc/malloc.c里面。
发现__libc_malloc的实现比较像。
怎么从malloc到__libc_malloc的呢?
看到文件里有一个语句
有点苗头
来看看strong_alias的实现
_typeof (name) aliasname 就是定义别名的意思了 至于后面的__attribute__看下面的解释。
GNU C的一大特色(却不被初学者所知)就是__attribute__机制。
__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)
__attribute__前后都有两个下划线,并且后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数
__attribute__语法格式为:
__attribute__ ( ( attribute-list ) )
函数属性(Function Attribute),函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
__attribute__机制也很容易同非GNU应用程序做到兼容。
GNU CC需要使用 –Wall,这是控制警告信息的一个很好的方式。
就这样定义了malloc的是__libc_malloc的别名,__malloc也是__libc_malloc的别名。
__attribute__((alias))
variable attributeThis variable attribute enables you to specify multiple aliases for variables.
Where a variable is defined in the current translation unit, the alias reference is replaced by a reference to the variable, and the alias is emitted alongside the original name. Where a variable is not defined in the current translation unit, the alias reference is replaced by a reference to the real variable. Where a variable is defined as static, the variable name is replaced by the alias name and the variable is declared external if the alias is declared external.
Note
Function names might also be aliased using the corresponding function attribute
__attribute__((alias))
.Syntax
typenewname
__attribute__((alias("oldname
")));Where:
oldname
is the name of the variable to be aliased
newname
is the new name of the aliased variable.
Example
#include <stdio.h> int oldname = 1; extern int newname __attribute__((alias("oldname"))); // declaration void foo(void) {printf("newname = %d\n", newname); // prints 1 }
还存在一种weak_alias的概念,对比strong_alias,就是展开的时候多了个__attribute__里多了个weak
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]# <span
class
=
"wp_keywordlink_affiliate"
><a href=
"http://lenky.info/tag/gcc/"
title=
"查看 gcc 中的全部文章"
>gcc</a></span> -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修饰符仅针对静态库产生影响。