汇编语言(机器语言)中没有变量的概念,一切操作都是直接对地址进行。
前置知识
例子:
#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 10;
int *pa = &a;
printf("a = %d\n", a);
printf("&a = %p\n", &a);
printf("pa = %p\n", pa);
printf("&pa = %p\n", &pa);
return 0;
}
在 printf("a = %d\n", a);
代码行打上断点。
通过 disass /m
进行进行反汇编。
Breakpoint 1, main (argc=2, argv=0x7fffffffec38) at /tmp/tmp.lskJd4a8xb/main.c:6
6 printf("a = %d\n", a);
(gdb) i line 3
Line 3 of "/tmp/tmp.lskJd4a8xb/main.c" starts at address 0x5555555551c0 <main> and ends at 0x5555555551cf <main+15>.
(gdb) i line 5
Line 5 of "/tmp/tmp.lskJd4a8xb/main.c" starts at address 0x5555555551d6 <main+22> and ends at 0x5555555551de <main+30>.
(gdb) disass /m 0x5555555551c0,+30
Dump of assembler code from 0x5555555551c0 to 0x5555555551de:
3 int main(int argc, char *argv[]) {
0x00005555555551c0 <main+0>: push %rbp
0x00005555555551c1 <main+1>: mov %rsp,%rbp
0x00005555555551c4 <main+4>: sub $0x20,%rsp
0x00005555555551c8 <main+8>: mov %edi,-0x14(%rbp)
0x00005555555551cb <main+11>: mov %rsi,-0x20(%rbp)
4 int a = 10;
0x00005555555551cf <main+15>: movl $0xa,-0x4(%rbp)
5 int *pa = &a;
0x00005555555551d6 <main+22>: lea -0x4(%rbp),%rax
0x00005555555551da <main+26>: mov %rax,-0x10(%rbp)
End of assembler dump.
由上述汇编代码(AT&T
格式)可知,-0x4(%rbp)
表示变量 a
,-0x10(%rbp)
表示变量 pa
。
进程的堆栈由高地址向低地址扩展。
因为要进行内存对齐,而 -0x4(%rbp) - 0x8
不能整除 8,所以要补位 4,因此 pa
的地址为 -0x10(%rbp)
。
0x4 + 0x8 + 0x4 = 0x10
通过 i r rbp rsp
打印堆栈寄存器信息。
(gdb) i r rbp rsp
rbp 0x7fffffffeb50 0x7fffffffeb50
rsp 0x7fffffffeb30 0x7fffffffeb30
控制台输出:
/tmp/tmp.lskJd4a8xb/cmake-build-debug/test nfs
a = 10
&a = 0x7fffffffeb4c
pa = 0x7fffffffeb4c
&pa = 0x7fffffffeb40
0x7fffffffeb4c
= 0x7fffffffeb50 - 0x4
= -0x4(%rbp)
= 变量 a
0x7fffffffeb40
= 0x7fffffffeb50 - 0x10
= -0x10(%rbp)
= 变量 pa
【lea
和 mov
指令】介绍
lea
( load effective address
) 指令可以用来将一个内存地址直接赋给目的操作数。
例如:lea eax,[ebx+8]
就是将 ebx+8
这个值直接赋给 eax
,而不是把 ebx+8
处的内存地址里的数据赋给 eax
。
而 mov
指令则恰恰相反,例如:mov eax,[ebx+8]
则是把内存地址为 ebx+8
处的数据赋给 eax
。
上面的汇编指令格式为
Intel
格式。
AT&T
和 Intel
格式中的源操作数和目标操作数的位置正好相反。
- 在
Intel 汇编格式
中,目标操作数在源操作数的左边; - 而在
AT&T 汇编格式
中,目标操作数在源操作数的右边。
gdb 命令查看信息命令:
(gdb) i r rbp rsp
rbp 0x7fffffffeb50 0x7fffffffeb50
rsp 0x7fffffffeb30 0x7fffffffeb30
(gdb) p &a
$10 = (int *) 0x7fffffffeb4c
(gdb) p &pa
$11 = (int **) 0x7fffffffeb40
(gdb) x /32xb $rsp
0x7fffffffeb30: 0x38 0xec 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffeb38: 0x90 0x50 0x55 0x55 0x02 0x00 0x00 0x00
0x7fffffffeb40: 0x4c 0xeb 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffeb48: 0x00 0x00 0x00 0x00 0x0a 0x00 0x00 0x00
(gdb) p a
$12 = 10
(gdb) p pa
$13 = (int *) 0x7fffffffeb4c
(gdb) x /16xb $rsp
0x7fffffffeb30: 0x38 0xec 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffeb38: 0x90 0x50 0x55 0x55 0x02 0x00 0x00 0x00
网友评论