Первая программа на GAS

Последнее обновление: 23.09.2023

Создадим первую программу с помощью ассемблера GAS. При создании программы на ассемблере стоит понимать, что это не высокоуровневый язык, где достаточно вызвать одну функцию, которая выполнит всю сложную работу. В ассемблере, чтобы выполнить довольно простые вещи, придется писать довольно много инструкций. И здесь есть разные подходы: мы можем написать весь код только на ассемблере - вариант, который в реальности втречается редко, либо мы можем какие-то части писать на ассемблере, а какие-то на языке высокого уровня, например, на С. В данном случае рассмотрим создание программы целиком на ассемблере, но в дальнейшем посмотрим на второй вариант на примере взаимодействия с языками С и С++.

Итак, напишем программу на ассемблере, которая выводит строку на консоль. Для этого определим на жестком диске папку для файлов с исходным кодом. Допустим, она будет называться asm. И в этой папке создадим новый файл, который назовем hello.s и в котором определим следующий код:

.globl _start

.data 
message: .asciz "Hello METANIT.COM\n"   # текст выводимого сообщения

.text
_start:

    movq $message, %rsi  # в RSI - адрес строки
    movq $1, %rdi        # в RDI - дексриптор вывода в стандартный поток (консоль)
    movq $18, %rdx       # в RDX - длина строки
    movq $1, %rax        # в RAX - номер функции для вывода в поток 
    syscall              # вызываем функцию Linux

    movq $60, %rax
    syscall

Теперь протестируем программу. Откроем консоль и перейдем в ней к папке, где располагается файл hello.s. Затем выполним следующюю команду

as hello.s -o hello.o

В результате ассемблер GAS из кода программы скомпилирует объектный файл hello.o. Далее создадим исполняемый файл, выполнив следующую программу компоновщика:

ld hello.o -o hello

Затем запустим программу командой

./hello

Полный вывод компиляции и выполнения программы:

eugene@Eugene:~/asm# as hello.s -o hello.o
eugene@Eugene:~/asm# ld hello.o -o hello
eugene@Eugene:~/asm# ./hello
Hello METANIT.COM
eugene@Eugene:~/asm#

Вкратце разеберем программу. Вначале идет инструкция

.globl _start

Далее определяет секция данных программы

.data

Эта директива указывает, что дальше располагаются определения данных. В нашем случае это одна переменная message:

message: .asciz "Hello METANIT.COM\n" 

То есть в начале указывается имя переменной - message, а после двоеточия - ее определение. С помощью директивы .asciz мы указываем, что переменная будет представлять строку. Затем идет собственно строка в кавычках - значение переменной message.

С помощью директивы .text открываем секцию кода и затем определяем точку входа в программу - метку _start:

.text
_start:

Далее идут инструкции программы. Суть программы - вывод сообщения message на экран. Но ассемблер по умолчанию не имеет подобного функционала, и обычно в этом случае задействуются системные вызовы текущей операционной системы. В зависимости от конкретной системы детали этих вызовов - их номер и параметры будут отличаться. Например, на Linux это системная функция write, которая имеет номер 1 и которая принимает 3 параметра:

  • В регистр RSI помещается адрес строки

  • В регистр RDI помещается дескриптор вывода - то есть куда выводить строку. К примеру, это может быть файл на диске, консоль и т.д.

  • В регистр RDX помещается количество символов строки

И в соответствии с данным API сначала помещаем в регистр RSI адрес строки message:

movq $message, %rsi

Чтобы указать, что в регистр помещается именно адрес, а не сама переменная, перед названием переменной указывается символ $.

Поскольку мы выводим на консоль, то в регистр RDI надо поместить дескриптор консольного вывода - число 1:

movq $1, %rdi

Далее в регистр RDX помещается количество символов выводимой строки:

movq $18, %rdx

И для вывода строки помещаем в регистр RAX номер системной функции Linux (число 1) и вызываем ее:

movq $1, %rax
syscall

После этого помещаем в RAX номер системной функции завершения приложения - число 60 и также вызываем ее для завершения работы программы:

movq $60, %rax
syscall
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850