使用汇编代码调用地址

时间:2017-01-26 19:40:22

标签: gcc assembly g++

在我们的应用程序中,我有以下源代码:

#define GET_CALL_ADDRESS(VAR) asm("movl 4(%%ebp),%0;" : "=r"(VAR));

void * _our_malloc(size_t size)
{
    unsigned long calladdr;
    ...
    GET_CALL_ADDRESS(calladdr);
    ...
    return p;
}

我想知道GET_CALL_ADDRESS做了什么?此代码在32位计算机上编译并正常工作。

但是在64位机器上,在编译期间我收到以下错误:

Error: incorrect register `%rax' used with `l' suffix

1 个答案:

答案 0 :(得分:1)

指令

asm("movl 4(%%ebp),%0;" : "=r"(VAR));

将32位数量从[EBP+4]复制到VAR。您的案例中的VAR定义为calladdr。这假设返回地址是32位,这在64位系统中不再是真的,它假定返回地址为[EBP+4],这在64位系统中也不再正确。

它失败的原因是calladdr类似于[EBP-x](其中x是某个数字,如4),并且没有单一的Intel x86指令可以从{{1}获取并存储在[EBP+4],因此从[EBP-x]获取的值必须存储在某个寄存器中,然后该寄存器的值必须存储在[EBP+4]。然后对于一些我不知道的原因gcc决定使用寄存器[EBP-x]来完成这项工作,但是rax是64位宽,而rax指令的'l'前缀意味着32比特数量,所以存在不匹配。

即使您以某种方式设法解决了这个问题,您的下一个问题是在64位架构上,返回地址不在movl

因此,整个子句假设你是32位。

我的建议:彻底抛弃这个废话并将其替换为一些现成的库(无需重新发明轮子),它可以在32位和64位模式下工作,或者使用gcc的内置函数检索返回地址,如Michael Petch建议的那样;然后像老板那样继续重建64位。