Препроцессор

Директивы препроцессора

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

Первая стадия компиляции представляет предобработку кода препроцессором. На этой стадии препроцессор обработывает все директивы препроцессора в исходном коде и заменяет их на соответствующий им код. Рассмотрим некоторые наиболее распространенные директивы препроцессора.

%define

Директиа %define позволяет определить константу:

global _start           

%define MAGIC_NUM   22

section .data
num: db MAGIC_NUM       ; num = 22

section .text

_start:
    mov rdi, MAGIC_NUM  ; в RDI число 22
    mov rax, 60
    syscall

В данном случае определена константа MAGIC_NUM. При обработке препроцессором все вхождения этой контанты в коде будут заменяться на ее значение.

Стоит отметить, что идентификаторы, которые определяются с помощью директив препроцессора, как MAGIC_NUM, еще называются препроцессорными символами (preprocessor symbol). Таким символы позволяют дать более описательные имена для данных и действий программы.

Директивы %define могут определять более сложные выражения. Например:

global _start           

%define set_status mov rdi,
%define STATUS_CODE rax

section .text
_start:
    mov STATUS_CODE, 45
    set_status STATUS_CODE
    mov rax, 60
    syscall

Здесь константа set_status определяет текст "mov rdi,", соответственно все входжения этой константы будут заменяться на данный текст. Второй препроцессорный символ - STATUS_CODE представляет регистр rax.

Одни константы могут зависеть от других:

%define i 1
%define d i * 3

Здесь константы i равна 1, а константа d зависит от i и равна i * 3.

Переопределение и изменение символов

NASM позволяет переопределить препроцессорный символ:

%define num 1

%define num 3

Однако %define имеет проблему - она не позволяет вычислять арифметические выражения, в которых применяется та же константа. Например:

%define num 1

%define num num + 2     ; ! Ошибка

Для подобных случаев NASM предоставляет другую директиву - %assign, которая позволяет изменить значение символа:

%define num 1

%assign num  num + 2

Повторения и циклы

NASM позволяет организовать повторение некоторых действий с помощью директивы %rep:

%rep количество_повторений
повторяемые действия
%endrep

После %rep указывается количество повторений. Действия, которые надо повторять, помещаются между директивами %rep и %endrep. Пример применения:

global _start           

%define num 1

section .data
; цикл, 10 повторений
%rep 10
%assign num num+1
%endrep
status_code: dq num     ; status_code = 11

section .text
_start:
    mov rdi, [status_code]
    mov rax, 60
    syscall

Здесь определяется символ num, который равен 1. В цикле последовательно прибавляем к num единицу. Количество повторений равно 10, поэтому финальное значение символа num равно 11

Циклы позволяют нам создать наборы данных или инструкций. Например, нам надо определить в программе набор факториалов:

global _start           

%define N 5
%define F 1

factorials: 
%assign i 1
%rep N
    %assign F F*i
    db F
    %assign i i+1
%endrep


section .text
_start:
    mov rdi, [factorials+4]     ; пятый факториал
    mov rax, 60
    syscall

Здесь в цикле изменяем значение символа F таким образом, чтобы он представлял произведение всех предыдущих чисел от 1 до i. В результате после прохода препроцессора мы получим следующий набор данных:

factorials: 
db 1
db 2
db 3
db 6
db 24
db 120
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850