Windows与Linux动态链接库技术的对比

Windows与Linux动态链接库区别概述

Windows与Linux对动态链接库的实现虽然思想相同,但是使用方式却有些不同。下表总结了这一区别。


linux gcc
windows vc

生成静态库
gcc -c calc.c -o calc.o
ar  rcs libcalc.a calc.o

cl /c calc.c
lib /OUT:calc.lib calc.obj



使用静态库
gcc test.c libcalc.a -o test
gcc test.c -L. -lcalc -o test

cl test.c calc.lib
gcc 有-l选项可以以它要求的名称查找库。
生成动态库
gcc -c calc.c -o calc.o
gcc -shared calc.c -o libcalc.so

cl /c calc.c
link /DLL calc.obj

lib /DLL /def:calc.def /OUT:calc.lib
linux下动态链接库的符号信息包含在so文件当中,Windows虽然在dll和生成的lib当中都包含一份符号表信息,但是链接的时候只可使用lib当中的符号。
使用动态库
gcc test.c ./libcalc.so
gcc test.c libcalc.so 错误
gcc test.c -L. -lcalc -o test


cl test.c calc.lib
cl test.c calc.dll 错误


静态链接库与动态链接库混合使用
gcc main.c -Wl,-Bstatic-lcalc -Wl,-Bdynamic -lm
gcc main.c ./libcalc.a -lm
cl test.c a.lib b.lib
windows无论链接动态库还是静态库都指定lib即可,在选择使用动态连接还是静态链接的时候由代码当中的__declspec(dllimport)决定,这句代码要求一个符号必须使用动态链接库

库的名称约束
静态库以libname.a方式命名。
动态库以libname.so方式命名。
若不遵循这两个规则,那么gcc -l选项便无法找到指定的库。
静态库以 name .lib方式命名。
动态库以 name .dll方式命名。
动态库符号文件 name .lib方式命名
linux下对动态链接库和静态链接库的名称要求以lib开头(当然也可以不必以lib开头),而Windows则无此约定。


Linux链接库的使用

测试程序如下:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /*calc.c*/  
  2. int val = 10;  
  3. static int inner_val = 20;  
  4. int Add(int a,int b)  
  5. {  
  6.     return a + b;  
  7. }  


  1. /*test.c*/  
  2. #include <stdio.h>  
  3.   
  4. extern int val;  
  5. extern int Add(int a,int b);  
  6.   
  7. int main()  
  8. {  
  9.     printf("val:%d\n",val);  
  10.     printf("4 + 4:%d\n",Add(4,4));  
  11.   
  12.     return 0;  
  13. }  


静态链接库的使用

生成可重定向文件

gcc创建静态链接库的方式如下,这并不局限于Linux,如在Cygwin下也是如此。

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $gcc -c calc.c -o calc.o  


在C语言当中被static修饰的变量或函数是私有的,因为在calc.c当中val与Add符号未被static修饰,所以可以在任意的其它模块当中使用val变量或调用Add函数,这意味着val变量是全局的,它的值可以被任何链接到它的一个模块更改。我们可以通过readelf查看calc.o的符号信息,从中可以看出inner_val被LOCAL修饰,而val和Add被GLOBAL修饰。

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $ readelf -s calc.o  
  2.   
  3. Symbol table '.symtab' contains 11 entries:  
  4.    Num:    Value  Size Type    Bind   Vis      Ndx Name  
  5.      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND  
  6.      1: 00000000     0 FILE    LOCAL  DEFAULT  ABS calc.c  
  7.      2: 00000000     0 SECTION LOCAL  DEFAULT    1  
  8.      3: 00000000     0 SECTION LOCAL  DEFAULT    2  
  9.      4: 00000000     0 SECTION LOCAL  DEFAULT    3  
  10.      5: 00000004     4 OBJECT  <span style="color:#ff0000;">LOCAL  </span>DEFAULT    2 inner_val  
  11.      6: 00000000     0 SECTION LOCAL  DEFAULT    5  
  12.      7: 00000000     0 SECTION LOCAL  DEFAULT    6  
  13.      8: 00000000     0 SECTION LOCAL  DEFAULT    4  
  14.      9: 00000000     4 OBJECT  <span style="color:#ff0000;">GLOBAL </span>DEFAULT    2 val  
  15.     10: 00000000    13 FUNC    <span style="color:#ff0000;">GLOBAL </span>DEFAULT    1 Add  

创建归档文件

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $ar rcs libcalc.a calc.o  
静态链接库将可重定向目标文件(.o文件)以特定的格式压缩在一起,从而解决.o文件管理混乱的问题,下面的命令可以查看.a文件当中包含了哪些.o文件。

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ar -t /usr/lib/i386-linux-gnu/libc.a  
  2. init-first.o  
  3. libc-start.o  
  4. sysdep.o  
  5. version.o  
  6. check_fds.o  
  7. libc-tls.o  
  8. elf-init.o  
  9. ...  
也可以查看.a文件当中每个.o文件的符号信息

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. $ nm /usr/lib/i386-linux-gnu/libc.a | head -200  
  2.   
  3. init-first.o:  
  4.          U abort  
  5.          U __ctype_init  
  6.          U _dl_fpu_control  
  7.          U _dl_non_dynamic_init  
  8. 00000090 T _dl_start  
  9.          w _dl_starting_up  
  10.          U __environ  
  11.          U __fpu_control  
  12.          U __init_misc  
  13. 00000004 C __libc_argc  
  14. 00000004 C __libc_argv  
  15. 00000000 T __libc_init_first  
  16.          U __libc_init_secure  
  17. 00000000 D __libc_multiple_libcs  
  18.          U __setfpucw  
  19.   
  20. libc-start.o:  
  21.          U __assert_fail  
  22.          U __cxa_atexit  
  23.          U _dl_aux_init  
  24.          U _dl_discover_osversion  
  25.          U _dl_osversion  
  26. ...  


