2017-01-30 12 views
0

Предположим, что размер целочисленного массива хранится в eax. Я полагаю, вы можете вы можете выделить память для массива следующим образом:Как создать массив размером x для стека и значений scanf в нем

subl (%eax), %esp 

Однако размер в EAX обеспечивается пользователем и будет другой размер с каждым выполнением программы. Учитывая это, как инициализировать каждый 4-байтовый адрес памяти целым числом, предоставленным пользователем с помощью scanf? Как мы можем гарантировать, что если больше целых чисел, чем размер массива, мы не перезаписываем какую-либо память?

ответ

2

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 и на самом деле не сопоставляет один-к-одному с возможностями программиста сборки для роста и сжатия стека.