Как работает базово-индексная адресация?

addw (%edx,%ecx,4), %ax # базово-индексная адресация
                        # %edx - базовый регистр, адрес массива Numbers,
                        # %ecx - счетчик по элементам, 4 — т. к.
                        # в call-S был объявлен как массив int 

Как работает эта адресация? Точнее нет, как работает она, я понимаю, а вот 4 для чего и за что отвечает не понимаю.

Тип, просто потому что у нас дан массив интов, и чтобы попасть в следующий элемент надо прибавить 4? Или что мы с ней вообще делаем?


Ответы (1 шт):

Автор решения: eanmos

Такая адресация в мануалах Intel описывается следующим образом:

Base + (Index × Scale) + Displacement — Using all addressing components together allows efficient indexing of a two-dimensional array when the elements of the array are 2, 4, or 8 bytes in size.

В синтаксисе языка ассемлера Intel записывается точно также как в мануале:

[Base + Index * Scale + Displacement]

В вашем случае было бы

addw AX, [EDX + ECX * 4 + 0]

Синтаксисе языка ассемлера AT&T сильно отличается от синтаксиса Intel и там такой режим адресации можно записать следующим образом:

displacement(base, index, scale)

Соответственно, в вашем случае:

addw (%edx, %ecx, 4), %ax
      ^~~~  ^~~~  ^ 
      |     |     +-- scale
      |     +-- index
      +-- base

Как это используется

Допустим, у нас есть массив чисел типа int32_t (4 байта) из 32-х элементов:

int32_t array[32];

Тогда чтобы обратиться в пятому элементу массива мы можем использовать следующий режим адресации:

(array, 5, 4)
 ^~~~   ^  ^
 |      |  +-- размер элементов массива
 |      +-- индекс нужного элемента
 +-- адрес самого массива

Это работает, потому что, когда мы умножаем индекс элемента на его размер, то получаем смещение от начала массива, по которому расположен этот элемент. А когда мы прибавим к адресу массива это смещение, то получим адрес самого элемента.


Хотя, для обращения к элементам одномерных статических массивов документация Intel рекомендует использовать (Index × Scale) + Displacement, что и делают компиляторы:

#include <stdio.h>
#include <stdint.h>

const int32_t array[32] = {1, 2, 3, 4, 5, 6};

int
main(void)
{    
    for (size_t i = 0; i < 32; ++i)
        printf("%d\n", array[i]);
}

Обращение к элементам массива компилятор транслирует в следующий код:

movl    array(,%rax,4), %eax
→ Ссылка