• keepgoing
    2021-11-06
    自己的话总结: 1. 静态函数不需要重定位因为和执行单元代码都在.text段,相对位置在编译的时候就能确定了,因为链接器合并中间文件时相对位置不会变。 2. 静态变量需要重定位,因为和编译单元代码段.text分属不同的section,在.data,链接器合并文件时会重新排布,所以需要重定位。 3. 全局变量/函数,外部变量/函数都是需要被重定位的,大致方法就是: 编译器先用0占位符号、链接重定位表找符号、定位符号地址、然后在当前代码段计算RIP相对偏移位置填上。 编译器:生成机器码、符号0占位 链接器:合并文件,分配符号地址,给符号地址写回编译出的代码

    作者回复: 总结得真好!来,来,来,笔给你,你来写。哈哈哈。

    共 3 条评论
    30
  • 慢动作
    2021-11-06
    为什么要S+A-P,直接用S有什么不好的?

    作者回复: S是绝对地址,而S+A-P算出来的是相对地址。使用相对地址的好处是只要引用者和被引用者的相对位置不变,那么它们就可以被安排到任意的位置上。这就可以支持加载地址随机化等安全增强技术啦。

    共 2 条评论
    14
  • 鵼
    2021-11-12
    全局变量和静态变量的初值在编译阶段吧。初始值应该都在.data段。链接的主要工作是合并目标文件以及重定向符号。可以看到重定向是进行地址的转换。目标文件中,可以看到变量和函数的地址都用0占位,静态方法除外,因为静态方法是计算的相对偏移量,地址怎么变无所谓,偏移量是固定的。但是链接主要是符号地址转化,并不代表是值,值应该是在 data段保存好的,只是通过链接把地址值回填。因此,我猜测是编译阶段,目标文件应该是能看到初始值的。对于数组类型的全局变量,因为都是0,所以放在bss段,应该是在加载的时候再分配内存吧,这个应该是在加载的时候决定吧。

    作者回复: very good:)

    共 3 条评论
    6
  • 郑童文
    2021-11-10
    谢谢老师对我前一个问题的回答,可能我当时没有表达清楚。 再接着问一下。 我的意思是栈和堆区域在虚拟内存布局的起始虚拟地址(也就是它们的起始边界)是如何确定的? 会保存在可执行文件中吗? 谢谢!

    作者回复: 栈是在用户空间的顶部,这是操作系统决定的位置。对于编译器和链接器来说,栈基址在哪里都是可以的。因为对栈的操作都是通过栈顶指针完成的。只要栈顶的数据是对的,就都是对的。堆的起始边界是brk指针决定的。而brk是代码段长度+数据段长度+bss段长度决定的。当加载器在加载各个段的时候会计算brk指针的。所以答案是文件中不用保存,但加载器会根据文件中的信息去计算brk指针。

    共 2 条评论
    2
  • kylin
    2021-11-08
    一般来说,重定位表的名字都是以.rela 开头,比如.rela.text 就是对.text 段的重定位表,.rela.data 是对.data 段的重定位表。因为我们的例子中并没有涉及.data 段的重定位,所以,在上面打印的信息中没有出现.rela.data 段。 --- 请问上面代码的 extern_var为啥不在rela.data中,而是在rela.text里面呢?静态变量不是应该在rela.data中吗?

    作者回复: 这里要记住的是重定位表的作用是描述“需要被重定位”的位置。所以它描述的是“引用”符号的地方,不是符号所在的位置。你可以试试声明一个指针变量,初始化时给他一个外部变量的地址。一定要记住,重定位表描述的是“引用者”,不是被引用者。

    共 2 条评论
    2
  • 小时候可鲜啦
    2021-12-04
    小标题静态变量和总结之间的那张讲述静态变量重定位的示意图中(有错误): 227地址处的指令长度应该为6字节:8b 05 00 00 00 00, 那么根据OFFSET = S + A - P = (102 + (- 4) - 227) = 0x12D 而不是图中的0x12C

    作者回复: 已修复,谢谢

    共 2 条评论
    1
  • 杨军
    2021-11-21
    老师,S+A-P,这里的S 是其最终符号的真实地址,也就是 0x601030 ;A 是 Addend 的值,可以从重定位表里查到是 -4,;P 是重定位 offset 的地址,这里是 0x4004b7。0x601030,0x4004b7可以从哪里查到了?

    作者回复: 从注释里看到的。objdump在反编译的时候,会把地址放在注释里给你看。实际上,反编译的过程就是从文件中把这些信息读出来并展示给你的过程。

    共 2 条评论
    1
  • IT小僧
    2021-12-02
    老师,请教个跑题的问题,上面main函数有6个整形变量,共需24字节内存,为啥编译器会预分配内存空间sub $0x20,%rsp,分配了32字节呢?

    作者回复: 一般来说,是为了让栈帧对齐,有利于加速访存速度。

    
    
  • 姑射仙人
    2021-11-21
    Java语言的编译和链接和这个不一样吧,还有JVM里应该没有虚拟内存的概念,大家都在一个内存空间内。那些字变量的地址什么的,是在什么时候确定的?

    作者回复: java也有符号解析的过程。基本原理和第8课里说的运行时解析比较相似。符号的地址都是运行时得到的。

    
    
  • LDxy
    2021-11-19
    我经常听人说要查看一下map文件,请问老师map文件有什么作用呢?查看map文件能看出什么?

    作者回复: 不如自己动手试一下?你可以通过cat命令,查看/proc/pid/map和/proc/pid/smap文件,看看他们的各个字段的作用。它的信息是非常全面的,我这里无法一一列举。你可以通过man命令进行学习。

    
    