【问题标题】:What does the PIC register (%ebx) do?PIC 寄存器 (%ebx) 有什么作用?
【发布时间】:2010-10-31 03:19:44
【问题描述】:

我用 C++ 编写了一个“危险”程序,它从一个堆栈帧来回跳转到另一个堆栈帧。目标是从调用堆栈的最底层跳转到调用者,做某事,然后再次向下跳转,每次跳过中间的所有调用。

我通过手动更改堆栈基地址(设置%ebp)并跳转到标签地址来做到这一点。它完全可以使用 gcc 和 icc ,根本没有任何堆栈损坏。这工作的那天很酷。

现在我正在使用相同的程序并用 C 重新编写它,但它不起作用。具体来说,它不适用于 gcc v4.0.1 (Mac OS)。一旦我跳转到新的堆栈帧(堆栈基指针设置正确),就在调用fprintf 之前执行以下指令。此处列出的最后一条指令崩溃,取消引用 NULL:

lea    0x18b8(%ebx), %eax
mov    (%eax), %eax
mov    (%eax), %eax

我已经进行了一些调试,我发现通过在切换堆栈帧时手动设置%ebx 寄存器(使用我在离开函数之前观察到的值),我修复了错误.我读过这个寄存器处理 gcc 中的“位置无关代码”。

什么是位置无关代码?位置无关代码如何工作?这个寄存器指向什么?

【问题讨论】:

  • 您可以考虑使用 setjmp/longjmp 来获得此功能,而无需直接使用 %ebx。
  • 总的来说,是的,你是对的。在这种情况下,我需要能够跳转到调用者,执行一些其他函数,然后再跳转回被调用者。使用 setjmp/longjmp,被调用者的堆栈将被另一个函数覆盖。

标签: c++ gcc assembly x86 cpu-registers


【解决方案1】:

PIC 是在加载时动态重定位的代码。非 PIC 代码在链接时设置了跳转和调用地址。 PIC 有一个表,它引用了存在此类值的所有位置,就像 .dll 一样。

当图片被加载时,加载器会动态更新这些值。其他方案引用定义“基”的数据值,目标地址是通过在基上执行计算来决定的。基数通常由 loader 重新设置。

最后,其他方案使用各种调用已知相对偏移量的蹦床。相对偏移量包含由加载器更新的代码和/或数据。

选择不同方案有不同的原因。有些运行时速度很快,但加载速度较慢。有些加载速度很快,但运行时性能较差。

【讨论】:

    【解决方案2】:

    EBX 指向全局偏移表。见this reference about PIC on i386。该链接解释了 PIC 是什么以及如何使用 EBX

    【讨论】:

    • 现代 GCC 并不总是使用 EBX;至少在叶函数中,它有时会使用 EAX、ECX 或 EDX(暂存寄存器)作为 GOT 指针。在此 g++7.3 -O3 -m32 godbolt.org/g/UfPVRF 的编译器探索器输出中,请注意两个不同函数使用的两个不同 thunk。
    猜你喜欢
    • 2017-05-15
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 2013-05-21
    相关资源
    最近更新 更多