x64cpu与IA32cpu中通用寄存器的差异

 整理一下IA32处理器和x86-64处理器中通用寄存器的差异。
    IA32既支持32位处理器,也向后兼容16位寄存器。IA32把16位的通用寄存器,标志寄存器和指令指针寄存器扩充为32位。段寄存器仍为16位。IA32 CPU中包含一组8个32位通用寄存器,用来存储整数数据和指针。它们的名字以%e开头,可以理解为对16位的extend。
    这8个寄存器分别为eax, ebx, ecx, edx, esi, edi, ebp和esp,其中eax,ebx,ecx,edx为数据寄存器,esi,edi为变址寄存器,ebp和esp为指针寄存器。eax,ebx,ecx,edx的低16位可以像以前的16位寄存器一样单独当成16位寄存器使用,例如eax的低16位ax,并且这个低16位寄存器的高8位和低8位可以分别当成两个8位寄存器使用,例如ax的低8位al和高8位ah,ebx,ecx,edx同eax。寄存器的名字反映了它的用途。八个通用寄存器的名字和一般用途如下(除ESP和EBP外用途仅供参考,具体看使用者):
  • EAX  一般作为累加器(add)
  • EBX  一般作为基地址寄存器(base)
  • ECX  一般作为计数寄存器(count)
  • EDX  一般用来存放数据(data)
  • ESP   一般作为栈指针寄存器(stack pointer)
  • EBP   一般作为基指针寄存器(base pointer)
  • ESI     一般作为源变址寄存器(source index)
  • EDI    一般作为目标变址寄存器(destinatin index)
下图即为IA32通用寄存器
    在x86-64中,所有的寄存器都扩充到了64位,不仅位数上发生变化,通用寄存器的数量也从原有的8个增加到16个。标识符上,从原来的%eax变成了%rax,但是为了保持向后兼容性,%eax仍然可用,并且指向%rax的低32位。寄存器的发展中仍然保持着对上一般本的兼容。
    x86-64中有了更多数量的寄存器,可以把堆栈数据直接放在寄存器中代替使用存储器,从而加快运算速度。x86-64的16个寄存器分别是%rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rsp, %rbp, %r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15。
    16个寄存器的名字和一般用途如下:
  • %rax 作为函数返回值使用。
  • %rsp 栈指针寄存器,指向栈顶
  • %rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。
  • %rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
  • %r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值
    下图为x86-64通用寄存器
下面我们写一个简单的C函数来看一下gcc生成的32位和64位汇编代码的区别:
C语言代码:(保存为simple.c)
void 
swap(int *x, int *y) {
    int t = *x;
    *x = *y;
    *y = t;
}
下面我们使用gcc -O1 -S -ma32 simple.c来生成32位汇编代码:
	.file	"simple.c"
	.text
	.globl	swap
	.type	swap, @function
swap:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$16, %esp
	movl	8(%ebp), %eax
	movl	(%eax), %eax
	movl	%eax, -4(%ebp)
	movl	12(%ebp), %eax
	movl	(%eax), %edx
	movl	8(%ebp), %eax
	movl	%edx, (%eax)
	movl	12(%ebp), %eax
	movl	-4(%ebp), %edx
	movl	%edx, (%eax)
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	swap, .-swap
	.ident	"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
	.section	.note.GNU-stack,"",@progbits
再使用gcc -S -ma64 simple.c 来生成64位汇编代码:
	.file	"simple.c"
	.text
	.globl	swap
	.type	swap, @function
swap:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movq	%rdi, -24(%rbp)
	movq	%rsi, -32(%rbp)
	movq	-24(%rbp), %rax
	movl	(%rax), %eax
	movl	%eax, -4(%rbp)
	movq	-32(%rbp), %rax
	movl	(%rax), %edx
	movq	-24(%rbp), %rax
	movl	%edx, (%rax)
	movq	-32(%rbp), %rax
	movl	-4(%rbp), %edx
	movl	%edx, (%rax)
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	swap, .-swap
	.ident	"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
	.section	.note.GNU-stack,"",@progbits

参考:1. 《深入理解计算机系统》
2. 淘宝博客http://www.searchtb.com/2013/03/x86-64_register_and_function_frame.html

你可能感兴趣的:(x64cpu与IA32cpu中通用寄存器的差异)