LOL > "Ну раз разбираться, то разбираться до конца " Ну тогда несколько уточнений и пояснений Стековый фрейм (кадр) - это область стека, в которой находятся аргуметны функции, адрес возврата и локальные переменные. Для stdcall-функции с прологом кадр стека выглядит так: Код (Text): адрес значение пояснение ----- -------- --------- esp -> local(m) / esp+4 local(m-1) | ... ... |- локальные переменные, выделяются прологом (enter или sub esp,X) ebp-4 local(1) \ ebp ebp <- сохраненное значение ebp, заталкивается прологом (enter или push ebp) ebp+4 ret_addr <- адрес возврата, заталкивается инструкцией call ebp+8 arg(1) / ... ... |- аргументы функции, заталкиваются перед вызовом call пушами или макросом invoke arg(n) \ Соответсвено "входная" часть кадра, содержащая аргументы и адрес возврата создается при вызове функции макросом invoke или вручную серией push + call. Область локальных переменных создается прологом функции - либо enter SizeOfLocals,0 либо комбинацией push ebp + mov ebp,esp + sub esp,SizeOfLocals. (enter в основном испульзуется в ЯВУ во вложенных функциях для возможности доступа к фреймам "родительских" функций). Для чего нужен пролог - для удобства адресации аргументов и локальных переменных - в регистре ebp фиксируется состояние стека на момент входа в процедуру и затем доступ к i-му аргументу (i=1,2..) осуществляется через [ebp+4+i*4], а доступ к i-ой локальной переменной через [ebp-i*4]. При этом ты можешь в любом месте функции обращаться к любому аргументу или переменной по имени, например mov eax,local_2 или mov eax,arg_2 - ассемблер сам "сообразит" что к чему и превратит эти выражения соответсвенно в mov eax,[ebp-8] и mov eax,[ebp+0Ch]. Разумеется при использовании пролога нельзя изменять ebp (точнее сказать - можно, но очень осторожно , но зато можно незадумываясь обращаться с esp - пушить и попить сколько душе угодно. Раз есть пролог, то должен быть и эпилог, который удаляет из стека локальные переменные и восстанавливает регистры ebp и esp. С использованием пролога\эпилога есть одна "неприятность" - если мы хотим "досрочно" выйти из функции, то нужно либо осуществлять jmp на эпилог, стоящий в конце функции, либо иметь какую-то директиву (макрос) типа ЯВУ-шных return или exitX, которая будет автоматически выполнять эпилог. Вопрос: кто и как создает пролог\эпилог и как реализуется exit\return? В общем случае можно сказать - компилятор. В ЯВУ это действительно так - вся кухня прологов\эпилогов\выходов зашита в недрах самого компилятора, до которых мы добраться не можем. А в асме вся эта фигня построена на макросах - пролог и эпилог создаются макросами proc, ret* и endp, текст которых можно посмотреть в исходниках. Самая "ужасная" хитрость макроса proc состоит в том, что он временно переопределяет идентификатор ret c инструкции x86 (= retn) на макрос, который выполняет эпилог (по сути в явушный return\exit), т.е. вместо простого retn превращается в цепочку add esp,X + pop ebp + mov esp,ebp + retn Y. Соответсвенно макрос endp отменяет это переопределение и до следующего proc имя ret снова соответсвует retn. Я лично считаю, что это "нехорошо" и для этих целей луше было бы использовать другое имя, например exitp(roc), иначе создается какая-то путанница - но так уж сложилось по дурной традиции ( Можно обойтись без пролога\эпилога ? Можно, если в proc использовать option prologue или вообще не объявлять proc, а просто использовать имя функции как метку. Дает это возможность "спокойно" использовать регистр ebp для свих целей + небольшая экономия кода (тут правда нужно учитывать, что безиндексная адресация [ebp+disp] на байт короче чем [esp+disp]). А минус - в необходимости держать в голове смещения аргументов и локальных переменных относительно текущего esp. Поэтому эту фичу обычно используют для оптимизации, когда аргументов\переменных немного и есть возможность разместить их в регистрах, когда esp не изменяется и т.п.
leo Большое спасибо! Я уже убедился как это "нехорошо", когда в вышеописанной процедуре использовал 3 ret'а... Ну а так - все встало на свои места. З.Ы. В общем: спасибо IceStudent, cresta, leo, Ustus !!!