当前位置: 技术问答>linux和unix
为什么gcc可以连接archive中的多个同样的symbol,而没有报multiple definition?
来源: 互联网 发布时间:2016-01-02
本文导语: 1. why gcc can link objs with multiple same symbols after ar? what's the difference between it and linking before ar? 2. If multiple same symbols are allowable when linking, then what's the rule to resolve undefined function call(claimed with "ex...
1. why gcc can link objs with multiple same symbols after ar? what's the difference between it and linking before ar?
2. If multiple same symbols are allowable when linking, then what's the rule to resolve undefined function call(claimed with "extern" before)?
a.c:
extern int f();
int main()
...{
printf("result is %d ",f());
return f();
}
int f()
...{
return 1;
}
b.c:
int f()
...{
return 0;
}
test1:
>gcc -c a.c -o a.o
>nm -s a.o
00000030 T f
00000000 t gcc2_compiled.
00000000 T main
U printf
>gcc -c b.c -o b.o
>nm -s b.o
00000000 T f
00000000 t gcc2_compiled.
>gcc b.o a.o -o main //link failed because of the same global symbols "f"
a.o: In function `f':
a.o(.text+0x30): multiple definition of `f'
b.o(.text+0x0): first defined here
collect2: ld returned 1 exit status
test2:
>ar cr b.a b.o
f in b.o
b.o:
00000000 T f
00000000 t gcc2_compiled.
>ar cr a.a a.o
Archive index:
main in a.o
f in a.o
a.o:
00000030 T f
00000000 t gcc2_compiled.
00000000 T main
U printf
>gcc b.a a.a -o main //link is sucessful!!! what's the difference between it and test1???
> main
result is 1 //why the result is 1???
--------------------------------------------------------------------------------------------------------------------------------------------
a1.c:
extern int f();
int main()
...{
printf("result is %d ",f());
return f();
}
a2.c:
int f()
...{
return 1;
}
b.c:
int f()
...{
return 0;
}
> gcc -c a1.c -o a1.o
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
> gcc -c a2.c -o a2.o
00000000 T f
00000000 t gcc2_compiled.
> gcc -c b.c -o b.o
00000000 T f
00000000 t gcc2_compiled.
> ar cr a2.a a2.o
> nm -s a2.a
Archive index:
f in a2.o
a2.o:
00000000 T f
00000000 t gcc2_compiled.
> ar cr b.a b.o
> nm -s b.a
Archive index:
f in b.o
b.o:
00000000 T f
00000000 t gcc2_compiled.
> ar cr a1.a a1.o
> nm -s a1.a
Archive index:
main in a1.o
a1.o:
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
> ar cr a.a a2.o a1.o
> nm -s a.a
Archive index:
f in a2.o
main in a1.o
a2.o:
00000000 T f
00000000 t gcc2_compiled.
a1.o:
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
test1:
> gcc b.a a.a -o main
> main
result is 1
test2:
> gcc a1.a b.a a2.a -o main0
> gcc a2.a a1.a b.a -o main0
> main0
result is 0 //the result is dependent to link sequence!!!
> gcc a1.a a2.a b.a -o main1
> gcc b.a a1.a a2.a -o main1
> main1
result is 1 //the result is dependent to link sequence!!!
test3:
> gcc b.a a2.a a1.a -main //why this liinking failed???
a1.a(a1.o): In function `main':
a1.o(.text+0xd): undefined reference to `f'
a1.o(.text+0x25): undefined reference to `f'
collect2: ld returned 1 exit status
2. If multiple same symbols are allowable when linking, then what's the rule to resolve undefined function call(claimed with "extern" before)?
a.c:
extern int f();
int main()
...{
printf("result is %d ",f());
return f();
}
int f()
...{
return 1;
}
b.c:
int f()
...{
return 0;
}
test1:
>gcc -c a.c -o a.o
>nm -s a.o
00000030 T f
00000000 t gcc2_compiled.
00000000 T main
U printf
>gcc -c b.c -o b.o
>nm -s b.o
00000000 T f
00000000 t gcc2_compiled.
>gcc b.o a.o -o main //link failed because of the same global symbols "f"
a.o: In function `f':
a.o(.text+0x30): multiple definition of `f'
b.o(.text+0x0): first defined here
collect2: ld returned 1 exit status
test2:
>ar cr b.a b.o
f in b.o
b.o:
00000000 T f
00000000 t gcc2_compiled.
>ar cr a.a a.o
Archive index:
main in a.o
f in a.o
a.o:
00000030 T f
00000000 t gcc2_compiled.
00000000 T main
U printf
>gcc b.a a.a -o main //link is sucessful!!! what's the difference between it and test1???
> main
result is 1 //why the result is 1???
--------------------------------------------------------------------------------------------------------------------------------------------
a1.c:
extern int f();
int main()
...{
printf("result is %d ",f());
return f();
}
a2.c:
int f()
...{
return 1;
}
b.c:
int f()
...{
return 0;
}
> gcc -c a1.c -o a1.o
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
> gcc -c a2.c -o a2.o
00000000 T f
00000000 t gcc2_compiled.
> gcc -c b.c -o b.o
00000000 T f
00000000 t gcc2_compiled.
> ar cr a2.a a2.o
> nm -s a2.a
Archive index:
f in a2.o
a2.o:
00000000 T f
00000000 t gcc2_compiled.
> ar cr b.a b.o
> nm -s b.a
Archive index:
f in b.o
b.o:
00000000 T f
00000000 t gcc2_compiled.
> ar cr a1.a a1.o
> nm -s a1.a
Archive index:
main in a1.o
a1.o:
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
> ar cr a.a a2.o a1.o
> nm -s a.a
Archive index:
f in a2.o
main in a1.o
a2.o:
00000000 T f
00000000 t gcc2_compiled.
a1.o:
U f
00000000 t gcc2_compiled.
00000000 T main
U printf
test1:
> gcc b.a a.a -o main
> main
result is 1
test2:
> gcc a1.a b.a a2.a -o main0
> gcc a2.a a1.a b.a -o main0
> main0
result is 0 //the result is dependent to link sequence!!!
> gcc a1.a a2.a b.a -o main1
> gcc b.a a1.a a2.a -o main1
> main1
result is 1 //the result is dependent to link sequence!!!
test3:
> gcc b.a a2.a a1.a -main //why this liinking failed???
a1.a(a1.o): In function `main':
a1.o(.text+0xd): undefined reference to `f'
a1.o(.text+0x25): undefined reference to `f'
collect2: ld returned 1 exit status
|
就我的经验而言,
gcc对待.o与.a是不同的,.a是所谓“静态库文件”,其实就是.o的一个集合,但是它被视作“函数体的提供者”,只要有可能,就尽量少去把它的成员连接到最终的可执行文件中,而命令行参数中普通的.o文件将完整地被连接到最终的可执行文件中去。
gcc在连接过程中,只在当前存在有Undefined 的symbol的时候,才会到参数list中的下一个.a里去找它的成员,如果一个成员(.o文件)没有提供要找的symbol,这个.o将不会被连接到最终的可执行文件中去;如果在某个.o中存在要找的symbol的定义体,那么这个.o将被整个连接进可执行文件(注意只连接了这个.o,它所属的.a中其他的.o文件不被连接),这一时刻,symbol表是有可能发生扩充的,也就是这个.o中的symbol将被整个引入当前的symbol表中,当然也就有可能增加Undefined的symbol;gcc在连接过程中,任一时刻发现没有Undefined的symbol存在,那么gcc将停止对.a的搜索。这就是为什么会出现明明两个.a中有同名symbol,却可以编译连接通过;同样可以说明,为什么你程序的运行结果会和参数顺序有关系,实际情况是,后一个.a并没有被连接进去。
此外在以上行为中,还隐藏了一个推断:gcc在连接过程,对.a的操作是严格有序的,也就是说,在搜索中由于未发现有用的symbol而被忽略(将不被连接到最终可执行文件中)了的.o,不会被再次扫描。那么如果在命令行参数的顺序中比较靠后的.a中有一个symbol没有定义,而该symbol的定义体所在的.o在之前也恰好被忽略了,那么gcc最终将无法定位这个symbol,也就会报出"undefined reference "这样的错误来。
for you information
gcc对待.o与.a是不同的,.a是所谓“静态库文件”,其实就是.o的一个集合,但是它被视作“函数体的提供者”,只要有可能,就尽量少去把它的成员连接到最终的可执行文件中,而命令行参数中普通的.o文件将完整地被连接到最终的可执行文件中去。
gcc在连接过程中,只在当前存在有Undefined 的symbol的时候,才会到参数list中的下一个.a里去找它的成员,如果一个成员(.o文件)没有提供要找的symbol,这个.o将不会被连接到最终的可执行文件中去;如果在某个.o中存在要找的symbol的定义体,那么这个.o将被整个连接进可执行文件(注意只连接了这个.o,它所属的.a中其他的.o文件不被连接),这一时刻,symbol表是有可能发生扩充的,也就是这个.o中的symbol将被整个引入当前的symbol表中,当然也就有可能增加Undefined的symbol;gcc在连接过程中,任一时刻发现没有Undefined的symbol存在,那么gcc将停止对.a的搜索。这就是为什么会出现明明两个.a中有同名symbol,却可以编译连接通过;同样可以说明,为什么你程序的运行结果会和参数顺序有关系,实际情况是,后一个.a并没有被连接进去。
此外在以上行为中,还隐藏了一个推断:gcc在连接过程,对.a的操作是严格有序的,也就是说,在搜索中由于未发现有用的symbol而被忽略(将不被连接到最终可执行文件中)了的.o,不会被再次扫描。那么如果在命令行参数的顺序中比较靠后的.a中有一个symbol没有定义,而该symbol的定义体所在的.o在之前也恰好被忽略了,那么gcc最终将无法定位这个symbol,也就会报出"undefined reference "这样的错误来。
for you information