静态库
静态库的链接过程
#include <cstdio>
void foo();
extern int b; //foo函数和b的定义都在libh.a里
int main() {
foo();
int a = b;
foo();
return b;
}
编译成目标文件:g++ a.cc -g -c -o a.o
反汇编查看汇编代码:objdump -dS a.o
0000000000000000 <main>:
#include <cstdio>
void foo();
extern int b;
int main() {
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 83 ec 10 sub $0x10,%rsp
foo();
c: e8 00 00 00 00 callq 11 <main+0x11>
int a = b;
11: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 17 <main+0x17>
17: 89 45 fc mov %eax,-0x4(%rbp)
foo();
1a: e8 00 00 00 00 callq 1f <main+0x1f>
return b;
1f: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 25 <main+0x25>
}
25: c9 leaveq
26: c3 retq
先看两次调用foo()
函数,汇编代码地址0xc
的位置:callq 11
,0x11
是callq 11
的下一行位置。再看地址0x1a
:callq 1f
,0x1f
也是下一行位置。因为这时不知函数foo()
的定义在哪,所以暂时用callq
指令的下一个指令的位置代替。
再看引用变量b
的时候:mov 0x0(%rip)
,也是用下一个指令的地址代替还没有找到定义的b
。
再看与库链接后的汇编代码:
0000000000001189 <main>:
#include <cstdio>
void foo();
extern int b;
int main() {
1189: f3 0f 1e fa endbr64
118d: 55 push %rbp
118e: 48 89 e5 mov %rsp,%rbp
1191: 48 83 ec 10 sub $0x10,%rsp
foo();
1195: e8 16 00 00 00 callq 11b0 <_Z3foov>
int a = b;
119a: 8b 05 70 2e 00 00 mov 0x2e70(%rip),%eax # 4010 <b>
11a0: 89 45 fc mov %eax,-0x4(%rbp)
foo();
11a3: e8 08 00 00 00 callq 11b0 <_Z3foov>
return b;
11a8: 8b 05 62 2e 00 00 mov 0x2e62(%rip),%eax # 4010 <b>
}
11ae: c9 leaveq
11af: c3 retq
00000000000011b0 <_Z3foov>:
11b0: f3 0f 1e fa endbr64
11b4: 55 push %rbp
11b5: 48 89 e5 mov %rsp,%rbp
11b8: 48 8d 35 46 0e 00 00 lea 0xe46(%rip),%rsi
看地址0x1195
和0x119a
就知道,链接后函数foo()
的地址在0x11b0
,变量b
的地址在0x4010
的位置。
编译成目标文件(未链接)
g++ -c a.cc b.cc c.cc d.cc
#生成 a.o b.o c.o d.o
将目标文件打包为静态库
ar rs libxxx.a a.o b.o c.o d.o
#选项'r'表示将后边的文件列表添加到文件包,如果不存在就创建它,如果文件包中已有同名文件就替换成新的。
#选项's'是专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用。
#库名以lib开头
将库和主程序编译链接在一起
g++ main.cc -L. -lxxx -I. -o main
#'-L' 后接静态库的目录
#'-l' 后接静态库名称(去掉lib和.a。如:libxxx.a就写xxx)
#'-I' 后接头文件目录
查找路径
g++ -print-search-dirs #查看
install: /usr/lib/gcc/i486-linux-gnu/4.3.2/
programs: =/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/
libraries: =/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/
编译器会在这些路径和-L
指定的路径中查找-l
指定的库,比如-lxxx
编译器会先查找有没有libxxx.so
,如果有就链接它,如果没有就查找静态库。所以编译器是优先考虑共享库的,如果希望只链接静态库,可以指定-static
选项。