分析环境
- 编译器 x86-64 gcc 10.2
- 汇编风格 AT&T 风格
概述
汇编代码基于 x86-64 ,由于 x86 系列的 CPU 向后兼容,在指令上,兼容就是 intel8086 这个 16bit 的处理器的指令,在 intel80386 这个32bit 的处理器上也能使用。以此类推。先来了解下寄存器的变化。详细的可以查看 x86 寄存器历史。
以 ax 为例
| 16bit | 32bit | 64bit |
|---|---|---|
| ax | eax | rax |
可以了解 eax 是 32bits,rax 是 64bits。 其他指令类似。用
e和r来区分 32bits 还是 64bits
不同位数下的指令如何区分?
以 mov 为例
| 8bit | 16bit | 32bit | 64bit |
|---|---|---|---|
| movb | movw | movl | movq |
可以看到使用不同的后缀来表示这个是多少 bit 的指令
CPU 如何寻址?
CPU 寻址方式, 也就是拿到数据的方式.
立即数
movb $0x05,%al
表示为:R[al] = 0x05;> 将立即数 0x05(1 byte) 复制到寄存器 al
R 表示寄存器(register)
间接寻址
就是到内存里去寻找数据。
内存如何寻址?
通过
signed-offset(base,index,scale)来表示。
内存地址计算:
memory address = scale * index + base + signed-offset
举例说明
mov (%esi,%ebx,4), %edx
Move the 4 bytes of data at address esi+ 4 * ebx into edx.
%edx = 4 * %ebx + %esi
至此,如果将 scale = 8, 那就是 C 语言中的 long 型数据,如果同时递增 %ebx,那就是依次访问数组元素了。
register to memory (指针)
movl %eax, -4(%ebp)
表示为: mem[R[ebp]-4] = R[eax];
将寄存器eax 里面的值复制到寄存器 ebp 的值减去 4指向的内存地址处(也就是 R[ebp] -4 的值是一个内存地址).
通过寄存器指向了内存地址, 是不是很熟悉的指针啊, 对, 就是指针。 C 语言的指针就是这么玩的啊!
memory to register
movl -4(%ebp), %eax
%eax 表示为: R[eax] = mem[R[ebp] -4];
将寄存器esp 的值减去 4的值指向的内存地址处存放的值, 复制到寄存器 eax
代码分析
int main(){
int i = 10;
int *pi = &i;
int ii = *pi;
char c = 'z';
char *pc = &c;
char cc = *pc;
long l = 1000000000L;
long *pl = &l;
long ll = *pl;
return 0;
}
图解分析
C 代码和汇编对照

汇编代码分析

- 执行完
1和2这两个汇编指令后,假定%rsp = %rbp = 1024(内存地址)。 汇编第 4 行:movl $10, -52(%rbp) , 可以从上图中看到-52内存地址处被赋值为 10,占据 4Bytes。movl表示操作的是32bit 的整数。这和C 代码中第 6 行 int i = 10保持一致。汇编第 5 行: leaq -52(%rbp), %rax, 表示的是将 %rbp - 52 的内存地址,复制到 rax。因为使用的编译器是 x86-64gcc 10.2,是 64bits 的汇编代码,内存地址是 64bits。此时也就是 C 代码中,变量 i的地址复制给 rax。汇编第 6 行:movq %rax, -8(%rbp), 将此时 rax 复制到内存地址 %rbp - 8 的内存地址处。至此,完成了 C代码中第 7 行 int *pi = &i;汇编第 7 行:movq -8(%rbp),%rax,将 %rbp - 8 的内存地址处的值()指针(&i),复制到 rax。汇编第 8 行: movl (%rax), %eax, 将 %rax指向的值(i)复制到 eax。可以看到此时使用的是 eax,也就是 32bits,正是 C 语言中 int 型数据。汇编第 9 行: movl %eax, -12(%rbp), 将此时 eax 的值(i) 复制到 %rbp - 12 的内存地址处。至此,完成了 C 代码中第 8 行 int ii = *pi。- 其他的 char 和 long 类型,同理。
本文介绍了x86-64汇编语言的基础,包括不同位数下的指令区分,如movb、movw、movl、movq。详细解析了CPU的寻址方式,如立即数和间接寻址,并通过实例展示了内存地址的计算。此外,通过C代码与汇编代码的对照分析,阐述了如何将C语言的变量和指针映射到汇编指令中,帮助理解底层内存操作。
2426

被折叠的 条评论
为什么被折叠?



