【Linux】21.基础IO(3)

news/2025/1/31 6:45:35 标签: linux, 运维, 服务器

文章目录

  • 3. 动态库和静态库
    • 3.1 静态库与动态库
    • 3.2 静态库的制作和使用原理
    • 3.3 动态库的制作和使用原理
      • 3.3.1 动态库是怎么被加载的
    • 3.4 关于地址


3. 动态库和静态库

3.1 静态库与动态库

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库

  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码

  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking

  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。


3.2 静态库的制作和使用原理

mymath.h

#pragma once

#include <stdio.h>

int add(int x, int y);//加
int sub(int x, int y);//减
int mul(int x, int y);//乘
int div(int x, int y);//除

mymath.c

#include "mymath.h"

int myerrno = 0;

int add(int x, int y){
    return x + y;
}

int sub(int x, int y){
    return x - y;
}

int mul(int x, int y){
    return x * y;
}

int div(int x, int y){
    if(y == 0){
        myerrno = 1;
        return -1;
    }
    return x / y;
}

makefile

lib=libmymath.a

$(lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.c
	gcc -c $^

.PHONY:clean
clean:
	rm -rf *.o *.a lib

.PHONY:output
output:
	mkdir -p lib/include
	mkdir -p lib/mymathlib
	cp *.h lib/include
	cp *.a lib/mymathlib

make后:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ ll
total 28
drwxrwxr-x  2 ydk_108 ydk_108 4096 Jan 24 22:18 ./
drwxrwxr-x 17 ydk_108 ydk_108 4096 Jan 24 22:07 ../
-rw-rw-r--  1 ydk_108 ydk_108 2024 Jan 24 22:18 libmymath.a
-rw-rw-r--  1 ydk_108 ydk_108  229 Jan 24 22:18 makefile
-rw-rw-r--  1 ydk_108 ydk_108  276 Jan 24 22:13 mymath.c
-rw-rw-r--  1 ydk_108 ydk_108  147 Jan 24 22:12 mymath.h
-rw-rw-r--  1 ydk_108 ydk_108 1848 Jan 24 22:18 mymath.o
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ 

make output后:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ make output
mkdir -p lib/include
mkdir -p lib/mymathlib
cp *.h lib/include
cp *.a lib/mymathlib
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ ll
total 32
drwxrwxr-x  3 ydk_108 ydk_108 4096 Jan 24 22:22 ./
drwxrwxr-x 17 ydk_108 ydk_108 4096 Jan 24 22:07 ../
drwxrwxr-x  4 ydk_108 ydk_108 4096 Jan 24 22:22 lib/
-rw-rw-r--  1 ydk_108 ydk_108 2024 Jan 24 22:18 libmymath.a
-rw-rw-r--  1 ydk_108 ydk_108  229 Jan 24 22:18 makefile
-rw-rw-r--  1 ydk_108 ydk_108  276 Jan 24 22:13 mymath.c
-rw-rw-r--  1 ydk_108 ydk_108  147 Jan 24 22:12 mymath.h
-rw-rw-r--  1 ydk_108 ydk_108 1848 Jan 24 22:18 mymath.o
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ tree lib
lib
├── include
│   └── mymath.h
└── mymathlib
    └── libmymath.a

2 directories, 2 files
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ 

然后在lesson23这个目录下创建test目录,把lib复制到test目录下

同时在test目录下创建main.c文件

#include "lib/include/mymath.h"

int main(){
        printf("1+1=%d\n",add(1,1));
        
        return 0;
}

如果main.c文件的头文件写的是#include "mymath.h"

那么直接gcc是无法编译的,可以用gcc main.c -I ./lib/include/

当然如果头文件是#include "lib/include/mymath.h"就可以直接gcc了。

gcc编译后:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ gcc main.c
/usr/bin/ld: /tmp/ccErjU5m.o: in function `main':
main.c:(.text+0x13): undefined reference to `add'
collect2: error: ld returned 1 exit status
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$

因为gcc默认去系统的默认库里面找的,所以我们要加点东西:

gcc main.c -L ./lib/mymathlib/ -lmymath

这里的-L表示的是在lib库里面,

-lmymath表示是在./lib/mymathlib/库里面的libmymath.a库文件,这里要去掉lib前缀和.a后缀。-l表示库名称。

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ gcc main.c -L ./lib/mymathlib/ -lmymath
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ ll
total 36
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 24 22:40 ./
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 24 22:24 ../
-rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 24 22:40 a.out*
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 24 22:22 lib/
-rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 24 22:26 main.c
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ 

可是gcc main.c -L ./lib/mymathlib/ -lmymath这个东西太长了,我们可不可以不写这么长的呢?

我们可以把mymath.hlibmymath.a放到系统默认路径下,这个操作也叫库的安装

这样只需要gcc main.c -lmymath就可以了。

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
total 36
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:26 ./
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:27 ../
-rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:26 a.out*
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
-rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 25 10:26 main.c
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ sudo cp lib/include/mymath.h /usr/include/
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ls /usr/include/mymath.h
/usr/include/mymath.h
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ sudo cp lib/mymathlib/libmymath.a /lib64/
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ls /lib64/libmymath.a
/lib64/libmymath.a
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c
/usr/bin/ld: /tmp/ccDIK8p6.o: in function `main':
main.c:(.text+0x13): undefined reference to `add'
collect2: error: ld returned 1 exit status
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c -lmymath
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
total 36
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:52 ./
drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:27 ../
-rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:52 a.out*
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
-rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 25 10:26 main.c
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ 

不过不建议我们自己乱加文件,这样可能会在以后背刺自己,造成冲突。


注意:如果我们把main.c写成这样

#include "lib/include/mymath.h"

int main(){
    printf("10/0=%d, error=%d\n",div(10,0),myerrno);

    return 0;
}       

那么运行结果就是

10/0=-1, error=0

为什么会这样呢?这里的运算一看就出错了,为什么error不是1呢?

因为C语言默认是从右向左运算的,这里先把myerrno的值传进来才传div(10,0)的值。

我们可以修改一下代码:

#include "lib/include/mymath.h"

int main(){
    int n = div(10,0);
    printf("10/0=%d, error=%d\n",n,myerrno);

    return 0;
}       

打印:

10/0=-1, error=1

把我们提供的方法,给别人用有两个方法:

  1. 我把源文件直接给他

  2. 把我们的源代码想办法打包成库 =库+.h

  1. 第三方库,往后使用的时候,必定要是用gcc-l

  2. 深刻理解errno的本质

  3. 如果系统中只提供静态链接,gcc则只能对该库进行静态链接

  4. 如果系统中需要链接多个库,则gcc可以链接多个库

  5. 不带static有动态库就动态编译,只有静态库才静态编译。带static只静态编译。


3.3 动态库的制作和使用原理

makefile

# 定义动态库名称
dy-lib=libmymethod.so
# 定义静态库名称
static-lib=libmymath.a

# 声明all为伪目标(不是实际文件)
.PHONY:all
# 默认目标 - 构建动态库和静态库
all: $(dy-lib) $(static-lib)

# 从mymath.o创建静态库的规则
$(static-lib):mymath.o
	ar -rc $@ $^     # 创建归档文件,如存在则替换,创建索引
mymath.o:mymath.c
	gcc -c $^        # 将C文件编译为目标文件

# 从mylog.o和myprint.o创建动态库的规则
$(dy-lib):mylog.o myprint.o
	gcc -shared -o $@ $^    # 将目标文件链接成共享库
mylog.o:mylog.c
	gcc -fPIC -c $^         # 使用位置无关代码编译
myprint.o:myprint.c
	gcc -fPIC -c $^         # 使用位置无关代码编译

# 清理目标 - 删除所有生成的文件
.PHONY:clean
clean:
	rm -rf *.o *.a *.so mylib

# 输出目标 - 创建发布目录结构
.PHONY:output
output:
	mkdir -p mylib/include  # 创建头文件目录
	mkdir -p mylib/lib      # 创建库文件目录
	cp *.h mylib/include    # 复制头文件
	cp *.a mylib/lib        # 复制静态库
	cp *.so mylib/lib       # 复制动态库

myprint.h

#pragma once

#include <stdio.h>


void Print();

myprint.c

#include "myprint.h"


void Print()
{
    printf("hello new world!\n");
    printf("hello new world!\n");
    printf("hello new world!\n");
    printf("hello new world!\n");
}

mylog.h

#pragma once

#include <stdio.h>


void Log(const char*);

mylog.c

#include "mylog.h"

void Log(const char*info)
{
    printf("Warning: %s\n", info);
}

然后编译:make ; make output

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ make ; make output
gcc -fPIC -c mylog.c
gcc -fPIC -c myprint.c
gcc -shared -o libmymethod.so mylog.o myprint.o
gcc -c mymath.c
ar -rc libmymath.a mymath.o
mkdir -p mylib/include
mkdir -p mylib/lib
cp *.h mylib/include
cp *.a mylib/lib
cp *.so mylib/lib
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ ll
total 76
drwxrwxr-x  4 ydk_108 ydk_108  4096 Jan 25 13:50 ./
drwxrwxr-x 18 ydk_108 ydk_108  4096 Jan 25 10:26 ../
-rw-rw-r--  1 ydk_108 ydk_108  2024 Jan 25 13:50 libmymath.a
-rwxrwxr-x  1 ydk_108 ydk_108 16312 Jan 25 13:50 libmymethod.so*
-rw-rw-r--  1 ydk_108 ydk_108   448 Jan 25 13:34 makefile
drwxrwxr-x  4 ydk_108 ydk_108  4096 Jan 25 13:50 mylib/
-rw-rw-r--  1 ydk_108 ydk_108    85 Jan 25 13:34 mylog.c
-rw-rw-r--  1 ydk_108 ydk_108    58 Jan 25 13:34 mylog.h
-rw-rw-r--  1 ydk_108 ydk_108  1704 Jan 25 13:50 mylog.o
-rw-rw-r--  1 ydk_108 ydk_108   276 Jan 25 10:26 mymath.c
-rw-rw-r--  1 ydk_108 ydk_108   147 Jan 25 10:26 mymath.h
-rw-rw-r--  1 ydk_108 ydk_108  1848 Jan 25 13:50 mymath.o
-rw-rw-r--  1 ydk_108 ydk_108   176 Jan 25 13:35 myprint.c
-rw-rw-r--  1 ydk_108 ydk_108    49 Jan 25 13:35 myprint.h
-rw-rw-r--  1 ydk_108 ydk_108  1864 Jan 25 13:50 myprint.o
drwxrwxr-x  3 ydk_108 ydk_108  4096 Jan 25 10:52 test/
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ tree mylib
mylib
├── include
│   ├── mylog.h
│   ├── mymath.h
│   └── myprint.h
└── lib
    ├── libmymath.a
    └── libmymethod.so

2 directories, 5 files
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ 

这里的执行过程是:

  1. 首先执行 make,因为没有指定目标,所以默认执行 Makefile 中的第一个目标 all,完成所有库文件的编译和创建
  2. 然后执行 make output,创建目录结构并复制文件

这样写的原因是:

  • 必须先执行 make 生成所有的库文件(.so.a)
  • 再执行 make output 进行文件整理和复制
  • 如果直接执行 make output,可能会因为库文件还未生成而导致复制失败

然后我们把库复制进test文件夹里面,并且把main.c文件改一下:

#include "mylog.h"
#include "myprint.h"

int main()
{

    Print();
    Log("hello log function");
    return 0;
}

运行

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
total 40
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 ./
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 13:50 ../
-rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:52 a.out* # 之前静态编译留下的
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
-rw-rw-r-- 1 ydk_108 ydk_108   116 Jan 25 13:57 main.c
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 mylib/
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c -I mylib/include/ -L mylib/lib -lmymethod
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
total 40
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 ./
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 13:50 ../
-rwxrwxr-x 1 ydk_108 ydk_108 16712 Jan 25 14:00 a.out* # 现在动态编译新生成的
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
-rw-rw-r-- 1 ydk_108 ydk_108   116 Jan 25 13:57 main.c
drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 mylib/
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ 

虽然编译过了,但是一运行就这样了:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ./a.out
./a.out: error while loading shared libraries: libmymethod.so: cannot open shared object file: No such file or directory

为什么呢?

我们之前编译的时候告诉编译器我们的动态库在哪里了,但是我们编译后,并没有告诉系统(即加载器)我们的动态库在哪里。

可以将自己库所在的路径,添加到系统的环境变量LD_LIBRARY_PATH中。

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
	linux-vdso.so.1 (0x00007ffc9cd79000)
	libmymethod.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa1947d3000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fa1949d3000)
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ydk_108/108/lesson24/test/mylib/lib
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ echo $LD_LIBRARY_PATH
::/home/ydk_108/108/lesson24/test/mylib/lib
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
	linux-vdso.so.1 (0x00007ffd6835f000)
	libmymethod.so => /home/ydk_108/108/lesson24/test/mylib/lib/libmymethod.so (0x00007f105f59b000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f105f3a2000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f105f5a7000)
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ./a.out
hello new world!
hello new world!
hello new world!
hello new world!
Warning: hello log function
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ 

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ su
Password: 
root@iZuf68hz06p6s2809gl3i1Z:/home/ydk_108/108/lesson24/test# cd /etc/ld.so.conf.d
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ll
total 20
drwxr-xr-x  2 root root 4096 Jun  3  2024 ./
drwxr-xr-x 89 root root 4096 Jan 14 19:45 ../
-rw-r--r--  1 root root   38 Sep  7  2019 fakeroot-x86_64-linux-gnu.conf
-rw-r--r--  1 root root   44 Apr 15  2020 libc.conf
-rw-r--r--  1 root root  100 Apr 15  2020 x86_64-linux-gnu.conf
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# touch ydk_108.conf
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ll
total 20
drwxr-xr-x  2 root root 4096 Jan 25 14:25 ./
drwxr-xr-x 89 root root 4096 Jan 14 19:45 ../
-rw-r--r--  1 root root   38 Sep  7  2019 fakeroot-x86_64-linux-gnu.conf
-rw-r--r--  1 root root   44 Apr 15  2020 libc.conf
-rw-r--r--  1 root root  100 Apr 15  2020 x86_64-linux-gnu.conf
-rw-r--r--  1 root root    0 Jan 25 14:25 ydk_108.conf
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# pwd
/etc/ld.so.conf.d
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# vim ydk_108.conf
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ldconfig
root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# 
# ldconfig前
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
	linux-vdso.so.1 (0x00007ffc8e125000)
	libmymethod.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4e24c2d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4e24e2d000)
