链接的概念
1.链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行。
2.链接可以执行于编译、加载、运行时。
3.在现代系统中,链接由连接器自动执行。
具体操作
编译器驱动程序
测试代码1
//mismatch-main.c
#include <stdio.h>
long int x; /* Weak symbol */
int main(int argc, char *argv[]) {
printf("%ld\n", x);
return 0;
}
//mismatch-variable.c
/* Global strong symbol */
double x = 3.14;
1.在Ubuntu终端输入 gcc -Og -o mismatch mismatch-main.c mismatch-variable.c 得到一个可执行目标文件mismatch,后输入 ./mismatch 即可得运行结果“461425307021498087”。
2.-o表示设定输出文件名,不加-o时默认a.out为可执行文件名。
3.在mismatch-main.c中定义了全局变量x(弱符号),mismatch-variable.c中定义了强符号x并赋值为3.14,依多重定义的符号名原则,Linux连接器选择强符号(即double x=3.14),又浮点数在计算机中按IEEE754标准存储表示,故输出结果为461425307021498087。
运行结果如下
测试代码2
//global.h
extern int g;
int f();
//global-c1.c
#include "global.h"
int f() {
return g+1;
}
//global-c1.c
#include <stdio.h>
#include <stdlib.h>
#include "global.h"
int g = 0;
int main(int argc, char *argv[]) {
if (argc >= 2) {
g = atoi(argv[1]);
}
printf("g = %d. f() = %d\n", g, f());
return 0;
}
运行结果如下
静态链接
测试代码
/* addvec.c */
/* $begin addvec */
int addcnt = 0;
void addvec(int *x, int *y,int *z, int n){
int i;
addcnt++;
for (i = 0; i < n; i++)
z[i] = x[i] + y[i];
}
/* $end addvec */
/* multvec.c */
/* $begin multvec */
int multcnt = 0;
void multvec(int *x, int *y, int *z, int n) {
int i;
multcnt++;
for (i = 0; i < n; i++)
z[i] = x[i] * y[i];
}
/* $end multvec */
/* main2.c */
/* $begin main2 */
#include <stdio.h>
#include "vector.h"
int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];
int main() {
addvec(x, y, z, 2);
printf("z = [%d %d]\n", z[0], z[1]);
return 0;
}
/* $end main2 */
1.在Ubuntu终端依次输入
gcc -c addvec.c multvec.c
ar rcs libvector.a addvec.o multvec.o
gcc -c main2.c
gcc -static -o prog2c main2.o ./libvector.a
./prog2c
五条命令即得运行结果z = [4 6]。
2.gcc -c addvec.c multvec.c、ar rcs libvector.a addvec.o multvec.o用于将addvec.c和multvec.c大包至libvector库函数中。main2.c中包含了vector.h的头文件,包含了addvec函数信息。
运行结果如下
可重定位目标文件
测试代码
//symbols.c
#include <stdio.h>
int time;
int foo(int a) {
int b = a + 1;
return b;
}
int main(int argc, char *argv[]){
printf("%d\n", foo(5));
return 0;
}
1.在Ubuntu终端依次输入
readelf -s symbols.o
readelf -S symbols.o
readelf -r symbols.o
objdump -d main.o
2.readelf -s symbols.o为查看符号信息(此处为小s)。输出结果为符号表。foo、main均为强符号(函数)。foo、time定义为int型,占4字节。time定义为未初始化的全局变量(由COM表示),所以为弱符号。printf无类型、未定义(UND)。
3.readelf -S symbols.o为显示节头信息,-r可查看重定位信息。
4.objdump -d main.o为反汇编。可通过 objdump -dx main.o 查看可用头信息(符号表等)。其中-x表示显示所有可用头信息。
5.由于文件为可重定位文件,因此起始地址为0。Size表示每个节所占的大小、File off表示每个节在ELF中的偏移地址。
运行结果如下
写这次日志的时候自己的电脑出了点问题,所以借用的别人的电脑,下次还会在自己的电脑上运行一遍。