Друзья, не могу взять в толк, хочу сделать процедуру отдельным файлом, но не собирается exe. Спойлер: Вот файл процедуры Код (ASM): ;sort Процедура сортировки байтов ;Вход: invoke, addr param2, addr param1 ; param1 адресс массива размерность dw ; param2 кол-во байт в массиве dw ;Меняет регистры esi edi ecx ebx eax ;Выход: ;######################################################################### .586 .model flat, stdcall option casemap :none public sort ;######################################################################### include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib ;######################################################################### .data ;######################################################################### .code sort proc push ebp ;пролог: сохранение EBP mov ebp, esp ;пролог: инициализация EBP mov edi,[ebp+8] dec edi mov edx,edi ;в edx счетчик внешнего цикл-1 xor ebx,ebx ;если ebx=len-1 то прерываем внешний цикл и выходим lbig: xor ecx,ecx ;обнуляем ecx, который будет счетчиком внутреннего цикла mov ecx,[ebp+8] ;в ecx кол-во байт массива mov esi,[ebp+12] ;в esi АДРЕС массива intloop: dec ecx jcxz extloop ;переход на внешний цикл если eсх=0 mov word ptr ax,[esi] cmp al,ah ;иначе сравниваем текущий эл массива со следующим jc normsort ;если сортировка не требуется (al<ah)то идем к следующему эл-ту xchg al,ah ;иначе меняем эл местами mov [esi],ax inc esi ;переход к следующему эл jmp intloop ;продолжаем внутренний цикл normsort: inc ebx ;увеличиваем ebx и cmp ebx,edi ;сравниваем с количеством эл-ов массива je exit ;если ebx=len-1 то прерываем внешний цикл и выходим inc esi ;иначе переходим к следующему эл-ту jmp intloop extloop: ;внешний цикл если eсх=0 xor ebx,ebx ;сбрасываем счетчик преждевременного выхода dec edx ;уменьшаем счетчик внешнего цикла cmp edx,0 ;если конец то выход jne lbig ;иначе сортируем дальше exit: pop ebp ;эпилог: восстановление EBP ret 8 ;освобождаем 8 байт из стека sort endp END Спойлер: а вот основной код, из которого вызывается процедура Код (ASM): .586 .model flat, stdcall option casemap :none ;######################################################################### include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib ;######################################################################### extern sort@8:near .data unsort db "gygyu87559898432zxmnd" ;несортированный массив len= $-unsort ;длина массива ;######################################################################### .code start: mov edx,len push offset unsort push edx call sort@8 exit: invoke ExitProcess, 0 end start Причем obj файлы делаются, но дальше masm32 ругается: main.obj : error LNK2001: unresolved external symbol _sort@8 main.exe : fatal error LNK1120: 1 unresolved externals
Balamut, за правильность работы не отвечаю, но ехе-файл создался 01.asm Спойлер: файл процедуры Код (ASM): ;sort Процедура сортировки байтов ;Вход: invoke, addr param2, addr param1 ; param1 адресс массива размерность dw ; param2 кол-во байт в массиве dw ;Меняет регистры esi edi ecx ebx eax ;Выход: ;######################################################################### .586 .model flat, stdcall option casemap :none ;######################################################################### include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib ;######################################################################### .data ;######################################################################### .code sort proc public param2:DWORD, param1:DWORD mov edi,param2 dec edi mov edx,edi ;в edx счетчик внешнего цикл-1 xor ebx,ebx ;если ebx=len-1 то прерываем внешний цикл и выходим lbig: xor ecx,ecx ;обнуляем ecx, который будет счетчиком внутреннего цикла mov ecx,param2 ;в ecx кол-во байт массива mov esi,param1 ;в esi АДРЕС массива intloop: dec ecx jcxz extloop ;переход на внешний цикл если eсх=0 mov word ptr ax,[esi] cmp al,ah ;иначе сравниваем текущий эл массива со следующим jc normsort ;если сортировка не требуется (al<ah)то идем к следующему эл-ту xchg al,ah ;иначе меняем эл местами mov [esi],ax inc esi ;переход к следующему эл jmp intloop ;продолжаем внутренний цикл normsort: inc ebx ;увеличиваем ebx и cmp ebx,edi ;сравниваем с количеством эл-ов массива je exit ;если ebx=len-1 то прерываем внешний цикл и выходим inc esi ;иначе переходим к следующему эл-ту jmp intloop extloop: ;внешний цикл если eсх=0 xor ebx,ebx ;сбрасываем счетчик преждевременного выхода dec edx ;уменьшаем счетчик внешнего цикла cmp edx,0 ;если конец то выход jne lbig ;иначе сортируем дальше exit: ret ;эпилог и освобождаем 8 байт из стека sort endp END 02.asm Спойлер: основной код, из которого вызывается процедура Код (ASM): .586 .model flat, stdcall option casemap :none ;######################################################################### include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib ;######################################################################### extern sort@8:dword .data unsort db "gygyu87559898432zxmnd" ;несортированный массив len= $-unsort ;длина массива ;######################################################################### .code start: mov edx,len push offset unsort push edx call sort@8 exit: invoke ExitProcess, 0 end start bat-файл @echo off \masm32\bin\ml /c /coff 01.asm \masm32\bin\ml /c /coff 02.asm \masm32\bin\Link /SUBSYSTEM:WINDOWS 02.obj 01.obj del 01.obj del 02.obj чтобы работало корректно, необходимо погонять экзешник под отладчиком, найти ошибки, исправить и снова пересобрать
Mikl___ Большое спасибо, сейчас погоняю. Делал процедуру исполняемым файлом, без передачи параметров в стек, и все работало как надо. Извините за настырность, но есть еще вопрос.Есть ли разница между call@8:byte и call@2:dword ведь по количеству байт это одно и тоже, или masm конролирует тип данных?
@8 -- это очистить стек после выхода из процедуры от 8 байтов, но пишут "extern sort@8:dword" так как аргументы передаются в виде двордов. По поводу "masm контролирует тип данных?" не знаю, на ассемблере контроль лежит на человеке, это же на ЯВУ, где всё под присмотром компилятора
Balamut, открой \masm32\include\user32.inc посмотри любую функцию, например CreateWindowExA, видишь, у нее 12 аргументов типа двойное слово (WORD) CreateWindowExA PROTO STDCALL WORD,WORD,WORD,WORD,WORD,WORD,WORD,WORD,WORD,WORD,WORD,WORD а теперь открой \masm32\lib\user32.lib и найди поиском CreateWindowExA _CreateWindowExA@48 <-- она заканчивается на 4 х 12 = @48
То есть, вызывая ф-цию вот так (call@кол-во впихнутых в стек байт), мне необязательно явно возвращать стек в первоначальное состояние, типа ret n, (где n- кол-во впихнутых в стек байт)? Мне надо погонять, исправленный вами код, в ollydbg, думаю часть вопросов отпадет.
Код (ASM): jne lbig ;иначе сортируем дальше exit: ret ;эпилог и освобождаем 8 байт из стека sort endp компилятор подставит вместо ret --> leave/retn 8 автоматом
Вот теперь,наконец-то, ко мне пришло понимание func@n, но как исправленная вами процедура будет брать из стека параметры, ведь в моем варианте все было явно через смещение регистра bp, а у вас, будто глобальные переменные. Хотя, может, я напутал вас описанием к функции.
Balamut, Код (ASM): sort proc public param2:DWORD, param1:DWORD mov edi,param2 . . . . mov ecx,param2 ;в ecx кол-во байт массива mov esi,param1 компилятор сам подставит пролог и эпилог, локальные переменные (если требуется) и вместо param2 = [ebp+8], param1 = [ebp+12] и т.д. то есть избавит тебя от рутинной работы и ошибок
Эх, снова застрял в коде. Почему вызов процедуры лезет в содержимое [памяти], а не переходит по значению? вот участок кода: ..... CALL DWORD PTR [02.401020] ; call sort@8 ..... 02.401020 my proc ; вот адрес самой процедуры В итоге, вызов берет дворд, состоящий из первых четырех опкодов процедуры, и переходит в никуда
Беру hiew32 адрес 40100Bh, виден вызов процедуры sort. По адресу 401020h располагается сама процедура
Balamut, квадратные скобки нужны чтобы отличать адрес от числовой константы, то есть call ds:[000401020h] ― это вызов процедуры, расположенной по адресу 401020h. Не путай использование квадратных скобок с наименованием регистра и регистр без квадратных скобок.
Выполняя пошагово код, вызов процедуры происходит у меня, именно по четырем байтам, на которые указывает 000401020h. Не пойму, почему так. Разве в call d,[000401020] буква d не указывает на дворд.
есть две инструкции jmp ofs и jmp mem - первая прыгает на адрес - ofs, а вторая, загружает ofs из памяти и потом на него прыгает - прямой и косвенный переход jmp dword ptr var_contained_ofs и jmp near i32 call - аналогично