# ldconfig后
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
	linux-vdso.so.1 (0x00007fffa231c000)
	libmymethod.so => /home/ydk_108/108/lesson24/test/mylib/lib/libmymethod.so (0x00007f9b2d7b8000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9b2d5c6000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9b2d7cb000)
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ 

解决加载找不到动态库的方法:

  1. 拷贝到系统默认的库路径 /ib64 /usr/lib64/

  2. 在系统默认的库路径 /ib64 /usr/lib64/下建立软连接

  3. 将自己的库所在的路径,添加到系统的环境变量LD_LIBRARY_PATH中。(重启就消失了)

  4. /etc/ld.so.conf.d 建立自己的动态库路径的配置文件(名字随便写,里面路径写对就行),然后重新ldconfig即可。(重启不会消失)

实际情况,我们用的库都是别人的成熟的库,都采用直接安装到系统的方式。


3.3.1 动态库是怎么被加载的

动态库(共享库)的共享机制:

  1. 内存共享机制
  • 当第一个进程加载动态库时,动态库的代码段被加载到物理内存中
  • 后续进程再使用这个动态库时,不会重新加载代码段,而是直接映射到已加载的物理内存
  • 多个进程共享同一份物理内存中的代码段,节省内存资源
  • 每个进程有自己的数据段副本,确保数据隔离

