In short: the program does not work, because in the function function you forgot to add a prolog.
The prologue stores the value of the stack pointer as of the beginning of the function. Because there is no prologue, then the value of ebp , which is set in the calling function CMAIN (the value of esp before entering the function and before sending the arguments to the stack). What happens as the program runs (remember that the stack grows in the direction of smaller addresses, when push , esp decreases first, then the value is added to [esp] ):
mov ebp, esp ; пока что esp == ebp push 0 ; значение esp уменьшается на 4, по адресу [esp] кладется 0, esp == ebp - 4 push 8 ; ..., esp == ebp - 8 push array ; esp == ebp - 12 call function ; значение esp уменьшается на 4, в стек кладется адрес возврата, происходит переход на функцию
After entering the function esp == ebp - 16
From here it turns out that:
- Address
[esp] is the return address of the function - The array address is located at
[esp+4] (at the time the function is entered) or [ebp-12] - The size of the array is located at
[esp+8] or [ebp-8] - The x value is located at
[esp+12] or [ebp-4]
It turns out that in fact at the address [ebp+8] is not what you expected, some completely extraneous data. You interpret this data as an address (which is roughly equivalent to a call using an uninitialized pointer in C / C ++), a range of addresses that are not allowed for your program is accessed, we get segfault.
What should be corrected besides the prologue:
- For a proper stack alignment (by convention stdcall), the operand value of
ret must be equal to the size of the arguments, i.e. must be ret 12 (3 arguments by 4 bytes). - if there is a prologue in the function, then each
ret in this function should execute an epilog (you have an epilog in function only before one of ret ). If the epilogue is not added, then the saved ebp value will not be pulled out of the stack, which will be interpreted by the ret command as the return address, and the return will occur in the stack area, and then the data will be executed as code, everything is bad (although most likely the stack will be protected from execution and the program will fall with the exception).
Here is an option with minimal fixes (compiled with fasm):
include 'win32ax.inc' .data array dw 384,64,80,208,144,48,-768,-768 .code CMAIN: ; В этой функции пролог/эпилог не нужны, т.к. аргументов и локальных переменных нет push 0 push 8 push array call function ret function: push ebp mov ebp, esp ; после выполнения пролога в [ebp] сохраненное значение регистра ebp, ; в [ebp+4] - адрес возврата, в [ebp+8] - адрес массива, и т.д. mov eax, 0 mov esi, 0 mov edx, [ebp+8] ;(array) cmp edx, 0 je error_end mov ecx, [ebp+12] ; (N elements in array) cmp ecx, 0 jl error_end loop_start: mov edi, [edx+esi*2] cmp edi, ebx jg inc_eax inc_eax: inc eax jng go_on go_on: inc esi cmp esi, ecx jl loop_start mov esp,ebp pop ebp ret 12 error_end: mov eax, -1 ; если точек выхода несколько, то в каждой должен быть эпилог перед ret (если был пролог в начале функции) mov esp,ebp pop ebp ret 12 .end CMAIN