源文件
源文件main2.c
#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;
}
源文件 vector.h
void addvec(int *x, int *y, int *z, int n);
void multvec(int *x, int *y, int *z, int n);
int getcount();
源文件addvec.c
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];
}
}
源文件multvec.c
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];
}
}
创建共享库
gcc -shared -fpic -o libvector.so addvec.c multvec.c
使用共享库创建可执行文件
gcc -o prog21 main2.c ./libvector.so
这里采用的基本思想是:
- 在链接时由链接器做一些静态链接工作,比如把
libvector.so
中的重定位和符号表信息拷贝到文件prog21
中; - 在加载时由动态链接器做动态链接;
注意:此时创建的可执行目标文件prog21
是部分链接的,因为链接器不是把libvector.so
中的代码和数据都拷贝到文件prog21
中,而是把libvector.so
中的重定位和符号表信息拷贝到文件prog21
中,将文件prog21
中引用到的libvector.so
中的符号解析的工作留给加载过程来完成。
加载和运行可执行文件
[root@VM_0_16_centos link]# ./prog21
z = [4 6]
关键词 加载器 动态链接器 应用程序
详解:
- 加载器首先创建内存映像;如果可执行文件中有
.interp
节,则就将控制权交给动态链接器ld-linux.so
; - 动态链接器通过执行若干个重定位步骤,完成之前链接器遗留的链接工作,并将控制权返回给加载器;
- 加载器将控制权交给应用,即跳转到该程序的入口点,即
_start
函数的地址,该函数定义在系统目标文件crt1.o
中; -
_start
函数调用系统启动函数_lib_start_main
函数,该函数定义在libc.so
中; -
_lib_start_main
函数会初始化执行环境,调用用户层的main
函数,处理用户层main
函数的返回值,如有必要可将控制权交给内核;
问题 1 步骤1创建的内存映像长什么样?
问题2 步骤2中动态链接器都做了哪些重定位工作?
- 将
libc.so
中的代码和数据重定位到某个内存段; - 将
libvector.so
中的代码和数据重定位到另一个内存段; - 重定位被
prog21
引用且定义在libc.so
和libvector.so
中的符号;