查看原文
其他

静态链接符号地址重定位直观描述

IT服务圈儿 2023-02-06

The following article is from 低并发编程 Author 闪客

来源丨经授权转自 低并发编程(ID:dibingfa)

作者丨闪客


静态链接的符号地址如何重定位,在 CSAPP 里的描述很严谨,看起来很复杂。

实际上,从需求出发,我们直观地看一下符号重定位最终的目标,并没有这么绕口。

用最简单的方式写个 hello.c 程序。

void hello()

再写个 main.c 程序调用 hello 方法。

void main() {
  hello();
}

对,就是这么简单粗暴,我连格式都懒得调了。

分别编译 hello.c 和 main.c。

gcc -c hello.c 会生成 hello.o
gcc -c main.c 会生成 main.o

看下这里 main.o 的汇编代码,可以看到这里调用 hello 方法的符号地址是 0,因为暂时还不知道最终是多少,所以先占个位。

然后链接二者生成可执行文件,可以看到最终这里被填写成了 2,这里是相对地址,往后偏移 2 个字节刚好是 hello 符号的地址。

所以,静态链接的符号解析就是说,这个 2 是怎么在链接过程计算出来的。

很简单,其实就是 hello 符号的地址值 0x40053d 减去 callq 指令的下一条指令的地址值 0x40053b,刚好就是 2。

那么占位符的地址在哪里呢?就是上面画红框的位置,其实就是 main 函数的地址 0x40052d,加上 callq 指令的偏移地址 0x9,再加上 callq 指令本身的长度 1。

分别用程序写出来。

倒数第二行就是直接打印出 hello 符号的地址。

倒数第一行是我们计算出来的 hello 的地址,就是 main 符号地址,加上 0xe 也就是 callq 指令的下一条指令的节偏移地址,再加上占位符处的值也就是 hello 的偏移地址。

这两行的值应该相等,就对了。

gcc main.c hello.c && ./a.out

也就是说:

hello = main + callq 下一条指令偏移地址 + 占位符的值

占位符的值就是我们符号解析要算的值,变下公式就是:

占位符的值 = hello - main - callq 下一条指令偏移地址

其中 callq 下一条指令的偏移地址,还可以继续分解为,占位符的地址 + 4

那继续变下公式就是:

占位符的值 = hello - main - 占位符地址 - 4

这也就是书上这两个公式的含义了。

这样想,是不是直观一点。

当然啦,以上是相对地址的重定位,绝对地址重定位的话,就更简单了,直接一步到位填上值就好了。

1、分库分表,可能真的要退出历史舞台了!

2、为什么Python不适合写游戏?

3、Nest.js 这么大的项目是怎么优化 ts 编译性能的?

4、面试到底面什么?

5、对于“前端状态”相关问题,如何思考比较全面

点分享

点点赞

点在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存