动态库在进程运行的时候,是要被加载的(静态库没有)

所以,动态库在系统中加载之后,会被所有进程共享。

9e45eb35a7ab2f9f8cb634e75555f4e3

这个共享库一旦被多个进程共享,那么它对应的页就会引入计数2,缺页中断的时候,识别发现是被多个进程共享的就会写时拷贝。


3.4 关于地址

程序没有加载前的地址(程序)

程序编译好之后,内部有地址的概念吗?

有的。(可以联想之前C++多态的虚函数表)

库可以在虚拟内存中,任意位置加载。

怎么做到的呢?

让自己内部函数不要采用绝对编址,只表示每个函数在库中的偏移量即可。

例如:printf的地址0x1122,这个0x1122代表printf相对于库的起始地址的偏移量。

然后加载动态库的时候,在地址空间里随便放。只需要记住这个库在虚拟地址空间的起始地址就可以了。

解释:为什么动态库可以被加载到任意位置,并且多个进程可以共享同一份代码?

  1. 假设有一个动态库 libexample.so:
起始位置: 未知 (加载时才确定)
函数A: +0x100 (偏移量)
函数B: +0x200 (偏移量)
函数C: +0x300 (偏移量)
  1. 不同进程加载时的情况:
进程1:
- 库加载到虚拟地址 0x10000000
- 函数A实际地址 = 0x10000000 + 0x100 = 0x10000100
- 函数B实际地址 = 0x10000000 + 0x200 = 0x10000200

