Открыть сервис

GNU Assembler

GNU Assembler (часто сокращается как GAS или As) — это ассемблер, входящий в состав проекта GNU Binutils. Он предназначен для преобразования текста программы, написанной на языке ассемблера, в машинный код (объектные файлы). GAS является стандартным ассемблером для операционной системы GNU/Linux и многих других Unix-подобных систем, а также используется в качестве бэкенда для компилятора GCC (GNU Compiler Collection).

История

GNU Assembler был разработан в 1986—1987 годах как часть проекта GNU, основанного Ричардом Столлманом. Первоначальная версия была написана самим Столлманом. Основной целью создания GAS было обеспечение свободного (в смысле свободы использования и модификации) ассемблера, который мог бы заменить проприетарные ассемблеры, поставляемые производителями UNIX-систем.

На ранних этапах GAS поддерживал только архитектуру VAX. С развитием проекта GNU и появлением поддержки новых процессоров (Motorola 68000, Intel 80386, SPARC, MIPS) GAS стал переносимым ассемблером, способным генерировать код для множества различных архитектур. В 1990-х годах GAS был интегрирован в GCC, что позволило компилятору генерировать ассемблерный код для целей, отличных от первоначальной платформы.

Ключевым этапом развития стало добавление поддержки синтаксиса Intel для архитектуры x86 в версии 2.10 (2000 год), что упростило его использование разработчиками, привыкшими к синтаксису MASM (Microsoft Macro Assembler) или NASM (Netwide Assembler). Тем не менее, по умолчанию GAS продолжает использовать AT&T-синтаксис.

Синтаксис

GAS поддерживает два основных синтаксиса для архитектуры x86/x86-64: AT&T и Intel. Выбор синтаксиса осуществляется с помощью директивы .intel_syntax noprefix или .att_syntax.

AT&T-синтаксис

Это исторически первый и наиболее распространённый синтаксис для GAS. Его ключевые особенности:

  • Порядок операндов: источник (source) указывается первым, приёмник (destination) — вторым. Например, movl %eax, %ebx означает «переместить значение из регистра eax в регистр ebx».
  • Регистры: имена регистров предваряются знаком процента (%). Например, %eax, %rcx, %rsp.
  • Непосредственные значения: константы предваряются знаком доллара ($). Например, movl $42, %eax помещает число 42 в регистр eax.
  • Суффиксы размера: инструкции часто имеют суффикс, указывающий размер операнда: b (byte, 1 байт), w (word, 2 байта), l (long, 4 байта), q (quad, 8 байт). Например, movb (переместить байт), movl (переместить двойное слово).
  • Адресация: адреса памяти записываются в форме смещение(базовый_регистр, индексный_регистр, масштаб). Например, movl %eax, 4(%ebx, %ecx, 2) означает «записать значение eax по адресу ebx + ecx*2 + 4».

Intel-синтаксис

Введён для совместимости с другими популярными ассемблерами. Его особенности:

  • Порядок операндов: приёмник указывается первым, источник — вторым. Например, mov ebx, eax означает «переместить значение из регистра eax в регистр ebx».
  • Регистры: имена регистров пишутся без префикса процента. Например, eax, rcx.
  • Непосредственные значения: константы пишутся без префикса доллара. Например, mov eax, 42.
  • Суффиксы размера: не используются; размер операнда определяется контекстом или явными директивами (например, BYTE PTR, WORD PTR, DWORD PTR).
  • Адресация: адреса памяти записываются в форме [базовый_регистр + индексный_регистрмасштаб + смещение]. Например, mov eax, [ebx + ecx2 + 4].

Директивы ассемблера

GAS включает множество директив (псевдоопераций), управляющих процессом ассемблирования. Некоторые из наиболее часто используемых:

  • .data — объявляет начало секции данных.
  • .text — объявляет начало секции кода.
  • .bss — объявляет начало секции неинициализированных данных.
  • .byte, .word, .long, .quad — резервируют и инициализируют данные указанного размера.
  • .ascii, .asciz, .string — определяют строковые литералы (.asciz добавляет завершающий нулевой байт).
  • .globl (или .global) — объявляет символ глобальным (видимым для линковщика).
  • .equ — присваивает константе значение.
  • .macro / .endm — определяет макрос.
  • .include — включает содержимое другого файла.
  • .section — переключает текущую секцию.
  • .type — задаёт тип символа (например, функция или объект).

Использование

GNU Assembler обычно вызывается через компилятор GCC или напрямую командой as. Типичный рабочий процесс:

  1. Написание исходного файла на ассемблере (например, program.s).
  2. Ассемблирование: as program.s -o program.o (создаётся объектный файл).
  3. Линковка: ld program.o -o program (создаётся исполняемый файл).

GAS также используется GCC для генерации ассемблерного кода из исходников на C/C++. Компилятор сначала транслирует код на C в ассемблерный файл, который затем передаётся GAS для создания объектного файла. Это можно увидеть, используя флаг -S (например, gcc -S program.c).

Поддерживаемые архитектуры

GAS поддерживает широкий спектр процессорных архитектур, включая, но не ограничиваясь:

Преимущества и недостатки

Преимущества

  • Свободное и открытое ПО: GAS распространяется под лицензией GPL, что позволяет использовать его в любых проектах без лицензионных отчислений.
  • Интеграция с GCC: является естественным выбором для проектов, использующих GCC.
  • Кроссплатформенность: доступен практически для всех Unix-подобных систем и может генерировать код для множества архитектур.
  • Поддержка сложных макросов и условного ассемблирования: предоставляет мощные возможности для метапрограммирования.

Недостатки

  • Синтаксис AT&T: для многих разработчиков, привыкших к синтаксису Intel, AT&T-синтаксис кажется менее интуитивным (обратный порядок операндов, префиксы).
  • Меньшая распространённость среди разработчиков под Windows: на платформе Windows доминирует MASM, а в среде разработки для Windows (например, Visual Studio) GAS не используется.
  • Меньшая скорость ассемблирования: по сравнению с некоторыми специализированными ассемблерами (например, NASM или FASM), GAS может быть несколько медленнее, хотя для большинства проектов это несущественно.

Пример программы

Ниже приведён пример программы на GAS для архитектуры x86-64, которая выводит строку «Hello, World!» и завершается. Используется AT&T-синтаксис.

```assembly .section .data hello: .asciz "Hello, World!\n"

.section .text .globl _start _start:

Системный вызов write (номер 1)

movl $1, %eax # номер системного вызова movl $1, %edi # файловый дескриптор (stdout) leaq hello(%rip), %rsi # адрес строки movl $14, %edx # длина строки syscall

Системный вызов exit (номер 60)

movl $60, %eax # номер системного вызова xorl %edi, %edi # код возврата (0) syscall ```

Источники

  1. Free Software Foundation. (2023). Using as: The GNU Assembler. GNU Binutils documentation.
  2. Stallman, R. M. (1987). GNU Emacs Manual. Free Software Foundation.
  3. Love, R. (2007). Linux System Programming. O'Reilly Media.
  4. Kerrisk, M. (2010). The Linux Programming Interface. No Starch Press.
  5. Документация проекта GNU Binutils: https://www.gnu.org/software/binutils/

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →