Читать книгу Ассемблер ARM64 (Андрей Викторович Ипполитов) онлайн бесплатно на Bookz (2-ая страница книги)
bannerbanner
Ассемблер ARM64
Ассемблер ARM64
Оценить:

5

Полная версия:

Ассемблер ARM64


Общие регистры общего назначения (X0–X30)


X0–X30

– 31 регистр общего назначения по 64 бита.

X0–X7

– используются для передачи аргументов и возвращаемых значений по вызовам (первый аргумент в

X

0 и т.д.; до

X

7).

X8

временный

/внутренний регистр (indirect result location / intra-procedure-call scratch).

X9–X15

– временные (

scratch

) регистры.

X16–X17

IP

0,

IP

1 – плейсхолдеры для промежуточных значений/внутренних вызовов (

intra

procedure

call

scratch

). Часто используются как регистры для вызовов в связке с межпроцедурными вызовами.

X18

platform

register

(может быть зарезервирован ОС/платформой). На

Linux

обычно свободен для использования как

General

Purpose

в пользовательском коде, но системные соглашения могут отличаться.

X19–X28

– калл‑сейв регистры

(callee-saved):

вызываемая функция обязана сохранять/восстанавливать их, если использует.

X29

Frame Pointer (FP)

по соглашению

(

если используется опорный кадр

).

X30

Link Register (LR)

– содержит адрес возврата при вызове

BL/BLR.

Регистры 32‑битной части именуются

W0

W30;

операции над

Wn

пишут старшие биты

Xn

обнуляя (

zero

extend

).


Stack Pointer и спецификации

SP

Stack

Pointer

, 64‑бит (есть и

WSP

для 32‑бит операций).

SP

всегда должен быть выровнен по 16 байтам согласно

ABI

при вызове функций.

Используйте

FP

(

X

29) и

LR

(

X

30) для организации кадра, если нужен

frame

pointer

; многие компиляторы могут его не использовать (

frame

pointer

omission

).


Специальные регистры

NZCV

– флаги состояния

(Negative, Zero, Carry, oVerflow)

в регистре

PSTATE

, устанавливаются арифметическими/логическими инструкциями с суффиксом

S

(например

, ADDS).

PC

Program

Counter

(не адресуем напрямую как общий регистр, но читается/изменяется косвенно при ветвлениях).

PSTATE

– процессорное состояние (флаги и состояние исключений/режимов). Доступ ограничён; для чтения/записи используются специальные инструкции или системные привилегии.

NZCV

– можно получить через

MRS/MRS instructions

в привилегированных контекстах или специальные псевдоинструкции ассемблера.


Регистры находятся внутри процессорного ядра, поэтому доступ к ним происходит быстрее, чем к любой памяти (кеш, ОЗУ). Именно благодаря регистрами процессор может выполнять инструкции за несколько тактов, а не за десятки, как при работе с внешней памятью.


Команды

Каждая команда (инструкция) представлена фиксированным 32‑битным машинным кодом, но в исходном тексте она записывается в более читаемом виде:

<операция> <операнд1>, <операнд2>, <операнд3> ; комментарий

операция – мнемоника (например

, ADD, LDR, B).

операнды – регистры, константы, метки, смещения и т.п.

комментарий – начинается с ; и игнорируется компилятором.


Директивы

Директивы – это команды, которые обрабатываются только на этапе ассемблирования. Они не попадают в машинный код, а управляют размещением данных, определяют символы, задают параметры сборки и т.п.


ДИРЕКТИВА

НАЗНАЧЕНИЕ

ПРИМЕР ИСПОЛЬЗОВАНИЯ


.text

Открывает секцию кода (инструкций). По умолчанию размещается в исполняемой памяти.

.text


.data

Открывает секцию данных (инициализированных).

.data


.bss

Открывает секцию неинициализированных данных (выделяется в памяти, но не хранится в объектном файле).

.bss


.global / .globl

Делает символ (метку) видимым за пределами текущего файла (экспорт).

.global _start


.type

Указывает тип символа (функция, объект). Требуется для некоторых линкеров.

.type _start, %function


.size

Задает размер функции/объекта (используется при отладке).

.size _start, . – _start


.align

Выравнивает следующую секцию/данные по указанному границе (в байтах или степеням двойки).

.align 4

;выравнивание по 16 байт


.org

Устанавливает текущий смещение (адрес) внутри секции.

.org 0x1000


.equ / .set

Определяет константу (символ‑замену).

.equ BUFFER_SIZE, 256


.macro / .endm

Объявление макроса, который может принимать параметры.

