Lecture Material from 201

Robert Dewar

AT&T x86 Asm Syntax



GCC uses AT&T asm syntax. This is a little bit different from the regular
Intel format. The main differences are:

    * AT&T syntax uses the opposite order for source and destination operands,
          source followed by destination.
    * Register operands are preceded by the "%" character, including sections.
    * Immediate operands are preceded by the "$" character.
    * The size of memory operands are specified using the last character of
       the opcode. These are "b" (8-bit), "w" (16-bit), and "l" (32-bit).

Here are some examples: (Intel equivalent in parentheses)

	movw %bx, %ax   (mov ax, bx)
	xorl %eax, %eax (xor eax, eax)
	movw $1, %ax    (mov ax,1)
	movb X, %ah     (mov ah, byte ptr X)
	movw X, %ax     (mov ax, word ptr X)
	movl X, %eax    (mov eax, X)

Most opcodes are identical between AT&T and Intel format, except for the
addition of the character b/w/l to indicate the operand size. The main
exceptions are:

	movsSD (movsx)
	movzSD (movzx)

Where S and D are the source and destination operand size suffixes,
respectively. For example, "movswl %ax, %ecx (movsx ecx, ax)".

	cbtw        (cbw)
	cwtl        (cwde)
	cwtd        (cwd)
	cltd        (cdq)
	lcall $S,$O (call far S:O)
	ljmp $S,$O  (jump far S:O)
	lret $V     (ret far V)

Memory references are a little bit different too. The usual Intel memory
reference of the form

SECTION:[BASE + INDEX*SCALE + DISP]

is written as

SECTION:DISP(BASE, INDEX, SCALE).

Here are some examples: (Intel equivalent in parentheses)

	movl 4(%ebp), %eax            (mov eax, [ebp+4])
	addl (%eax,%eax,4), %ecx      (add ecx, [eax + eax*4])
	movb $4, %fs:(%eax)           (mov fs:eax, 4)
	movl _array(,%eax,4), %eax    (mov eax, [4*eax + array])
	movw _array(%ebx,%eax,4), %cx (mov cx, [ebx + 4*eax + array])

Jump instructions always use the smallest displacements. The following
instructions always work in byte displacements only, however: "jcxz",
"jecxz", "loop", "loopz", "loope", "loopnz" and "loopne". As suggested
in the online docs, a "jcxz foo" could be expanded to work:

	  jcxz cx_zero
	  jmp cx_nonzero
	cx_zero:
	  jmp foo
	cx_nonzero:

The online docs also caution on "mul" and "imul" instructions. The
expanding multiply instructions are done using ONE operand. For example,
"imul $ebx, $ebx" will NOT put the result in "edx:eax". Use the single
operand form "imul %ebx" to get the expanded result.