汇编程序指针地址 - 如何获取它

时间:2016-08-23 07:29:34

标签: pointers assembly x86 memory-address

我对汇编程序中的指针有很大的误解。我知道要获取指针(变量)的地址,请使用

MOV EAX, variable
or 
LEA EAX, variable

我也知道MOV有很多不同的OP代码,但我感兴趣的是MOV register, address

问题是......它如何知道变量所在的地址?汇编程序是否已在可执行文件中生成MOV EAX, address_of_variable或指令为MOV EAX, ...并且它找到该值然后获取它的地址。但是它如何知道如何在内存中搜索该值然后返回地址(假设每次都改变地址)。

如果这是一个愚蠢的问题,请原谅我,但我不明白它是如何做到的。

1 个答案:

答案 0 :(得分:3)

在标准体系结构上,您可以存储变量的各种位置:

  • 数据段/ BSS:对于全局变量和静态局部变量(具有静态存储持续时间的变量);
  • Stack:局部变量(具有自动存储持续时间的变量);
  • 堆:动态变量(具有动态存储持续时间的变量,使用newmalloc分配 - 类似函数)。

编译器如何解析变量的地址取决于存储变量的位置。

数据段/ BSS

这些是具有静态存储持续时间的变量,编译器在编译时知道它们的所有内容,并且它们的地址在链接时已知。请看以下代码段:

int a = 0;

int main () {
    return a;   
}

汇编(缩减):

a:
        .zero   4
main:
        ...
        movl    a(%rip), %eax
        ...

您有a所在的数据段(程序集顶部),要获取a的地址,编译器将使用a(%rip)(指定x86程序集)。这将被取代"在链接时由链接器 - 没有"动态"计算地址。

注意:否"动态"计算意味着在运行时没有用于计算地址的指令,但这些地址" live"在virtual address space(相对于程序本身),并将在memory management unit的运行时转换为物理地址。

这可能是最简单的存储类型:变量的地址已存储在某处,因此您只需检索它。请看以下代码段:

int main () {
    int *p = new int();
    return *p;      
}

大会:

main:
        ...
        movq    -8(%rbp), %rax # Load p into rax (see the stack section)
        movl    (%rax), %eax   # Load *p into eax
        ...

有关第一个汇编指令的说明,请参阅堆栈部分,但基本上它将p的值存储到rax寄存器中,然后使用(%rax)来检索值存储在rax的地址中(如果rax包含0x8000,则(%rax)是地址0x8000处的值)。

堆栈

具有自动存储持续时间的变量存储在堆栈中,并且它们的地址相对于堆栈指针(这是一个始终指向堆栈的" base"的寄存器)进行检索。请看以下代码段:

int f() {
    int a = 4;
    return a + 2;
}

汇编(缩减):

f():
        ...
        movl    $4, -4(%rbp)     # Set a = 4
        movl    -4(%rbp), %eax   # Load a into eax
        addl    $2, %eax         # Add 2 to eax
        ...

在上面的程序集中,rbp基本指针,正如您所看到的,a的地址是-4(%rbp)相对于它检索的(第一条指令基本上是a = 4)。

注意:返回值存储在eax寄存器中,如果存在,该函数的参数也将放在堆栈中,但此行为取决于{ {3}},其他架构可能使用不同的方法。

相关问题