进程2:
- 库加载到虚拟地址 0x20000000
- 函数A实际地址 = 0x20000000 + 0x100 = 0x20000100
- 函数B实际地址 = 0x20000000 + 0x200 = 0x20000200
  1. 工作原理:
  • 编译时:函数地址全部用偏移量表示
  • 加载时:
    • 动态链接器选择一个可用的虚拟地址空间
    • 记录库的基地址
    • 所有函数调用时:实际地址 = 基地址 + 偏移量

这就好比:

  • 一本书的目录不用页码,而用"距离书开始的页数"
  • 无论这本书放在书架的哪个位置(起始地址)
  • 只要知道书在哪(基地址),就能通过偏移量找到每个章节

这也就是为什么fPIC叫做产生位置无关码

  1. 静态库为什么不谈加载呢?

因为静态库会直接把程序拷贝到可执行程序里面,就谈不上加载了。

  1. 静态库为什么不说与位置无关呢?

因为库方法拷贝到可执行程序里后,就不谈偏移量了。他在什么位置就是确定的了。


http://www.niftyadmin.cn/n/5838418.html

相关文章

unity使用AVpro插件播放视频,打包安卓系统总是失败

已经排除了中文文件名等问题&#xff0c;只要在工程中添加了AVpro插件&#xff08;目前是2.6.6版本&#xff09;&#xff0c;在windows上一切正常使用&#xff0c;可以打包输出&#xff0c;但是只要打包安卓就是错误 一次偶然的机会在一台苹果笔记本上用相同的方法做了一个含有…

