Article by Ayman Alheraki on January 11 2026 10:37 AM
When it comes to writing assembly code using the GNU Assembler (GAS), understanding the syntax of assembly instructions is paramount. Assembler syntax refers to the rules and structure for writing assembly language instructions in a way that can be understood by
the assembler. GAS primarily supports two instruction syntaxes: AT&T Syntax (which is the default) and Intel Syntax (which can be enabled with the .intel syntax directive). Understanding the differences between these syntaxes is crucial, as they each have distinct formatting conventions for operands, instructions, and overall structure.
In this section, we will explore both syntaxes in detail, discussing their fundamental characteristics, key differences, usage scenarios, and how to switch between them. The section will provide you with a comprehensive understanding of the two syntaxes, ensuring you can write and comprehend GAS assembly code effectively.
The AT&T syntax is the default and widely used syntax in GAS (the GNU Assembler). It is historically derived from Unix and BSD assemblers, and it has remained the standard for many Unix-like operating systems, including Linux. The AT&T syntax is somewhat more verbose than Intel syntax, but it has certain advantages in terms of clarity, particularly for handling registers and operands.
Let’s explore the major elements and conventions of AT&T syntax:
In AT&T syntax, the order of operands is source first, destination second. This is one of the most noticeable differences when comparing it to Intel syntax.
Source operand appears before the destination operand.
This convention is based on the older tradition from early Unix assemblers.
Example in AT&T syntax:
movl %eax, %ebx # Move the value in the eax register to the ebx registerHere, the value in the %eax register (source) is moved into the %ebx register (destination).
Contrast this with Intel syntax, where the destination comes first:
mov ebx, eax # Move the value in eax to ebx
In AT&T syntax, registers are always prefixed with a % symbol. This helps distinguish registers from other operands, such as memory addresses or immediate values.
Example with registers in AT&T syntax:
movl %eax, %ebx # Move the value in eax into ebx
The %eax and %ebx represent registers, while the instruction movl moves a 32- bit value from one register to another.
In AT&T syntax, immediate values (literal constants) are prefixed with a $ symbol.
Example of using an immediate value in AT&T syntax:
movl $5, %eax # Move the immediate value 5 into the eax registerHere, $5 is an immediate value, and it is being moved into the %eax register.
In AT&T syntax, the suffix on each instruction is used to specify the size of the operands. These suffixes indicate the number of bits the instruction will handle and are used to differentiate between operations on bytes, words, long words, and quad words.
Common instruction suffixes:
b: 8-bit operand (byte)
w: 16-bit operand (word)
l: 32-bit operand (long word)
q: 64-bit operand (quad word)
Examples:
xxxxxxxxxx movb $5, %al # Move the immediate byte value 5 into the AL register movw $10, %ax # Move the immediate word value 10 into the AX register movl $100, %eax # Move the immediate long word value 100 into the EAX register movq $500, %rax # Move the immediate quad word value 500 into the RAX registerIn AT&T syntax, memory operands are written in the format
<displacement>(<base>,<index>,<scale>).
The base register is specified first, followed by an index register and an optional scaling factor (commonly 1, 2, 4, or 8), and a displacement (an offset).
Example of memory access in AT&T syntax:
movl 4(%eax), %ebx # Move the value at the memory address (eax + 4) into ebxHere, the 4(%eax) represents the memory address where the displacement 4 is added to the %eax register’s value.
Intel Syntax is often used in tutorials, books, and programming environments that target Intel-based systems or Windows environments. It is the preferred syntax for many other assemblers, such as MASM (Microsoft Assembler). Intel syntax is considered more intuitive for many programmers, especially those coming from higher-level programming languages like C, because it places the destination operand before the source operand.
In GAS, Intel syntax is not the default, but it can be enabled using the .intel syntax
directive.
Operand Order
In Intel syntax, the destination operand comes first, followed by the source operand.
This is opposite of AT&T syntax, where the source operand comes first.
The operand order in Intel syntax is more familiar to those who have experience with high-level languages.
Example in Intel syntax:
mov ebx, eax # Move the value in eax into ebxHere, ebx is the destination, and eax is the source.
In Intel syntax, register names are written without any prefix, unlike AT&T syntax, where the % symbol is used to denote registers.
Example:
mov ebx, eax # Move the value from eax into ebxIn this case, ebx and eax are written directly, without the % symbol.
In Intel syntax, immediate values (constant values) are not prefixed by the $
symbol, unlike in AT&T syntax, where immediate values are prefixed with $.
Example in Intel syntax:
mov eax, 5 # Move the immediate value 5 into eaxHere, 5 is the immediate value being moved into the eax register.
In Intel syntax, the size of the operands is implicitly determined by the size of the registers involved in the operation. Unlike AT&T syntax, where the size is
explicitly written as a suffix (b, w, l, q), in Intel syntax, the size of the operation is inferred from the register. Therefore, no suffix is required on the instruction.
Example:
mov eax, 5 # Move the 32-bit value 5 into eax mov ax, 5 # Move the 16-bit value 5 into axIn this example, the register size (eax for 32-bit and ax for 16-bit) implicitly defines the size of the operands.
In Intel syntax, memory operands are written in a similar way to AT&T syntax, but with a slightly different format. The memory operand format is usually [base + index***scale + displacement]**.
Example of memory access in Intel syntax:
mov eax, [ebx + 4] # Move the value at the memory address (ebx + 4) into eaxThe [ebx + 4] refers to the memory address ebx + 4, and the value stored at this address is moved into eax.
Although GAS defaults to AT&T syntax, it is easy to switch to Intel syntax using the
.intel syntax directive. This directive can be placed at the beginning of the assembly file to change the syntax style.
To switch to Intel syntax in GAS, you can add the following line at the top of your assembly file:
.intel_syntax noprefixThe noprefix option tells the assembler to omit the % prefix for registers, which is common in Intel syntax. If you prefer to keep the % prefixes, you can omit the noprefix option.
To switch back to AT&T syntax in GAS, you can use the .att syntax directive:
.att_syntaxThis will revert the syntax to the default AT&T style, where registers are prefixed with
%, operands follow the source-first format, and immediate values are prefixed with $.
Let’s take a look at the same assembly operation using both AT&T and Intel syntax to see the differences more clearly.
xxxxxxxxxx movl %eax, %ebx # Move the value from eax to ebx addl $1, %eax # Add the immediate value 1 to eaxIntel Syntax Example:
xxxxxxxxxx mov ebx, eax # Move the value from eax to ebx add eax, 1 # Add the immediate value 1 to eaxIn this example:
Operand Order: In AT&T, the source comes first (%eax), and the destination comes second (%ebx). In Intel, the order is reversed.
Register Prefix: AT&T uses the % prefix for registers, whereas Intel does not.
Immediate Values: AT&T uses the $ prefix for immediate values, while Intel does not.
Both AT&T syntax and Intel syntax are supported by GAS, with AT&T syntax being the default. Intel syntax is commonly used in many Windows-based assemblers and is often preferred by developers familiar with Intel-based assembly languages. The decision to use one over the other often comes down to the development environment, platform, and personal preference.
While GAS defaults to AT&T syntax, it is flexible and allows switching to Intel syntax with the .intel syntax directive. Understanding both syntaxes and their differences is essential for low-level programming, enabling you to work effectively across different architectures and assembler environments.