Сравнение синтаксисов Intel и AT&T

Тема в разделе "GAS/AT&T", создана пользователем Mikl___, 11 сен 2026 в 12:29.

  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.282
    Синтаксисы Intel и AT&T — это два разных способа записи ассемблерных инструкций для архитектуры x86/x64. Описывают одни и те же машинные команды, но по‑разному оформляют их в исходном коде.
    История
    Синтаксис AT&T возник в контексте разработки операционной системы UNIX. Исходные версии UNIX были написаны на ассемблере для PDP-11, где использовался синтаксис, ставший предшественником AT&T. Когда архитектура x86 (Intel 8086, 80286, 80386) стала популярной, компания AT&T портировала на неё свои инструменты, включая ассемблер. В результате для x86 был принят синтаксис, основанный на традициях PDP-11 и VAX, а не на синтаксисе, предложенном Intel.
    В 1980-х годах, с распространением UNIX-систем на платформе x86 (например, Xenix, System V), синтаксис AT&T стал стандартом де-факто для этой операционной среды. Позднее, с появлением проекта GNU и созданием ассемблера GAS (GNU Assembler), синтаксис AT&T был выбран в качестве основного режима работы по умолчанию. Это было обусловлено тем, что GAS разрабатывался как часть набора компиляторов GNU, ориентированного на UNIX-подобные системы. Хотя GAS поддерживает и синтаксис Intel (через директиву .intel_syntax), синтаксис AT&T остаётся его родным и наиболее тесно интегрированным с другими инструментами GNU, такими как GCC и GDB.
    Ассемблеры, поддерживающие синтаксис AT&T
    • GAS (GNU Assembler) — входит в комплект компиляторов GCC, используется в Unix-подобных системах. Синтаксис AT&T характерен для Unix-подобных систем, так как Unix изначально разрабатывался в AT&T Bell Labs. GAS может работать как в режиме AT&T, так и в режиме Intel. Переключение между режимами осуществляется директивами .intel_syntax noprefix и .att_syntax для возврата к AT&T
    • LLVM Integrated Assembler (llvm-mc) — встроенный ассемблер инфраструктуры LLVM. Поддерживает синтаксис GAS и может использоваться как его прямая замена.
    • Free Pascal (встроенный ассемблер) — для процессоров x86 Free Pascal использует AT&T-синтаксис во встроенном ассемблере, исторически опирается на GAS.
    • AS (System V/386 Assembler) — ассемблер, давший название синтаксису. Разработан в AT&T Bell Labs для PDP-11 и унаследован в Unix-системах. В современных дистрибутивах Linux as символическая ссылка на GAS
    • Rust (asm! macro) — встроенный ассемблер Rust использует LLVM IAS "под капотом" и по умолчанию работает в режиме Intel на x86-64, но поддерживает AT&T-синтаксис через опцию options(att_syntax)
    • YASM (Yet Another Assembler) — первоначально задуман как переработка NASM. YASM кроссплатформенный, распространяется под лицензией BSD и поддерживает несколько форматов выходных файлов (ELF32/ELF64 (Linux/Unix), Mach‑O (macOS), COFF/MS COFF/MS64 COFF (Windows), RDOFF2 (чистый бинарный файл)). Поддерживает оба синтаксиса, выбор делается через опцию -p (например, -p gas).
    Основные отличия синтаксисов Intel и AT&T
    синтаксис
    IntelAT&T
    Порядок
    операндов
    mnemonic dest, src (приёмник источник)
    imul ebx, eax, 69
    mnemonic src, dest (источник приёмник)
    imull $69, %eax, %ebx
    Префикс
    регистров
    Просто имя: eax, ebxПеред именами регистров всегда ставится %:
    • 64-битные регистры %rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rbp, %rsp, %r8-%r15
    • 32-битные регистры %eax, %ebx, %ecx, %edx, %edi, %esi, %ebp, %esp, %r8d-%r15d
    • 16-битных их младших половин: %ax, %bx, %cx, %dx, %di, %si, %bp, %sp, %r8w-%r15w.
    • 8-битные регистры: %ah, %al, %bh, %bl, %ch, %cl, %dh, %dl, %dil, %sil, %bpl, %spl, %r8b-%r15b
    • сегментные регистры %cs, %ds, %ss, %es, %fs, %gs.
    • yпpавляющие регистры %cr0, %cr2 , %cr3.
    • регистры отладки %db0, %db1, %db2, %db3, %db6 и %db7
    • тестовые регистры %tr6 и %tr7
    • регистры FPU: %st или %st(0), %st(1), %st(2), %st(3), %st(4), %st(5), %st(6) и %st(7)
    то, что вы должны ставить префикс % перед именем регистра, позволяет создавать переменные с тем же именем, что и регистры, что невозможно в синтаксисе Intel
    Размер
    операнда
    Задаётся явно в операнде или подразумевается контекстом:
    mov eax, ebx
    Размер операнда задается суффиксом, замыкающим инструкцию:
    movl %ebx, %eax
    movb %al,%ah
    movw %ax,%bx
    movq %rsi,%rbp
    addl, subl, incl, decl, divl, imull, lcall (call far)/call (call near), ljmp (jmp far)/jmp (jmp near), lret (retf)/ret (retn), pushl, leal, andl, orl, xorl, cmpl
    • b — байт (8-bit)
    • w — слово (16-bit)
    • l — двойное слово (32-bit)
    • q — учетверенное слово (64-bit)
    • x — 16 байт (128-bit vector)
    • y — 32 байта (256-bit vector)
    • z — 64 байта (512-bit vector)
    для чисто векторных операций (вроде addps) суффиксы обычно совпадают с синтаксисом Intel
    Константы
    • десятичное: mov rsi,11
      (mov rsi,11d)
    • двоичное: mov rsi,1011b
      (mov rsi,1011y)
    • шестнадцатеричное: mov rsi,0Bh
    • восьмеричное: mov rsi, 13o
      (mov rsi, 13q)
    используем $, числовые константы записываются в Си-соглашении:
    • десятичное: movq $11,%rsi
    • двоичное: movq $0b1011, %rsi
    • шестнадцатеричное: movq $0xb, rsi
    • восьмеричное: movq $013,%rsi
    Адреса
    памяти
    Квадратные скобки:
    [ebx+4]
    [rbp-8]
    Круглые скобки, смещение перед регистром:
    4(%ebx)
    -8(%rbp)
    Косвенная
    адресация/
    переходы
    • jmp eax
    • jmp [addr]
    • mov RDI,[RBX]
    • jmp table[ecx*4]
    • lea eax,[ebx+ecx]
    звёздочка для косвенности:
    • jmp *%eax
    • jmp *addr
    • movq (%rbx), %rdi
    • jmp *(table, %ecx, 4)
    • leal (%ebx,%ecx),%eax
    Переход
    по метке
    jmp label

    jmp dword ptr [label]
    jmp label
    # метка — адрес перехода
    jmp *label
    # в ячейке label хранится адрес перехода
    Масштабируемая
    индексация
    [ebx + ecx*4 + 8]
    база+индекс*масштаб+смещение
    8(%ebx, %ecx, 4)
    смещение (база, индекс, масштаб)
    ОСWindows, DOSLinux/Unix
    Комментарий
    однострочный
    ;
    • #
    • //
    • /* */
    Комментарий
    многострочный
    comment/* */
    Получить адрес
    переменной
    mov RSI, offset message
    lea RSI,message
    используем $: movq $message,%rsi
    не используем $: lea message(%rip), %rsi
    Значение
    переменной
    mov count,ecxне используем $: movl %ecx,count
    Типы
    целочисленных
    данных

    • DB (BYTE, SBYTE)
    • DW (WORD, SWORD)
    • DD (DWORD, SDWORD)
    • DQ (QWORD)
    • OWORD

    • .byte
    • .short (.word)
    • .long
    • .quad
    • .octa
    Типы
    вещественных
    данных

    • DD (REAL4)
    • DQ (REAL8)
    • DT (TBYTE, REAL10)

    • .float
    • .double
    • .tfloat
    Повторениеzeros dd 10 dup (0)zeros: .fill 10, 4, 0
    buffer1: .skip 1024, 22
    # каждый из 1024 байтов равен 22
    Определение
    константы
    Имя equ значение
    Имя = значение
    MAX_BUFFER TEXTEQU 1024
    ; Символ, созданный через TEXTEQU, можно переопределять (изменять) в коде сколько угодно раз. Директива EQU такого не позволяет
    name_macro TEXTEQU <"Hello, World!">
    ;Применяется для макросов, замены фрагментов текста, инструкций или имен регистров
    .equ Имя значение
    Имя = значение
    .equ MAX_BUFFER, 1024
    # Определение константы
    .set TEMP_REG, %eax
    # Еще один вариант, часто используется для регистров
    Определение
    данных
    Имя тип значениеИмя: .тип значение
    Строка из символов
    • Hello db 'Hello, world!',0
    • Alphabet db 'abcdef'
    • Hello: .asciz "Hello, world!"
    • Alphabet: .ascii "abcdef"
    Внутри кавычек могут быть \n \t \r
    Резервирование
    памяти
    Когда надо определить набор байтов, при этом значение каждого байта не важно (например, когда надо просто определить буфер для считывания данных с файла)
    buffer dd 1024 dup(?)
    применяется директива .skip, .space или .zero.
    Директивы с аргументом представляющим количество резервируемых байт, числа в наборе инициализируются нулем
    buffer1: .skip 1024
    # каждый из 1024 байтов равен 0
    buffer2: .space 512
    # каждый из 512 байтов равен 0
    buffer3: .zero 256
    # каждый из 256 байт равен 0
    Команды преобразования размера
    • cbw
    • cwde
    • cwd
    • cdq
    • cdqe
    • cqo

    • cbtw
    • cwtl
    • cwtd
    • cltd
    • cltq
    • cqto
    Строковые
    команды

    • lodsb/lodsw/lodsd/lodsq
    • stosb/stosw/stosd/stosq
    • movsb/movsw/movsd/movsq
    • scasb/scasw/scasd/scasq
    • cmpsb/cmpsw/cmpsd/cmpsq
    • lodsb/lodsw/lodsl/lodsq
    • stosb/stosw/stosl/stosq
    • movsb/movsw/movsl/movsq
    • scasb/scasw/scasl/scasq
    • cmpsb/cmpsw/cmpsl/cmpsq
    Префиксы REP, REPE, REPNE совпадают: rep movsl
    могут указываться регистры: movsb %esi, %edi
    movsx/movzxmovsx edx,almovsbl %al,%edx
    Команды SIMD практически совпадают, но придется учитывать порядок операндов
    Пересылка данныхmovd xmm0, eaxmovd %eax, %xmm0
    # Перенос 32-бит из CPU в SIMD
    movaps xmm1, [rbx]movaps (%rbx), %xmm1
    # Загрузка 128-бит вектора (выровненного)
    Сложениеpaddd xmm0, [rcx]paddd (%rcx), %xmm0
    # Поэлементное сложение четырех 32-битных целых
    addps xmm0, xmm1addps %xmm1, %xmm0
    # Сложение 4-х single float (SSE)
    vaddps ymm0, ymm1, ymm2vaddps %ymm2, %ymm1, %ymm0
    # Сложение 8-ми single float (AVX, 3 операнда)
    Умножениеmulpd xmm0, xmm1mulpd %xmm1, %xmm0
    # Векторное умножение double float
    Применение
    Синтаксис AT&T является доминирующим в следующих областях:
    • Разработка под Linux и другие UNIX-подобные системы: Абсолютное большинство встроенного ассемблерного кода в ядре Linux, драйверах и системных библиотеках написано с использованием синтаксиса AT&T. Компилятор GCC, при вставке ассемблерного кода на C (inline assembly), по умолчанию использует именно этот синтаксис.
    • Reverse Engineering в среде Linux: Дизассемблеры, такие как objdump (с флагом -d), по умолчанию выводят код в синтаксисе AT&T. Для получения синтаксиса Intel требуется явно указать флаг -M intel.
    • Отладка с использованием GDB: Отладчик GNU GDB (GNU Debugger) по умолчанию отображает дизассемблированный код в синтаксисе AT&T. Это может быть изменено командой set disassembly-flavor intel.
    • Образовательные курсы по системному программированию: Многие университетские курсы, особенно в рамках изучения операционных систем и архитектуры компьютеров, используют синтаксис AT&T, так как он тесно связан с инструментарием GNU.
    Критика со стороны приверженцев синтаксиса Intel
    Синтаксис AT&T неинтуитивен для начинающих и избыточно многословен по сравнению с синтаксисом Intel.
    • Обратный порядок операндов: Главный источник ошибок для человека привыкшего к синтаксису Intel, путаница источника и приемника в AT&T приведет к неверным результатам.
    • Избыточные символы: Необходимость ставить % перед регистрами и $ перед константами делает текст программы более громоздким и менее читаемым, особенно при работе с длинными строками.
    • Сложность адресации
    • Неочевидность суффиксов: Хотя суффиксы размера (b, w, l, q) делают размер операнда явным, но добавляют лишний символ к каждой инструкции, что увеличивает объём программ.
    Тем не менее, синтаксис AT&T — стандарт для инструментов GNU, используется в сообществе разработчиков открытого программного обеспечения. Изучение синтаксиса AT&T необходимо для понимания работы ОС семейства UNIX и низкоуровневого программирования на платформе x86-64.
    Источники
     

    Вложения:

    Последнее редактирование: 13 сен 2026 в 07:08
    Application и MaKsIm нравится это.
  2. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.570
    Адрес:
    Russia
    опечатка

    так же пункт "Получить значение в переменной" звучит невалидно
    надо переделать на "записать значение в переменную"
     
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.282
    TermoSINteZ,
    спасибо, поправил. В MASM постфиксы двоичного числа B (старое) и Y (новое) чтобы не путать с шестнадцатеричным числом, у которого последняя цифра B, .radix 16 позволяет не ставить после шестнадцатеричного числа постфикс H/h. При включенном .radix 16 число 10B это 2 или 267?
    Сводная таблица для основных языков:
    C/C++PascalBASICMASM
    DEC12121212 (отсутствие постфикса),12d, 12t
    HEX0xC$C&hC0Ch, 3F800000r
    OCT014&o1414o, 14q
    BIN&b11001100b, 1100y
    «Microsoft Macro Assembler Programmer's Guide» MASM 6.1 Глава 1 «Understanding Global Concepts», раздел «Integer Constants and Constant Expressions», стр 31 — «y for binary (or b if the default radix is not hexadecimal)»
    И чтобы не упрекнули что R не используется для 16-ричных чисел «Microsoft Macro Assembler Programmer's Guide», глава 6, стр 157 — «Using Floating-Point Numbers». «The number must begin with a decimal digit (0–9) and end with the real-number designator (R). For example, the hexadecimal number 3F800000r can serve as an initializer for a doubleword-sized variable.»
    Правила для суффикса R
    Из Programmer's Guide:
    • Количество шестнадцатеричных цифр должно точно соответствовать размеру типа: 8 цифр для REAL4 (32 бита), 16 цифр для REAL8 (64 бита), 20 цифр для REAL10 (80 бит).
    • Если добавляется ведущий ноль, то 9, 17 и 21 цифра соответственно.
    • Точка (.) в записи с суффиксом R не допускается — это шестнадцатеричное кодирование числа, а не десятичная запись.
     

    Вложения:

    Последнее редактирование: 13 сен 2026 в 04:59
    Ahimov нравится это.