Доступ к элементам массива внутри массива - сборка Y86
Мне интересно, что в сборке (в моем случае Y86), возможно ли иметь массив внутри массива? И если это так, как бы я получить доступ к элементам внутри этого массива. Я знаю, что вы разыменовываете массивы, чтобы получить их элементы, но это только с одним массивом в стеке. Есть ли способ получить элемент внутри массива внутри массива.
Пример, потому что это сложно объяснить:
Обычный захват элемента:
array1:
.long 0x0
.long 0x0
.long 0x0
.long 0x0
Main:
pushl %ebp
rrmovl %esp,%ebp
irmovl array1,%edx #store array1 on the stack
pushl %edx
mrmovl (%edx), %eax #get the first element of array1
rrmovl %ebp, %esp
popl %ebp
ret
Теперь скажите, у меня есть это:
array1:
.long 0x0
.long 0x0
.long 0x0
.long 0x0
array2:
.long array1
Могу ли я получить доступ к элементу array2 один, а затем получить доступ к элементам array1?
1 ответ
pushl %edx
не хранит массив в стеке, но адрес памяти первого элемента.
В вашем другом примере первый элемент array2
является 32-битным целочисленным значением, которое равно адресу памяти array1
так что в терминах языка C array2
это массив указателей.
Когда вы получаете первый элемент array2
в некоторый регистр у вас есть "указатель" (адрес памяти), и, выбирая значение с этого адреса, вы получите первый элемент array1
(или вы можете изменить его на некоторое смещение, чтобы получить дополнительные элементы).
Этот шаблон "массив указателей на массивы" часто используется, когда у вас есть несколько массивов одинакового / похожего типа с разной длиной, и вы хотите хранить их непрерывно в памяти, например:
array0:
.long 1, 2, 3
array1:
.long 4
array2:
.long 5, 6, 7, 8
array3:
.long 9, 10
; notice the values in memory form a continuous block of 10 long values,
; so you can also access them through "array0" as single array of 10 values
mainArray:
.long array0, array1, array2, array3
Теперь, если вам нужно значение "[2, 3]", то есть значение "8", вы не можете просто умножить значение строки 2 на "размер столбца", как в примере matrix16x16, потому что строки не имеют фиксированной длины, поэтому вместо этого вы будете вычислять смещение в mainArray
во-первых, как (я буду использовать синтаксис x86 AT&T, потому что я не знаю Y86, но вы должны быть в состоянии понять эту идею, поскольку в основном это одни и те же инструкции, просто у Y86 более ограниченный набор инструкций, и у вас есть больше многословных и загадочный синтаксис с большим количеством частей префикса / суффикса имени инструкции):
; edi = 2 (row), esi = 3 (column)
movl mainArray(, %edi, 4), %ebx ; ebx = mainArray[2] (*4 because pointers are 32 bit)
; (in x86 AT&T syntax the target memory address is "edi*4 + mainArray")
; here ebx = array2 (and "array2" is symbolic name for memory address value)
; it is NOT whole array in single register, just the memory address of first element
movl (%ebx, %esi, 4), %eax ; eax = 8 (array2[3]) (again *4 because longs are used)
; (the target memory address is "ebx + esi*4")
Извините, что не использовал y86, но, как я уже сказал, я этого не знаю... Если у вас возникли трудности с расшифровкой примера x86, попробуйте описать ваши трудности в комментариях, в конце концов я могу попытаться исправить синтаксис для y86, или, может быть, кто-то еще предложит исправления...
Могу ли я получить доступ к элементу array2 один, а затем получить доступ к элементам array1?
Да, конечно, эти значения являются обычными 32-битными целыми числами (адреса памяти тоже на вашей платформе y86), так что вы, конечно, можете извлечь этот адрес под-массива из верхнего массива, а затем получить значение из этого под-массива адрес для достижения "значения". Попробуйте проверить в отладчике, как выглядит память после определения массива и как эти значения представляют ваш исходный код.
Сборка настолько проста и тривиальна, что писать сложные абстракции в ней довольно сложно / утомительно, но пока мы говорим об одной инструкции или доступе к памяти, ожидаем, что все будет очень просто. Если вы видите там некоторую сложность, вы, вероятно, неправильно понимаете, что происходит под колпаком, это всего лишь значения 0/1 бита и немного их перемещают (обычно в обычных количествах, таких как 8, 16, 32 или 64, для другой группы). битов часто требуется несколько инструкций, чтобы получить желаемый результат, в то время как эти выше изначально поддерживаются как byte/short/long/...). Сложность возникает из-за того, как написать этот алгоритм с простыми инструкциями копирования / плюс / минус.