linux 静态库与共享库

本文笔记学习自《Professional Assembly Language》

静态库

当我们将不同的函数写在不同的文件中,如果主程序调用这些函数,就需要相应的目标文件才能生成可执行文件。目标文件很多的话,不便于管理。我们可以将目标文件整合到一个存档文件中,编译器从存档文件挑选出需要的目标文件,这样的存档文件称之为库文件(library file)。
假设库文件的目标代码被编译到了主程序中,就称之为静态库文件(windows下对应着LIB文件)。
linux下有ar工具可以创建静态库文件。

ar - create, modify, and extract from archives
ar [--plugin name] [-X32_64] [-]p[mod [relpos] [count]] archive [member...]

以计算圆的面积areafunc.s进行说明。
areafunc.s:

.section .text
.type areafunc,@function
.globl areafunc
areafunc:
pushl %ebp         
movl %esp,%ebp        #store esp register
fldpi                 #store PI at st(0)
filds 8(%ebp)         #store first parameter at st(0) and PI moved to st(1)          
fmul %st(0),%st(0)    
fmul %st(1),%st(0)    #make sure st(0) has current anwser.
movl %ebp,%esp
popl %ebp
ret 

areafunc.c:

#include <stdio.h>

float areafunc(int);
int main(){
    float result;
    result = areafunc(1);
    printf("result is %f\n",result);

    result = areafunc(10);
    printf("result is %f\n",result);
    return 0;
}

生成目标文件 gcc -c areafunc.s -o areafunc.o
linux操作系统下的静态库文件通常命名为libx.a,x是自己的文件命名,.a表示这是一个静态库文件。
使用ar生成库文件liball.a:
下面我用所有的.o文件生成一个库文件。

[edemon@CentOS workspace]$ ls *.o
areafunc.o  area.o  ftest.o  movl.o  mov.o  quadtest.o
[edemon@CentOS workspace]$ ar -r liball.a *.o
ar: creating liball.a
[edemon@CentOS workspace]$ file liball.a
liball.a: current ar archive
[edemon@CentOS workspace]$ ar -t liball.a 
areafunc.o
area.o
ftest.o
movl.o
mov.o
quadtest.o

创建索引提高连接速度: ranlib liball.a
再介绍一个工具nm

nm - list symbols from object files
nm [-a|--debug-syms]
          [-g|--extern-only][--plugin name]
          [-B] [-C|--demangle[=style]] [-D|--dynamic]
          [-S|--print-size] [-s|--print-armap]
          [-A|-o|--print-file-name][--special-syms]
          [-n|-v|--numeric-sort] [-p|--no-sort]
          [-r|--reverse-sort] [--size-sort] [-u|--undefined-only]
          [-t radix|--radix=radix] [-P|--portability]
          [--target=bfdname] [-fformat|--format=format]
          [--defined-only] [-l|--line-numbers] [--no-demangle]
          [-V|--version] [-X 32_64] [--help]  [objfile...]

可查看函数所在文件位置

[edemon@CentOS workspace]$ nm -s liball.a 

Archive index:
areafunc in areafunc.o
area in area.o
main in ftest.o
_start in movl.o
_start in mov.o
_start in quadtest.o

areafunc.o:
00000000 T areafunc

area.o:
00000000 T area

ftest.o:
         U area
00000000 T main
00000000 d precision
00000002 d report

movl.o:
00000000 T _start
00000000 d value

mov.o:
00000000 T _start

quadtest.o:
00000000 T _start
00000000 d data1
00000014 d data2

使用静态库进行编译:

[edemon@CentOS workspace]$ gcc areafunc.c liball.a -o areafunc
[edemon@CentOS workspace]$ ./areafunc 
result is 3.141593
result is 314.159271

因为gcc是提取所需函数代码得到可执行文件,所以areafunc的大小并不会因为使用库文件编译而变大。

