XV6

操作环境为 Ubuntu 18.04,X86 下常用的汇编有 AT&T 与 Intel 两种,二者在语法上有一定的差异。

  1. 寄存器

    AT&T 需加前缀 %

  2. 立即数

    进制 AT&T 加前缀 $

    十六进制 Intel 加后缀 h,AT&T 加前缀 $0x

    二进制 Intel 加前缀 b,AT&T 加前缀 $

  3. 二者方向正好相反

    Intel 语法,第一个是目的操作数,第二个是源操作数。

    AT&T中,第一个数是源操作数,第二个数是目的操作数。(更符合阅读习惯)

  4. 内存单元操作数

    在 Intel 的语法中,基寄存器用 [] 括起来。

    而在 AT&T 中,用 () 括起来。

  5. 间接寻址方式

    Intel 的指令格式是 [base + index*scale + disp]

    AT&T 的格式是 disp(base, index, scale)

  6. 操作码的后缀

    在 AT&T 的操作码后加后缀,l(long,32 位),w(word,16 位),b(byte,8 位)

    在 Intel 的语法中,在操作数的前加 byte ptrword ptrdword ptr

样例如下:

Intel AT&T
mov eax,8 movl $8,%eax
mov ebx,0ffffh movl $0xffff,%ebx
int 80h int $0x80
mov eax,[ecx] movl (%ecx),%eax
mov al,bl movb %bl,%al
mov ax,bx movw %bx,%ax
Mov eax, dword ptr [ebx] movl (%ebx),%eax

1. 示例

比如,一个简单的函数:

int func(int i) {
    return 2 * i;
}

int main() {
    int s = func(255);
    return 0;
}

利用 GCC 进行汇编得到汇编指令,常用的汇编命令如下:

命令 输出文件
gcc -S hello.c hello.c
gcc -S -masm=intel hello.c hello.c

AT&T 的主要汇编代码如下:

func:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	%edi, -4(%rbp)
	movl	-4(%rbp), %eax
	addl	%eax, %eax
	popq	%rbp
	ret
main:
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$16, %rsp
	movl	$255, %edi
	call	func
	movl	%eax, -4(%rbp)
	movl	$0, %eax
	leave
	ret

Intel 的主要汇编代码如下:

func:
	push	rbp
	mov	rbp, rsp
	mov	DWORD PTR -4[rbp], edi
	mov	eax, DWORD PTR -4[rbp]
	add	eax, eax
	pop	rbp
	ret
main:
	push	rbp
	mov	rbp, rsp
	sub	rsp, 16
	mov	edi, 255
	call	func
	mov	DWORD PTR -4[rbp], eax
	mov	eax, 0
	leave
	ret

2. 汇编语言中的寄存器