Регистры, которые надо сохранять в Win32.

Тема в разделе "WASM.BEGINNERS", создана пользователем mc black, 15 май 2011.

  1. mc black

    mc black Member

    Публикаций:
    0
    Регистрация:
    19 янв 2005
    Сообщения:
    213
    Адрес:
    Russia, N.Novgorod
    Здравствуйте, уважаемые форумчане.

    Из того, что должно быть на видном месте в FAQ. Я читал, смотрел и не нашел, хотя когда-то где-то здесь видел (и уже забыл).

    Есть какие-то регистры, которые не следует изменять между вызовами Win32 API функциями. Помимо ESI, EDI кажется EBX и/или ECX. То есть если я буду свободно менять значение этого регистра, то программа может себя неправильно повести при очередном вызове некоторых функций API. Я прав, есть такие регистры (из числа регистров общего назначения) или я заблуждаюсь?

    С уважением, mc-black
     
  2. Igor1024

    Igor1024 Васил Троянов Боянов (Azis)

    Публикаций:
    0
    Регистрация:
    15 окт 2010
    Сообщения:
    345
    Адрес:
    Sliven, Bulgaria
    Смотря какая функция, но вообще ESP,EBX;
    EAX,ECX,EDX - зависит от функции.
     
  3. mc black

    mc black Member

    Публикаций:
    0
    Регистрация:
    19 янв 2005
    Сообщения:
    213
    Адрес:
    Russia, N.Novgorod
    Во, ESP и EBX! Спасибо за ценную подсказку!

    А насчет EAX, ECX, EDX можете подсказать примеры функций, где их менять нельзя? Или где это можно прочесть, в MSDN подозреваю, что про это ни слова.
     
  4. 9Demon

    9Demon New Member

    Публикаций:
    0
    Регистрация:
    18 апр 2011
    Сообщения:
    33
    Я давным давно открывал в отладчике интересующую функцию, смотрел там в начале
    push edi
    push esi
    push ebx
    и в конце
    pop ebx
    pop esi
    pop edi

    ок, значит эти регистры свободны, мона юзать. Даже списочек составлял для разных Api:)
     
  5. dinoweb

    dinoweb Дмитрий

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    129
    Адрес:
    Россия. Красноярск
    Вообще-то есть соглашение, по которому все __stdcall функции обязаны сохранять значения регистров
    ebx, esi, edi, ebp (и извлекать из стека все параметры, восстанавливая значение стека).

    Все остальные регистры эти функции могут менять по своему усмотрению, не обращая внимания на их значения. Суть не в том, чтобы сохранять значения между вызовами API, а в том, чтобы сохранять значения этих регистров для вызывающей функции.

    Например, есть ваша call-back функция WindowProc. Вот она обязана сохранить значения этих регистров. Иначе после возврата из функции, можно словить исключение.

    API функции обычно __stdcall.
     
  6. 9Demon

    9Demon New Member

    Публикаций:
    0
    Регистрация:
    18 апр 2011
    Сообщения:
    33
    Наверное имелось ввиду какие еще регистры использует функция. Вдруг ecx с edx свободны от юзанья в какой то апишке - это ж круто, на 2 push pop меньше до вызова апи для сохранения своих регистров :lol:
     
  7. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.206


    dinoweb прав, большинство вызовов WinAPI stdcall
    Есть fastcall, но они вам встретятся не скоро.
    Сохранять регистры ebx, esi, edi, ebp
    Сохранять esp не надо. Его нужно восстанавливать, забирая из стека переданные аргументы.

    Таких нет, в своем коде можете менять любые регистры, главное, восстанавливать их при выходе из процедуры, если она вызывается в соответствии с определенным соглашением.

    9Demon, иногда лучше жевать.
     
  8. 9Demon

    9Demon New Member

    Публикаций:
    0
    Регистрация:
    18 апр 2011
    Сообщения:
    33
    ormoulu
    Dinoweb уже сказал все что надо по этой теме, нах ты еще раз повторяешь ?
    Не понял. Иди в жопу умник..
     
  9. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.206
    Мне показалось, что чуть более подробное объяснение новайсу не повредит.

    Объясняю: если сделать так, как ты предлагаешь (открыть в отладчике и посмотреть, какие сохраняются в начале) можно серьезно облажаться, поскольку есх, например, __stdcall сохранять не обязан.
     
  10. 9Demon

    9Demon New Member

    Публикаций:
    0
    Регистрация:
    18 апр 2011
    Сообщения:
    33
    там еще "в конце" есть, прочитай мой пост
     
  11. 9Demon

    9Demon New Member

    Публикаций:
    0
    Регистрация:
    18 апр 2011
    Сообщения:
    33
    В XP к примеру есть такие функции, не меняющие ecx и edx
    GetModuleHandleA(0)
    GetCommandLineA
    GetCurrentProcess
    GetCurrentProcessId
    GetCurrentThread
    GetCurrentThreadId
     
  12. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.206
    А если между push ecx и pop ecx у тебя будет mov [esp], ЛЕВАЯ_ХРЕНЬ?

    Плюс, если ты не увидишь push/pop edi или ebp, то что, ты их будешь сохранять перед вызовом? И потеряешь те самые байты, которые хочешь сэкономить.
     
  13. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.206
    А перед вызовом ты определяешь ОС и сервиспак?

    ЗЫ: с физической памятью разобрался? :)
     
  14. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    9Demon
    Просто по дизасму не всегда получится определить это. Например Zw-стабы, явно меняют только Eax. Но ядро изменяет Ecx и Edx. А вот флажки(EFlags) сохраняет. Таким образом если в коде используются сервисы, то Ecx и Edx не сохраняются. Эта частный случай закрытых ветвлений(например Call Arg) - таких, в которых адрес ветвления не определён(сискол тоже процедурное ветвление), например колбеков.
     
  15. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    mc black
    Соглашение о регистрах - только для CALLBACK процедур. Тех процедур, адрес которых передаётся в Win32:

    WindowProc
    DialogProc
    ThreadProc
    EnumWindowsProc
    EnumFontsProc

    и т.п.

    Ещё надо сбросить флаг направления перед возвратом в Win32, но только если он был установлен.
    По умолчанию DF=0 в Win32.

    Общее правило: если адрес процедуры ставится в какую-либо структуру Win32 и затем
    передаётся в Win32 или адрес процедуры передаётся непосредственно как параметер вызова Win32
    -- регистры в такой процедуре должны быть сохранены.

    Положив значения в ESI,EDI,EBX,EBP - можно быть уверенным что это сохранится между вызовами API:
    Код (Text):
    1. mov esi, [hWnd]
    2. invoke  InvalidateRect, esi, 0, 0
    3. invoke  UpdateWindow, esi
     
  16. mc black

    mc black Member

    Публикаций:
    0
    Регистрация:
    19 янв 2005
    Сообщения:
    213
    Адрес:
    Russia, N.Novgorod
    Ребята, всем огромное спасибо за участие и первоклассную помощь! Теперь всё стало ясно. Да, мне как раз надо сохранять ESI, EDI, EBX, EBP, так как я собрался сделать маленькую библиотечку, построенную по подобию masm32.lib. Эти функции я хотел бы вызывать по соглашению stdcall, помнил раньше чётко только про esi, edi (ebp мне бы в голову не пришло менять). Но где-то смутно помнил, что чего-то ещё менять не следует, мне про это чётко написали, теперь когда буду использовать ebx, не забуду добавить к proc: uses ebx (или push / pop ebx). Это главное, что меня смущало. Ещё раз всем СПАСИБО!