[edemon@CentOS workspace]$ gcc areafunc.c areafunc.o -o areafunc1
[edemon@CentOS workspace]$ du -h areafunc areafunc1
8.0K    areafunc
8.0K    areafunc1

共享库

和静态库文件不同,有一类存档文件的目标代码不被编译到可执行文件中,主程序不用把函数代码加入它的内存空间,这类存档文件称之为共享库文件。
Linux操作系统的命名格式为libx.so,其中x是自己的文件命名,.so表明这是共享库(windows下对应着DLL文件)。
静态编译(将函数代码连接到可执行文件)得到的可执行文件,我们使用objdump进行反汇编,可以查看函数调用的痕迹。
以areafunc为例:

[edemon@CentOS workspace]$ objdump -D areafunc > read
[edemon@CentOS workspace]$ vim read
#查找含有areafunc的地方:/areafunc
345  8048432:   e8 65 00 00 00          call   804849c <areafunc>

359  8048462:   e8 35 00 00 00          call   804849c <areafunc>

379 0804849c <areafunc>:
380  804849c:   55                      push   %ebp
381  804849d:   89 e5                   mov    %esp,%ebp
382  804849f:   d9 eb                   fldpi
383  80484a1:   df 45 08                fild   0x8(%ebp)
384  80484a4:   d8 c8                   fmul   %st(0),%st
385  80484a6:   d8 c9                   fmul   %st(1),%st
386  80484a8:   89 ec                   mov    %ebp,%esp
387  80484aa:   5d                      pop    %ebp
388  80484ab:   c3                      ret

以共享库编译方式得到的可执行文件是不含有函数代码的。
共享库编译方式shell> gcc sourcefile -Ldir -llibname -o executefile
-L 告诉编译器库文件在哪个位置(假设不在系统定义的位置)
-l 后跟上库的名字(x)
生成共享库文件:

[edemon@CentOS workspace]$ gcc -shared -o libshared.so areafunc.o  area.o  ftest.o
[edemon@CentOS workspace]$ file libshared.so 
libshared.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped

生成可执行文件:

[edemon@CentOS workspace]$ gcc -o areafunc2 -L. -lshared areafunc.c
[edemon@CentOS workspace]$ ./areafunc2
result is 3.141593
result is 314.159271

再次反汇编,查找函数areafunc的踪迹:

[edemon@CentOS workspace]$ objdump -D areafunc2 > read
[edemon@CentOS workspace]$ vim read

361 08048440 <areafunc@plt>:
362  8048440:   ff 25 b8 98 04 08       jmp    *0x80498b8
363  8048446:   68 10 00 00 00          push   $0x10
364  804844b:   e9 c0 ff ff ff          jmp    8048410 <_init+0x30>

505  80485a2:   e8 99 fe ff ff          call   8048440 <areafunc@plt>

519  80485d2:   e8 69 fe ff ff          call   8048440 <areafunc@plt>

可以发现,函数的代码并没有在这份反汇编后的文件中。
ldd可查看依赖的共享库:

[edemon@CentOS workspace]$ ldd areafunc2
    linux-gate.so.1 =>  (0x00bb1000)
    libshared.so (0x00395000)
    libc.so.6 => /lib/libc.so.6 (0x00397000)
    /lib/ld-linux.so.2 (0x001ee000)

可执行文件需要Linux动态加载器(/lib/ld-linux.so.2)自动加载所需的函数。
假设动态加载器找不到库文件的位置,怎么办?
系统文件/etc/ld.so.conf含有定位共享库文件位置的信息,我们改变它(增添位置信息),再使用ldconfig更新。还有一种添加库文件位置信息的方法,就是更改LD_LIBRARY_PATH变量,例如:

[edemon@CentOS workspace]$ echo $LD_LIBRARY_PATH 
/home/edemon/workspace/
[edemon@CentOS workspace]$ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/edemon/"
[edemon@CentOS workspace]$ echo $LD_LIBRARY_PATH 
/home/edemon/workspace/:/home/edemon/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值