从汇编来看 C 语言之变量

2021-07-12  本文已影响0人  蓝笔头

汇编语言(机器语言)中没有变量的概念,一切操作都是直接对地址进行。

前置知识

例子:

#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


leamov 指令】介绍

leaload effective address) 指令可以用来将一个内存地址直接赋给目的操作数。
例如:lea eax,[ebx+8] 就是将 ebx+8 这个值直接赋给 eax,而不是把 ebx+8 处的内存地址里的数据赋给 eax

mov 指令则恰恰相反,例如:mov eax,[ebx+8] 则是把内存地址为 ebx+8 处的数据赋给 eax

上面的汇编指令格式为 Intel 格式。

AT&TIntel 格式中的源操作数和目标操作数的位置正好相反。


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

参考

上一篇 下一篇

猜你喜欢

热点阅读