subl (%eax), %esp
читает содержимое адреса, обозначенного значком eax
.
Это скорее всего то, что вы не хотите делать в этом контексте.
Если eax
- это размер в байтах массива, то subl %eax, %esp
выделяет для этого достаточно памяти.
Если eax
- это число 32-разрядных целых чисел массива, то leal (,%eax,4), %esp
является правильной инструкцией.
Ни одна из приведенных выше инструкций не учитывает выравнивание стека.
Для правильного возврата из процедуры вы должны иметь возможность правильно отменить описанные выше шаги - отслеживать количество, необходимое для выполнения этого.
Вы можете получить доступ к элементам массива через указатель кадра, если таковой имеется, или непосредственно как положительное смещение от esp
.
Что касается других вопросов - это действительно обычные вопросы C, любой учебник C охватывает такие темы.
Если вы находитесь в тупике при переключении с C на сборку, вы можете позволить компилятору вдохновить вас.
Ниже the code generated by GCC для функции, которые напоминают тот, который вы хотите реализовать (как я понял):
#include <stdio.h>
void foo(int n)
{
int arr[n];
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
}
.LC0:
.string "%d"
foo(int):
pushl %ebp
movl %esp, %ebp ;Prologue
pushl %edi
pushl %esi
movl 8(%ebp), %edi ;EDI = n
pushl %ebx
leal 4(,%edi,4), %eax ;EAX = n*4+4 (For alignment purpose)
subl %eax, %esp ;Allocate space
;Pre loop condition
testl %edi, %edi
jle .L1
;Loop init
movl %esp, %esi ;ESI = ptr to first element
xorl %ebx, %ebx ;EBX = Counter
.L5:
;scanf("%d", &arr[i]);
pushl %esi
pushl $.LC0
addl $1, %ebx ;Inc counter
addl $4, %esi ;Move pointer
call scanf
;Loop condition
cmpl %ebx, %edi
popl %eax
popl %edx
jne .L5
.L1:
leal -12(%ebp), %esp ;Deallocate
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
Для целей этого ответа я предполагал существование VLAs, которое не является обязательным в C11 и на самом деле не сопоставляет один-к-одному с возможностями программиста сборки для роста и сжатия стека.