Ваша проблема не имеет ничего общего с доступом к элементам массива - ваша логика верна (хотя imul eax,4
- плохая идея и должна быть заменена на shl eax,2
или lea eax,[eax*4]
или lea eax,[ebx+eax*4]
, потому что смещение вмассив не является значением со знаком, и это ускорение позволяет избежать этого умножения).
Вместо этого;ваша проблема в том, что соглашения о вызовах в C неприятны. Они загрязняют код множеством дополнительных инструкций для манипулирования стеком, которые затрудняют чтение и отладку кода;и его оптимизация (например, использование sub esp, ...
для резервирования места для макс. параметров, которые вы хотите передать любой дочерней функции, и mov [rsp+ ...], ...
вместо push ...
для установки параметров перед вызовом дочерней функции) является болезненным;и все это в итоге приводит к ошибкам и медленному беспорядку (который не нужен для сборки, если вы не вызываете функции, скомпилированные компилятором C).
Более конкретно;для вашего GetElement
вы используете ebp
в качестве фрейма стека, но не устанавливаете ebp
в качестве фрейма стека, поэтому, когда функция пытается получить параметры из стека в регистры, функция не получает параметрыиз правильного местоположения.
Чтобы на самом деле соответствовать соглашениям о вызовах C (CDECL), было бы больше похоже на:
GetElement:
push ebp
mov ebp,esp ;Set up ebp as stack frame
push ebx ;ebx is "callee preserved" (not "caller saved") and is modified, so it must be saved/restored
push esi ;esi is "callee preserved" (not "caller saved") and is modified, so it must be saved/restored
mov ebx,[ebp+3*4+4] ;addr of array
mov ecx,[ebp+3*4+4+4] ;row
mov esi,[ebp+3*4+4+8] ;col
mov eax,ecx
mul dword [col]
add eax,esi
lea eax,[ebx+eax*4]
pop esi
pop ebx
leave
ret
Как ни странно, для вашего кода параметры уже находятся в регистрах- единственный вызывающий абонент делает это:
push ecx ;col
push edx ;row
push esi ;address of array
call GetElement
add esp,12
.. это означает, что (если вы забудете о соглашениях о вызовах C), ваш GetElement
может выглядеть следующим образом (удалено 10 ненужных инструкций):
;Inputs:
; ecx = column
; edx = row
; esi = address of array
;
;Outputs:
; eax = address of element in the array
;
;Trashed:
; edx
GetElement:
mov eax,edx
mul dword [col]
add eax,ecx
lea eax,[esi+eax*4]
ret
.. и вызывающий код может быть таким (удалено 4 ненужных инструкции):
call GetElement