好记性不如铅笔头

编程

【C语言】函数默认实现和用户自定义实现编程方法 — 【weak, strong alias】

本文转自【 https://blog.csdn.net/lida2003/article/details/51198194 】,有删改。

函数默认实现和用户自定义实现
这里介绍几种方式,供大家实现时参考:
Reference code(示例代码)
Pointer operation(指针操作)
Weak & Strong Alias(强弱别名)
1.Reference code(示例代码)
这个比较简单,也就是开发代码的时候将一段代码以示例的方式写好。然后用户直接复制源代码,然后进行修改,实现用户的自定义方式。
优点:最为直接的一种代码Demo方式,开发人员很容易接受
缺点:开发人员需要对示例代码进行检查,至少需要review代码,确保正确性。

2.Pointer operation(指针操作)
实现方法通过指针操作进行定位函数入口,当函数指针未被赋值就是原默认实现方法,当用户对其进行赋值,即运行用户自定义方法。
优点:常用方法,已经被广泛使用,尤其是Linux内核及驱动开发,基本采用这种方式。
缺点:指针操作要小心。

3.Weak & Strong Alias(强弱别名)
这个是编译链接的时候进行的操作,类似于对象默认方法,当没有自定义的方法时,链接到默认的方法实现,如果有实现方法(Strong Alias)的时候就采用强别名。
优点:默认方法不用关心,只要关心需要实现的方法。
缺点:默认实现方法被隐藏(如果不注意的话),更像高级应用,只开发自己关心的内容,其他都由框架完成。

由于前两种方式大家都较为熟悉,这里就简单介绍下Weak & Strong Alias的基本依据和应用方法。

CONTENTS

Weak & Strong Alias的基本依据

GCC手册中关于Weak & Strong Alias的介绍如下,大意就是强属性链接权限高于弱属性,一个函数符号优先链接的是强属性符号而非弱属性。
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. 

Weak & Strong Alias自定义函数验证

//libtest_weak.c
#include <stdio.h>
void fun()
{
    printf("weak test\n");
}
void fun() __attribute__ ((weak));

//test_strong.c
#include <stdio.h>
void fun()
{
    printf("strong test\n");
}

接下来,编译默认weak实现库和测试weak和stong的可执行文件 

# gcc -c libtest_weak.c
# ar crv libtest_weak.a libtest_weak.o
# gcc -o test_weak main.c libtest_weak.a
# gcc -o test main.c test_strong.c libtest_weak.a

最后,执行输出结果

# ./test_weak
weak test
# ./test
strong test

 从上述对比结果,我们可以看出,没有strong symbol的时候,链接器将fun链接到了weak symbol上,输出“weak test”,当我们增加test_strong.c实现了fun函数后,链接器就链接了strong symbol。

Weak & Strong Alias库打包差异

我们对上述libtest_weak.c和test_strong.c(修改文件名为libtest_strong.c)进行库打包

# gcc -c libtest_weak.c
# ar crv libtest_weak.a libtest_weak.o
# gcc -c libtest_strong.c
# ar crv libtest_strong.a libtest_strong.o

分析.a文件,可以看到fun符号,在libtest_weak.a中是“W”,而在libtest_strong.a中是“T”,链接器将会优先考虑“T”

# nm -s libtest_weak.a

Archive index:
fun in libtest_weak.o

libtest_weak.o:
0000000000000000 W fun
                 U puts

# nm -s libtest_strong.a

Archive index:
fun in libtest_strong.o

libtest_strong.o:
0000000000000000 T fun
                 U puts

 strong、weak符号链接优先级

修改源文件分别如下所示:

//libtest_strong.c
#include <stdio.h>
void fun()
{
    printf("libtest_strong test\n");
}

//libtest_weak.c
#include <stdio.h>
void fun()
{
    printf("libtest_weak test\n");
}
void fun() __attribute__ ((weak));

//test_strong.c
#include <stdio.h>
void fun()
{
    printf("test_strong.c test\n");
}

//test_weak.c
#include <stdio.h>
void fun()
{
    printf("test_weak.c test\n");
}
void fun() __attribute__ ((weak));

//test_weak2.c
#include <stdio.h>
void fun()
{
    printf("test_weak2.c test\n");
}
void fun() __attribute__ ((weak));

 对代码进行组合编译链接:

# gcc -c libtest_weak.c
# ar crv libtest_weak.a libtest_weak.o
# gcc -c libtest_strong.c
# ar crv libtest_strong.a libtest_strong.o

.c(strong)与.a(weak),优先链接 .c

# gcc -o test_strong_libweak main.c test_strong.c libtest_weak.a
# gcc -o test_libweak_strong main.c libtest_weak.a test_strong.c 
# ./test_strong_libweak
test_strong.c test
# ./test_libweak_strong
test_strong.c test

.c(strong)与.a(strong),.c先链接,strong符号与.a冲突,以.c为准
.c(strong)与.a(strong),.a先链接,strong符合与.c冲突,链接失败

# gcc -o test_strong_libstrong main.c test_strong.c libtest_strong.a
# gcc -o test_libstrong_strong main.c libtest_strong.a test_strong.c 
/tmp/cceiDAEw.o: In function `fun':
test_strong.c:(.text+0x0): multiple definition of `fun'
libtest_strong.a(libtest_strong.o):libtest_strong.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
# ./test_strong_libstrong
test_strong.c test
# ./test_libstrong_strong
-bash: ./test_libstrong_strong: No such file or directory

.c(weak)与.a(weak),.a和.c哪个先链接,weak符号先起作用

# gcc -o test_weak_libweak main.c test_weak.c libtest_weak.a
# gcc -o test_libweak_weak main.c libtest_weak.a test_weak.c
# ./test_weak_libweak
test_weak.c test
# ./test_libweak_weak
libtest_weak test

.c(weak)与.a(strong),.c先链接,以.c为准
.c(weak)与.a(strong),.a先链接,以.a为准

# gcc -o test_weak_libstrong main.c test_weak.c libtest_strong.a
# gcc -o test_libstrong_weak main.c libtest_strong.a test_weak.c
# ./test_weak_libstrong
test_weak.c test
# ./test_libstrong_weak
libtest_strong test

.c(strong)与.c(weak),.c编译链接过程,strong符号可以覆盖weak符号

# gcc -o test_weak_strong main.c test_weak.c test_strong.c
# gcc -o test_strong_weak main.c test_strong.c test_weak.c 
# ./test_weak_strong
test_strong.c test
# ./test_strong_weak
test_strong.c test

.c(strong)与.c(strong),.c编译链接过程,strong符号重复,链接失败

# gcc -o test_strong_strong main.c test_strong.c test_strong2.c
/tmp/cc3c8J5H.o: In function `fun':
test_strong2.c:(.text+0x0): multiple definition of `fun'
/tmp/ccy49Mpb.o:test_strong.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

.c(weak)与.c(weak),.c编译链接过程,先链接的weak符号优先考虑

# gcc -o test_weak_weak2 main.c test_weak.c test_weak2.c
# gcc -o test_weak2_weak main.c test_weak2.c test_weak.c
# ./test_weak_weak2
test_weak.c test
#./test_weak2_weak
test_weak2.c test

 

发表评论

17 − 15 =

此站点使用 Akismet 来减少垃圾评论。了解我们如何处理您的评论数据