Синтаксисы 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, 69mnemonic 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, %edimovsx/movzxmovsx edx,almovsbl %al,%edxКоманды SIMD практически совпадают, но придется учитывать порядок операндовПересылка данныхmovd xmm0, eaxmovd %eax, %xmm0 # Перенос 32-бит из CPU в SIMDmovaps 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. Источники Using as AT&T-синтаксис — Википедия Встроенный ассемблер GCC Использование GNU ассемблера as.: Архитектурные особенности GCC-Inline-Assembly-HOWTO Директивы ассемблера GNU | arm | programming Руководство программиста Free Pascal ASM386 Macro Assembler Operating Instructions Крис Касперски "Ассемблер в UNIX mini-faq"
опечатка так же пункт "Получить значение в переменной" звучит невалидно надо переделать на "записать значение в переменную"
TermoSINteZ, спасибо, поправил. В MASM постфиксы двоичного числа B (старое) и Y (новое) чтобы не путать с шестнадцатеричным числом, у которого последняя цифра B, .radix 16 позволяет не ставить после шестнадцатеричного числа постфикс H/h. При включенном .radix 16 число 10B это 2 или 267? Сводная таблица для основных языков: C/C++PascalBASICMASMDEC12121212 (отсутствие постфикса),12d, 12tHEX0xC$C&hC0Ch, 3F800000rOCT014―&o1414o, 14qBIN――&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 не допускается — это шестнадцатеричное кодирование числа, а не десятичная запись.