linux加载程序变成进程的过程
- fork进程, 在内核创建进程相关内核项, 加载进程可执行文件
- 查找依赖的so库, 加载映射虚拟地址
- 初始化程序变量
动态库依赖越多, 进程启动就越慢, 并且发布程序的时候, 这些链接但没有使用的so同样要一起跟着发布, 否则进程启动时候找不到对应的so导致启动失败.
一些查看依赖的命令
查看依赖关系: readelf -d xx.so
查看链接到的so库: ldd xx.so
查看不需要链接的so库: ldd -u xx.so
编译时自动忽略无用的so库: gcc –as-needed
链接so库有两种途径: 显式和隐式
显式加载: 程序主动调用dlopen
打开so库, 使用dlopen
打开的so并不是在进程启动时候加载映射的, 而是当进程运行到调用dlopen
代码地方才加载该so; 也就是说, 如果每个进程显示链接a.so, 但是如果发布该程序时候忘记附带发布该a.so, 程序仍然能够正常启动, 甚至如果运行逻辑没有触发运行到调用dlopen函数代码地方
显式加载的函数接口
The four functions dlopen(), dlsym(), dlclose(), dlerror() implement the interface to the dynamic linking loader.
- void *dlopen(const char *filename, int flag);
The function dlopen() loads the dynamic library file named by the null-terminated string filename and returns an opaque “handle” for the dynamic library.
- void *dlsym(void *handle, const char *symbol);
The function dlsym() takes a “handle” of a dynamic library returned by dlopen() and the null-terminated symbol name, returning the address where that symbol is loaded into memory.
- int dlclose(void *handle);
The function dlclose() decrements the reference count on the dynamic library handle handle.
If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.
- char *dlerror(void);
The function dlerror() returns a human readable string describing the most recent error that occurred from dlopen(), dlsym() or dlclose() since the last call to dlerror().
c调用示例:
//add.h
int add(int a, int b);
//add.c