Язык сборки x86: заполнение массива значениями, сгенерированными подпрограммой - PullRequest
0 голосов
/ 30 октября 2019

Редактировать: Большое спасибо за вашу помощь! Я действительно ценю это, потому что по какой-то причине у меня возникли проблемы с концептуализацией сборки, но я собираю ее воедино.

1) Я использую отладчик для поэтапного перехода. Проблема, необработанное исключение в 0x0033366B в Project2.exe: 0xC0000005: место записи нарушения прав доступа 0x00335FF8 возникает в этой строке:

mov [arrayfib + ebp*4], edx     

Is думаю может быть, это потому, что оператор return из другогоЦикл не может быть доступен для основной процедуры, но не уверен - трудно понять, что здесь происходит.

2) Я добавил дополнительные комментарии, надеюсь, сделав это несколько понятнее. Для контекста: я связал модель , которую я использовал для доступа к числам Фибоначчи, и моя цель состоит в том, чтобы заполнить этот массив значениями с циклом от последнего к первому.

.386
.model flat, stdcall 
.stack 4096
INCLUDE Irvine32.inc
ExitProcess PROTO, dwExitCode: DWORD

.data
arrayfib DWORD 35 DUP (99h)

COMMENT !
eax =  used to calculate fibonacci numbers
edi =  also used to calculate fibonacci numbers
ebp =  number of fibonacci sequence being calculated  
edx =  return value of fibonacci number requested
!

.code
main PROC   
;stores n'th value to calculate fibonacci sequence to
mov ebp, 30
mov edx, 0
;recursive call to fibonacci sequence procedure
call FibSequence
mov [arrayfib + ebp*4], edx								
dec ebp
jnz FibSequence 


mov esi, OFFSET arrayfib
mov ecx, LENGTHOF arrayfib 
mov ebx, TYPE arrayfib 
call DumpMem
INVOKE ExitProcess, 0 
main ENDP

;initializes 0 and 1 as first two fibonacci numbers
FibSequence PROC										 
mov eax, 0										
mov edi, 1	

;subrracts 2 from fibonacci number to be calculated. if less than 0, jumps to finish, 
;else adds two previous fibonacci numbers together
L1: 
sub ebp, 2										
cmp ebp, 0 
js FINISH
add eax, edi
add edi, eax
LOOP L1

;stores odd fibonacci numbers 
FINISH:
test eax, 1 
jz FINISHEVEN
mov edx, eax
ret    

;stores even fibonacci numbers
FINISHEVEN:
mov edx, edi
ret


FibSequence ENDP
END main 

1 Ответ

1 голос
/ 30 октября 2019

Ваша функция Фибоначчи уничтожает EBP, возвращая с ним значение меньше нуля.

Если ваш массив находится в начале страницы, тогда arrafib + ebp*4] попытается получить доступ к предыдущей странице и произойдет сбой. Обратите внимание на адрес ошибки 0x00335FF8 - последние 3 шестнадцатеричных цифры - это смещение в виртуальной странице 4k, 0x...3FF8 = 0x...4000 + 4*-2.

Так что именно так и произошло: EBP = -2, когдаВаше mov хранилище выполнено.

(Обычно вызовы функций уничтожают свои аргументы регистров в типичных соглашениях о вызовах, хотя использование EBP для передачи аргументов непривычно. Обычно в Windows вы передаете аргументы в ECX и/ или EDX, и возвращаемся в EAX. Или в стеке, но это отстой в производительности.)

(Есть много других вещей, которые тоже не имеют смысла в вашей функции Фибоначчи, например, я думаю, что выхочу jmp L1, а не loop L1, что похоже на dec ecx / jnz L1 без установочных флагов.


В языке ассемблера каждая инструкция имеет определенный эффект на архитектурное состояние (значения регистров и содержимое памяти). Вы можете посмотреть на этот эффект в справочном руководстве по набору инструкций, например https://www.felixcloutier.com/x86/index.html.

Нет "магии", которая сохраняет регистры для вас. (Ну, MASM будет толкать / выдавать за вас, если вы напишете что-то вроде proc foo uses EBP, но пока вы не поймете, что это делает для вас, лучше , а не , чтобы ассемблер добавил инструкции в ваш код.)

Если вы хотите, чтобы функция сохранила значение EBP своего вызывающего, вам нужно написать функцию таким образом. (например, mov, чтобы скопировать значение в другой регистр.) См. Что такое сохраненные регистры вызывающего и вызывающего абонентов? для получения дополнительной информации об этой идее.

может быть, потому что оператор returnиз другого цикла недоступна основная процедура

Это не имеет никакого смысла.

ret - это то, как мы пишем pop eip. Нелокальных эффектов нет, вам просто нужно убедиться, что ESP указывает на адрес (нажатие на вызов), к которому вы хотите перейти. Ака обратный адрес.

...