Выравнивание

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

Для ускорения доступа объектам в памяти в архитектуре x86-64 может применяться выравнивание. Выравнивание данных не всегда необходимо, так как кэш-архитектура современных процессоров x86-64 на самом деле обрабатывает большинство невыровненных данных. Тем не менее иногда доступ к данным, которые не выровнены по соответствующему адресу, может потребовать дополнительного времени. И если скорость доступа к подобным данным критична, то можно использовать выравнивание.

Выравнивание означает, что адрес объекта является четным и кратен определенному размеру. В качестве такого размера обычно выбирают размер объекта, если он не более 32 байт и является степенью двойки. Для объектов размером более 32 байт обычно достаточно выравнивание объекта по 8-, 16- или 32-байтовой адресной границе. Для установки выравнивания применяется директива align

align выравнивание

В качестве операнда директиве передается целочисленное значение: 1, 2, 4, 8 или 16. Как правило, если нужен максимально быстрый доступ, то необходимо выбирать значение, равное размеру объекта, по которому надо выровнять. То есть для выравнивания по слову (16 бит) применяется выражение align 2, для выравнивания по двойному слову (4 байта) применяется выражение align 4, по четверным словам - align 8 и т.д. Если размер объекта не является степенью числа 2, то обычно для выравнивания используется первая ближайщая степень числа 2 (максимум до 16 байт), большее размера объекта. При этом объекты real80 (и tbyte) выравниваются только по 8 байтам. Например:

.data
    d1 dword 33
    w1 word 22
    b1 byte 11
align 2
    w2 word 10

Если MASM встречает директиву align в разделе .data, он выравняет последующую переменную по адресу, который кратен указанному выравниванию. Если MASM определяет, что текущий адрес директивы align не является целым числом, кратным указанному значению, то после предыдущей переменной добавляются дополнительные байты до тех пор, пока текущий адрес в разделе .data не станет кратен указанному значению.

Первое объявление .data в программе (на Windows) размещает свои переменные по адресу, который кратен 4096 байтам. Какая бы переменная ни появилась первой в этом объявлении .data, она гарантированно будет выровнена. Каждая последующая переменная размещается по адресу, который представляет собой сумму размеров всех предыдущих переменных плюс начальный адрес этой секции .data.

Например:

.data
    d1 dword 33
    w1 word 22
    b1 byte 11
align 2
    w2 word 10
.code
main proc
    mov rax, 0
    mov ax, [w2 - 4]    ; смещаемся назад на 4 байта - [w2-4] = [w1]
    ret
main endp
end

Здесь первые три переменных в сумме занимают 7 байт (4 + 2 + 1):

d1 dword 33
w1 word 22
b1 byte 11

Но за ними идет еще одна переменная с выравниванием по 2 байтам:

align 2
w2 word 10

Поэтому после переменной b1 добавляется еще один байт, чтобы последующая переменная w2 располагалась по четному адресу, который кратен 2. Соотвественно, чтобы перейти от адреса переменной w2 к адресу переменной w1, надо вычесть 4 байта (размер переменной w1 + размер переменной b1 + 1 байт для установки выравнивания). И в данном случае в регистре AX окажется значение переменной w1.

mov ax, [w2 - 2]    ; [w2-2] = [b1]

Без выравнивания для перехода от адреса переменной w2 к адресу переменной w1 потребовалось бы смещение назад на 3 байта:

.data
    d1 word 33
    w1 word 22
    b1 byte 11
    w2 word 10  ; переменная w2 не выравнена
.code
main proc
    mov rax, 0
    mov ax, [w2-3]    ; смещаемся назад на 3 байта
    ret
main endp
end

Выравнивание делает программу немного больше (на несколько байтов), однако в обмен получаем более быстрый доступ к данным. Учитывая, что программа увеличится всего на несколько байтов, то это может быть неплохим решением.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850