使用静态链接库

使用方式一,显式链接

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. gcc test.c ./libcalc.a -o test  
使用方式二,隐式链接

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. gcc test.c -L. -static -lcalc -o test  
使用显式链接的时候我们不用关心静态链接库的名称问题,但是对于隐式链接必须遵从gcc对链接库的名称要求:静态库:lib name .a,动态库lib name .so。

隐式链接静态库的时候必须指定-static选项,若没有指定-static选项,gcc在链接的时候使用动态链接库的算法进行链接,这虽然不会出报错,但是在程序执行的时候实际其会要求加载libcalc.so,由于我们没有libcalc.so,所以程序无法执行。

另外,我们可以更改一下程序以验证上面提到的使用static修饰的变量不可被外部模块链接的说法。这里不做示例。

在链接静态库的时候还有一个陷阱需要注意。由于gcc链接的时候内部算法约束,参数的传递顺序对链接的成功起至关重要。上面的例子当中使用如下方式链接会报错。

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. gcc ./libcalc.a test.c -o test  

动态链接库的使用

创建动态链接库

众所周知,动态链接库的一个主要目的是允许多个正在运行的进程共享存储器中相同的库代码,因而解决宝贵的存储器资源。gcc创建一个动态链接库十分简单,并没有像VC一样单独导出一个可链接的符号文件(见Windows下动态链接库的使用),我们可以在main.c代码当中使用任何非static修饰的变量或函数。

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. gcc -shared calc.c -o libcalc.so  
另外,我们可以查看生成的动态库当中可链接的动态符号表,当我们的程序由于某个符号找不到无法链接的时候可以通过这个手段进行确认。
[plain]  view plain copy print ?
  1. $ readelf -s libcalc.so  
  2.   
  3. Symbol table '<span style="color:#ff0000;">.dynsym</span>' contains 13 entries:  
  4.    Num:    Value  Size Type    Bind   Vis      Ndx Name  
  5.      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND  
  6.      1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab  
  7.      2: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (2)  
  8.      3: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__  
  9.      4: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses  
  10.      5: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable  
  11.      6: 00002020     0 NOTYPE  GLOBAL DEFAULT   21 _edata  
  12.      7: 00002018     4 OBJECT  GLOBAL DEFAULT   21 val  
  13.      8: 00002024     0 NOTYPE  GLOBAL DEFAULT   22 _end  
  14.      9: 00002020     0 NOTYPE  GLOBAL DEFAULT   22 __bss_start  
  15.     10: 0000050b    13 FUNC    GLOBAL DEFAULT   11 Add  
  16.     11: 00000380     0 FUNC    GLOBAL DEFAULT    9 _init  
  17.     12: 00000518     0 FUNC    GLOBAL DEFAULT   12 _fini  
  18.   
  19. Symbol table '<span style="color:#ff0000;">.symtab</span>' contains 56 entries:  
  20.    Num:    Value  Size Type    Bind   Vis      Ndx Name  
  21.     ...  
  22.     38: 00000000     0 FILE    LOCAL  DEFAULT  ABS  
  23.     39: 000003e0     4 FUNC    LOCAL  DEFAULT   11 __x86.get_pc_thunk.bx  
  24.     40: 00002014     0 OBJECT  LOCAL  DEFAULT   21 __dso_handle  
  25.     41: 00001f0c     0 OBJECT  LOCAL  DEFAULT   18 _DYNAMIC  
  26.     42: 00002020     0 OBJECT  LOCAL  DEFAULT   21 __TMC_END__  
  27.     43: 00002000     0 OBJECT  LOCAL  DEFAULT   20 _GLOBAL_OFFSET_TABLE_  
  28.     44: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab  
  29.     45: 00002020     0 NOTYPE  GLOBAL DEFAULT   21 _edata  
  30.     46: 00000518     0 FUNC    GLOBAL DEFAULT   12 _fini  
  31.     47: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.1  
  32.     48: 00002018     4 OBJECT  GLOBAL DEFAULT   21 val  
  33.     49: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__  
  34.     50: 00002024     0 NOTYPE  GLOBAL DEFAULT   22 _end  
  35.     51: 00002020     0 NOTYPE  GLOBAL DEFAULT   22 __bss_start  
  36.     52: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses  
  37.     53: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable  
  38.     54: 0000050b    13 FUNC    GLOBAL DEFAULT   11 Add  
  39.     55: 00000380     0 FUNC    GLOBAL DEFAULT    9 _init  
上面打印的信息当中.dynsym段包含了其它应用程序可以使用的符号信息,.symtab包含了该动态链接库当中所有可用的符号信息,其是.dynsym的超集。

使用动态链接库

第一种方式,显式链接

[plain]  view plain copy print ?
  1. gcc test.c ./libcalc.so  

第二种方式,隐式链接

[plain]  view plain copy print ?
  1. gcc test.c -L. -lcalc -o test  
使用显式链接十分方便,但是你需要明确知道动态链接库的位置,另外下面的链接方法是错误的 。

[plain]  view plain copy print ?
  1. $ gcc test.c libcalc.so -o test  
  2. $ ./test  
  3. ./test: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory  
  4. $  

文章转自:http://blog.csdn.net/p569354158/article/details/45241933
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值