后端token校验流程

获取用户信息 前端中只有 await userStore.getInfo() 表示从后端获取数据 在页面中找到info对应的url地址&#xff0c;在IDEA中查找 这里是getInfo函数的声明&#xff0c;我们要找到这个函数的使用&#xff0c;所以点getInfo() Override public JSONObject getInfo() {JSO…

讯飞智作 AI 配音技术浅析(二):深度学习与神经网络

讯飞智作 AI 配音技术依赖于深度学习与神经网络&#xff0c;特别是 Tacotron、WaveNet 和 Transformer-TTS 模型。这些模型通过复杂的神经网络架构和数学公式&#xff0c;实现了从文本到自然语音的高效转换。 一、Tacotron 模型 Tacotron 是一种端到端的语音合成模型&#xff…

rust如何操作oracle

首先鄙视甲骨文&#xff0c;这么多钱的公司&#xff0c;不做一个rust库&#xff0c;还要社区帮忙。有个开源的rust库&#xff0c;叫oracle&#xff0c;但是并不是甲骨文做的。 我们来看一个从oracle数据库取所有表和视图的示例: // 定义连接字符串let conn_str1 format!(&quo…

论文阅读(八):结构方程模型用于研究数量遗传学中的因果表型网络

1.论文链接&#xff1a;Structural Equation Models for Studying Causal Phenotype Networks in Quantitative Genetics 摘要&#xff1a; 表型性状可能在它们之间发挥因果作用。例如&#xff0c;农业物种的高产可能会增加某些疾病的易感性&#xff0c;相反&#xff0c;疾病的…

130周四复盘(162)研究神作

1.设计相关 今天没有进行大思想的学习&#xff0c; 而思考的比较细节&#xff0c; 分析了某神作的核心机制的内外逻辑&#xff0c;总结优点&#xff0c;以及一些过时的缺点&#xff0c; b4这款神作就像一座高峰&#xff0c;难以企及&#xff0c;但魂牵梦萦。如果未来有朝一…

从0到1:C++ 开启游戏开发奇幻之旅(二)

目录 游戏开发核心组件设计 游戏循环 游戏对象管理 碰撞检测 人工智能&#xff08;AI&#xff09; 与物理引擎 人工智能 物理引擎 性能优化技巧 内存管理优化 多线程处理 实战案例&#xff1a;开发一个简单的 2D 射击游戏 项目结构设计 代码实现 总结与展望 游戏…

Elasticsearch:如何搜索含有复合词的语言

作者&#xff1a;来自 Elastic Peter Straer 复合词在文本分析和标记过程中给搜索引擎带来挑战&#xff0c;因为它们会掩盖词语成分之间的有意义的联系。连字分解器标记过滤器等工具可以通过解构复合词来帮助解决这些问题。 德语以其长复合词而闻名&#xff1a;Rindfleischetik…