我对汇编程序中的指针有很大的误解。我知道要获取指针(变量)的地址,请使用
MOV EAX, variable
or
LEA EAX, variable
我也知道MOV有很多不同的OP代码,但我感兴趣的是MOV register, address
。
问题是......它如何知道变量所在的地址?汇编程序是否已在可执行文件中生成MOV EAX, address_of_variable
或指令为MOV EAX, ...
并且它找到该值然后获取它的地址。但是它如何知道如何在内存中搜索该值然后返回地址(假设每次都改变地址)。
如果这是一个愚蠢的问题,请原谅我,但我不明白它是如何做到的。
答案 0 :(得分:3)
在标准体系结构上,您可以存储变量的各种位置:
new
或malloc
分配 - 类似函数)。编译器如何解析变量的地址取决于存储变量的位置。
这些是具有静态存储持续时间的变量,编译器在编译时知道它们的所有内容,并且它们的地址在链接时已知。请看以下代码段:
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}},其他架构可能使用不同的方法。