Разделение строки на подстроки

Тема в разделе "WASM.BEGINNERS", создана пользователем LOL, 12 май 2006.

  1. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    LOL

    > "Ну раз разбираться, то разбираться до конца ;)"

    Ну тогда несколько уточнений и пояснений :)

    Стековый фрейм (кадр) - это область стека, в которой находятся аргуметны функции, адрес возврата и локальные переменные. Для stdcall-функции с прологом кадр стека выглядит так:
    Код (Text):
    1. адрес   значение   пояснение
    2. -----   --------   ---------
    3. esp ->  local(m)   /
    4. esp+4   local(m-1) |
    5. ...     ...        |- локальные переменные, выделяются прологом (enter или sub esp,X)
    6. ebp-4   local(1)   \
    7. ebp     ebp        <- сохраненное значение ebp, заталкивается прологом (enter или push ebp)
    8. ebp+4   ret_addr   <- адрес возврата, заталкивается инструкцией call
    9. ebp+8   arg(1)     /
    10. ...     ...        |- аргументы функции, заталкиваются перед вызовом call пушами или макросом invoke
    11.         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), иначе создается какая-то путанница - но так уж сложилось по дурной традиции :dntknw:(



    Можно обойтись без пролога\эпилога ? Можно, если в proc использовать option prologue или вообще не объявлять proc, а просто использовать имя функции как метку. Дает это возможность "спокойно" использовать регистр ebp для свих целей + небольшая экономия кода (тут правда нужно учитывать, что безиндексная адресация [ebp+disp] на байт короче чем [esp+disp]). А минус - в необходимости держать в голове смещения аргументов и локальных переменных относительно текущего esp. Поэтому эту фичу обычно используют для оптимизации, когда аргументов\переменных немного и есть возможность разместить их в регистрах, когда esp не изменяется и т.п.
     
  2. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    leo

    Большое спасибо! :)





    Я уже убедился как это "нехорошо", когда в вышеописанной процедуре использовал 3 ret'а... :)



    Ну а так - все встало на свои места.



    З.Ы. В общем: спасибо IceStudent, cresta, leo, Ustus !!!