.macro push_regs regliststp \reglist, [sp, #-16]!.endm


.if / .else / .endif

Условная ассемблирование (компиляция части кода только при выполнении условия).

.if __ARM_FEATURE_CRYPTO__ .inst 0xd503201f.endif


.include

Включает внешний файл (аналог #include).

.include "constants.inc"


.byte, .hword, .word, .dword

Вставка данных фиксированного размера (8, 16, 32, 64 бит).

.word 0xDEADBEEF


.ascii / .asciz

Вставка строк без/с нулевым терминатором.

.asciz "Hello, world\n"


.skip / .space

Заполняет область нулями (или другим значением) заданного размера.

.skip 64


.section

Открывает произвольную секцию с указанием атрибутов (например, .section .rodata,"a").

.section .rodata,"a"


.func / .endfunc

Явно ограничивает границы функции (полезно для отладчиков).

.func my_func … .endfunc


.cfi_*

Директивы для генерации информации о раскладке стека (Call Frame Information) – нужны отладчикам и исключениям.

.cfi_startproc … .cfi_endproc


Как они взаимодействуют

Секции (.text, .data, .bss, .rodata и т.п.) определяют, где в объектном файле будет размещён код или данные.

Выравнивание (.align, .org) гарантирует, что последующие инструкции/данные находятся на корректных границах, что критично для производительности и корректного доступа к памяти.

Экспорт/импорт (.global, .type) позволяют другим объектным файлам видеть функции/переменные.

Константы и макросы (.equ, .macro) упрощают поддержку кода и позволяют менять параметры без правки множества мест.

Условные директивы (.if/.else/.endif) позволяют писать один файл, который собирается по‑разному для разных целевых платформ (например, наличие криптографических инструкций).


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


Выравнивание (Alignment)

Процессоры, работают эффективнее, когда доступ к данным происходит по адресам, кратным размеру этих данных.

32-битные данные (4 байта) лучше всего загружаются/сохраняются по адресам, кратным 4.

64-битные данные (8 байт) лучше всего загружаются/сохраняются по адресам, кратным 8.

Если вы попытаетесь загрузить 64-битное значение по адресу, не кратному 8, это может привести к:

Исключению (

Alignment

Fault

): Процессор может вызвать ошибку.

Снижению производительности: Процессор может выполнить несколько операций для чтения данных, или операционная система может исправить ошибку “на лету”, что замедлит выполнение.

Ассемблер и линкер на macOS обычно автоматически позаботятся о выравнивании для статических данных (используя директивы типа .align). Однако, при работе с динамической памятью или при ручном управлении смещениями, вам может потребоваться учитывать выравнивание самостоятельно.



Глава 3 Инструкции по передачи данных


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


Перемещение константы в регистр

Инструкция MOV является основным инструментом для копирования значений. Когда речь идет о перемещении константы (непосредственного значения) в регистр, MOV также является выбором номер один.


MOV , #immediate


:

Регистр назначения, куда будет помещено непосредственное значение. Это может быть 64-битный регистр (

x

0-

x

30,

xzr

) или 32-битный регистр (

w

0-

w

30,

wzr

).

#immediate:

Непосредственное значение, которое должно быть помещено в регистр.

Как это работает:

Инструкция MOV с непосредственным значением напрямую встраивает значение в код программы. Ассемблер преобразует это число в машинный код, который процессор может непосредственно использовать.


; Поместить число 100 в 64-битный регистр x0

mov x0, #100


После выполнения этой инструкции, регистр x0 будет содержать значение 100. Старшие 32 бита регистра x0 будут заполнены нулями, поскольку 100 – это положительное число, помещающееся в 32 бита.

Перемещение 32-битного значения:


mov x1, #255


После выполнения этой инструкции, младшие 32 бита регистра x1 (т.е. w1) будут содержать 255. Старшие 32 бита регистра x1 будут обнулены.


mov x5, #0


Хотя это работает, более идиоматичным и часто более эффективным способом обнуления регистра является использование нулевого регистра xzr (или wzr для 32-битных):


mov x5, xzr ; x5 = 0


Это потому, что xzr всегда содержит 0, и эта инструкция является простой копией из специального регистра.


Перемещение отрицательных чисел:


; Поместить число -1 в 64-битный регистр x0

mov x0, #-1


В двоичном представлении -1 – это все единицы. Поэтому x0 будет содержать 0xFFFFFFFFFFFFFFFF.


Ограничения на размер непосредственного значения:


Важно понимать, что ARM64 имеет ограничения на размер непосредственного значения, которое может быть напрямую встроено в инструкцию MOV. Обычно это 12-битное или 16-битное значение, которое может быть расширено (но не бесконечно).

Конец ознакомительного фрагмента.

Текст предоставлен ООО «Литрес».

Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.

Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.

Вы ознакомились с фрагментом книги.

Для бесплатного чтения открыта только часть текста.

Приобретайте полный текст книги у нашего партнера:


Полная версия книги

Всего 10 форматов

bannerbanner