Почему стек должен быть выровнен на 4-байтную границу ??

Тема в разделе "WASM.BEGINNERS", создана пользователем int2e, 4 фев 2009.

  1. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    Недавно столкнулся с непонятной ошибкой
    Большинство АПИ-функций отказывались работать, хотя аргументы были переданы верно

    Я очень долго медитировал, пока не просветлел: у меня адреса локальных переменных не были выровнены на дворд
    Как только выровнял - все заработало

    Подскажите пожалуйста, почему стек должен быть выровнен на дворд и где об этом можно почитать более детально?
     
  2. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    По-моему в доках Intel упоминалось что последние два бита ESP привилегированные, что и есть выравнивание. Что читать детальнее?
     
  3. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    почему привилегированные?
    под что используются?
     
  4. al79

    al79 Алексей

    Публикаций:
    0
    Регистрация:
    11 май 2006
    Сообщения:
    133
    Адрес:
    Екатеринбург
    Мне это тоже стало интересным. То есть получаетя я не смогу правильно прочитать данные из стека "mov eax,[esp]" если последние два бита esp не нули?
     
  5. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    al79
    просто там ВСЕГДА нули, прилигированные они чисто формально, чтобы переписать незя было.
     
  6. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Да ну.. а как же то, что esp - регистр общего назначения? Его можно использовать в арифметических вычислениях.
    В досе выравнивание на word, там только один бит привилегированный?)
     
  7. agrischuk

    agrischuk New Member

    Публикаций:
    0
    Регистрация:
    12 янв 2009
    Сообщения:
    47
    Изучите конвенцию stdcall которая подразумевает выравнивание стека.
    В SSE есть команды которые работают только с выравненной памятью (MOVDQA).
    Возможно есть еще какие-то ограничения.

    Приведи пример.
     
  8. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    JAPH
    Можно использовать, естественно, только после использования ESP надо вернуть на прежнее место.
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Следствие:
    Причина:
    Код (Text):
    1. VOID
    2. ExRaiseDatatypeMisalignment (
    3.     VOID
    4.     )
    5.  
    6. /*++
    7.  
    8. Routine Description:
    9.  
    10.     This function raises a datatype misalignment exception.
    11.  
    12.     N.B. There is not return from this function.
    13.  
    14. Arguments:
    15.  
    16.     None.
    17.  
    18. Return Value:
    19.  
    20.     None.
    21.  
    22. --*/
    23.  
    24. {
    25.  
    26.     ExRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
    27. }
    Вызов из ProbeForRead() и ProbeForWrite():
    Код (Text):
    1. VOID
    2. ProbeForRead(
    3.     __in_bcount(Length) VOID *Address,
    4.     __in SIZE_T Length,
    5.     __in ULONG Alignment
    6.     )
    7.  
    8. /*++
    9.  
    10. Routine Description:
    11.  
    12.     This function probes a structure for read accessibility and ensures
    13.     correct alignment of the structure. If the structure is not accessible
    14.     or has incorrect alignment, then an exception is raised.
    15.  
    16. Arguments:
    17.  
    18.     Address - Supplies a pointer to the structure to be probed.
    19.  
    20.     Length - Supplies the length of the structure.
    21.  
    22.     Alignment - Supplies the required alignment of the structure expressed
    23.         as the number of bytes in the primitive datatype (e.g., 1 for char,
    24.         2 for short, 4 for long, and 8 for quad).
    25.  
    26. Return Value:
    27.  
    28.     None.
    29.  
    30. --*/
    31.  
    32. {
    33.  
    34.     PAGED_CODE();
    35.  
    36.     ASSERT((Alignment == 1) || (Alignment == 2) ||
    37.            (Alignment == 4) || (Alignment == 8) ||
    38.            (Alignment == 16));
    39.  
    40.     if (Length != 0) {
    41.         if (((ULONG_PTR)Address & (Alignment - 1)) != 0) {
    42.             ExRaiseDatatypeMisalignment();
    43.  
    44.         } else if ((((ULONG_PTR)Address + Length) > (ULONG_PTR)MM_USER_PROBE_ADDRESS) ||
    45.                    (((ULONG_PTR)Address + Length) < (ULONG_PTR)Address)) {
    46.  
    47.             *(volatile UCHAR * const)MM_USER_PROBE_ADDRESS = 0;
    48.         }
    49.     }
    50. }
    Возможно без исключения:
    Код (Text):
    1. NtQuerySystemInformation()
    2.     > SystemSessionProcessInformation
    3.     > SystemHandleInformation
    4.     > SystemExtendedHandleInformation
    5.     > SystemSessionPoolTagInformation
    6.     > SystemSessionMappedViewInformation
    7. NtSetQuotaInformationFile()
    \wrk\base\ntos\ex\probe.c
     
  10. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    agrischuk
    Где написано про это требование?
    Здесь например нету - http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx

    Clerk
    Не путаешь? Это исключение вылетает на Itanium. Microsoft же рекомендует выравнивать на x86 только в целях повышения производительности.

    Например в ShowWindow при этом никаких исключений не возникает, просто криво отображается окно.
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Booster
    Оно не вылетает, а генерируется програмно функцией ExRaiseDatatypeMisalignment().
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Clerk
    >Оно не вылетает, а генерируется програмно функцией ExRaiseDatatypeMisalignment().
    В ShowWindow оно используется?
     
  13. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Например: многие Nt* требуют 8байт выравнивание структур. x86-64 требует 16байт выравнивание стэка при вызове АПИ (по конвенции). + SSE* требует в большинстве случаев 16б выравнивания для операции с данными (это как посыл к конвенциям вызова). +AC флаг для контроля выравнивания. +размеры кэш=линий (походу главная причина выравнивания). Скоро на 32будем равнять с AVX
     
  14. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    Booster
    Попробуй сделать так

    push dword ptr [pLibraryName] ;kernel32.dll
    call [LoadLibraryA]

    Если аргумент не выровнен на 4 - Функция вернет ошибку

    Clerk
    Большое спасибо! Дальше сам в сисере разберусь!!!!!!! ))
     
  15. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    asmfan
    Ткни где об этом написано.

    int2e
    Не вернула, отработала нормально.
     
  16. agrischuk

    agrischuk New Member

    Публикаций:
    0
    Регистрация:
    12 янв 2009
    Сообщения:
    47
    Все параметры длинной dword, чтобы сохранить выравнивание.
    На 64битных системах это qword.

    Здесь еще немного инфы:
    http://rs1.szif.hu/~tomcat/win32/win32asm.txt
     
  17. agrischuk

    agrischuk New Member

    Публикаций:
    0
    Регистрация:
    12 янв 2009
    Сообщения:
    47
    AC флаг будет работать только совмесно с флагом AM из CR0 (оно выключено). Причем если включить, винда хендлит эти эксепшены, аварийным завершением. В идеале в сорцах видно что включать AC можна было при создании потока (параметр функции). Однако потом почему-то забанили.

    Мой проект по включению всего этого дела я описал здесь:
    http://wasm.ru/forum/viewtopic.php?id=30650
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    agrischuk
    А где написано, что выравнивание необходимо для нормально работы? Везде про то, что оно лишь влияет на производительность. Функции Nt и SSE это из другой оперы.
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Booster
    Учи матчасть. Что происходит если вызвать сервсис, которой требует одним из параметров на входе указатель на данные ?
    Так как данные находятся в юзермодном адресном пространстве, поэтому сервис вначале устанавливает структурный обработчик исключений, иначе сервис былбы уязвим. Если указатель не валидный генерируется исключение(NTSTATUS код для него соответственно STATUS_ACCESS_VIOLATION). Но многие сервисы(таковых большинство) проверяют валидность указателя не только элементарной проверкой диапазона(сравнение с переменной MmUserProbeAddress etc.), а делоют попытку доступа к данным, вызвав соответственно ProbeForRead() или ProbeForWrite(). Последний вызов при не валидном указателе, или если указатель не выравнен в памяти на указанную границу генерирует исключение(если не выровнен то сех обрабатывается прямым вызовом RtlDispatchException()). Управление получает структурный обработчик исключений, который и возвращает ошибку, без разворачивания исключений в юзермоде, тоесть выполняется возврат из сервиса и возвращается код ошибки STATUS_DATATYPE_MISALIGNMENT.
    Каждый, кто видел ядерный код знает что делоют функции ProbeForRead() и ProbeForWrite(). Если указатель на данные не передаётся то никакое выравнивание не нужно, как говорил Михаил это нонсенс.
    К сожалению я уже давно не юзал винапи и GUI-сервисы, поэтому пришлось залезть в сурцы и MSDN. Функция ShowWindow() является просто стубом для сервиса NtUserShowWindow. Последний не требует указателя, как одного из параметров. Прототип следующий:
    Код (Text):
    1. W32KAPI
    2. BOOL
    3. NtUserShowWindow(
    4.     IN HWND hwnd,
    5.     IN int nCmdShow);
    Так как нет указателя не имеет значения выравнивание(два младших бита) юзермодного Esp(для KiFastCallEntry() и KiSystemService() это также не имеет значения). Поэтому результат исполнения сервиса не зависит от варавнивания стека.
    Пример. Раз речь пошла про GUI.
    Например функция GetCursorPos()требует указателя на структуру, принимающую данные. Соответственно ядерный сервис для этой апи xxxGetCursorPos(NtUserCallOneParam ->):
    Код (Text):
    1. 0002BD92 _xxxGetCursorPos@4                   /$  6A 08                    push 8
    2. 0002BD94                                      |.  68 F0D81900              push win32k_.0019D8F0
    3. 0002BD99                                      |.  E8 4F4DFEFF              call win32k_.__SEH_prolog
    4. 0002BD9E                                      |.  A1 18891B00              mov eax,dword ptr ds:[_gptiCurrent]
    5. 0002BDA3                                      |.  8B40 3C                  mov eax,dword ptr ds:[eax+3C]
    6. 0002BDA6                                      |.  85C0                     test eax,eax
    7. 0002BDA8                                      |.  74 08                    je short win32k_.0002BDB2
    8. 0002BDAA                                      |.  3B05 E0921B00            cmp eax,dword ptr ds:[_grpdeskRitInput]
    9. 0002BDB0                                      |.  75 3E                    jnz short win32k_.0002BDF0
    10. 0002BDB2                                      |>  A1 58851B00              mov eax,dword ptr ds:[_gpsi]
    11. 0002BDB7                                      |.  8BB8 9C080000            mov edi,dword ptr ds:[eax+89C]
    12. 0002BDBD                                      |.  8B98 A0080000            mov ebx,dword ptr ds:[eax+8A0]
    13. 0002BDC3                                      |.  8365 FC 00               and dword ptr ss:[ebp-4],0
    14. 0002BDC7                                      |.  6A 01                    push 1
    15. 0002BDC9                                      |.  6A 08                    push 8
    16. 0002BDCB                                      |.  8B75 08                  mov esi,dword ptr ss:[ebp+8]
    17. 0002BDCE                                      |.  56                       push esi
    18. 0002BDCF                                      |.  FF15 50A61900            call dword ptr ds:[<&ntoskrnl.ProbeForWrite>]             ;  ntoskrnl.ProbeForWrite
    19. 0002BDD5                                      |.  834D FC FF               or dword ptr ss:[ebp-4],FFFFFFFF
    20. 0002BDD9                                      |.  33C0                     xor eax,eax
    21. 0002BDDB                                      |.  40                       inc eax
    22. 0002BDDC                                      |.  8945 FC                  mov dword ptr ss:[ebp-4],eax
    23. 0002BDDF                                      |.  893E                     mov dword ptr ds:[esi],edi
    24. 0002BDE1                                      |.  895E 04                  mov dword ptr ds:[esi+4],ebx
    25. 0002BDE4                                      |.  834D FC FF               or dword ptr ss:[ebp-4],FFFFFFFF
    26. 0002BDE8                                      |>  E8 404DFEFF              call win32k_.__SEH_epilog
    27. 0002BDED                                      |.  C2 0400                  ret 4
    28. 0002BDF0                                      |>  33C0                     xor eax,eax
    29. 0002BDF2                                      \.^ EB F4                    jmp short win32k_.0002BDE8
    Юзоется ProbeForWrite(), но так как последним пераметром ProbeForWrite() является выравнивание, а указан один байт, поэтому выравнивание игнорируется.
    Например слежующий сервис:
    Код (Text):
    1. 00090052 _NtUserBuildNameList@16                      .  6A 10                    push 10
    2. 00090054                                              .  68 10B31900              push win32k_.0019B310
    3. 00090059                                              .  E8 8F0AF8FF              call win32k_.__SEH_prolog
    4. 0009005E                                              .  33DB                     xor ebx,ebx
    5. 00090060                                              .  895D E4                  mov dword ptr ss:[ebp-1C],ebx
    6. 00090063                                              .  E8 DB0AF8FF              call win32k_._EnterSharedCrit@0
    7. 00090068                                              .  837D 0C 0C               cmp dword ptr ss:[ebp+C],0C
    8. 0009006C                                              .^ 72 89                    jb short win32k_.0008FFF7
    9. 0009006E                                              .  895D FC                  mov dword ptr ss:[ebp-4],ebx
    10. 00090071                                              .  A1 409A1B00              mov eax,dword ptr ds:[_Win32UserProbeAddress]
    11. 00090076                                              .  8B4D 14                  mov ecx,dword ptr ss:[ebp+14]
    12. 00090079                                              .  3BC8                     cmp ecx,eax
    13. 0009007B                                              .^ 73 CC                    jnb short win32k_.00090049
    14. 0009007D                                              >  8B01                     mov eax,dword ptr ds:[ecx]
    15. 0009007F                                              .  8901                     mov dword ptr ds:[ecx],eax
    16. 00090081                                              .  6A 04                    push 4
    17. 00090083                                              .  FF75 0C                  push dword ptr ss:[ebp+C]
    18. 00090086                                              .  8B7D 10                  mov edi,dword ptr ss:[ebp+10]
    19. 00090089                                              .  57                       push edi
    20. 0009008A                                              .  FF15 50A61900            call dword ptr ds:[<&ntoskrnl.ProbeForWrite>]             ;  ntoskrnl.ProbeForWrite
    21. [...]
    Вначале устанавливает сех-фрейм и юзоет проверку указателя, причё выравнивание тоже на границу 4-х байт. Если указатель не валидный или не выровнен на 4 байта возникает исключение, далее оно обрабатывается, управление возвращается в _SEH_epilog и далее сервис возвратит STATUS_DATATYPE_MISALIGNMENT. Этот сервис юзоется из EnumWindowStations(), EnumDesktops(), поэтому можешь проверить.
     
  20. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Clerk
    ShowWindow как ты заметил не передаёт указателей, не генерит исключений, просто работает неправильно (криво показывает окно). Если есть какие-то особенности в соглашениях вызова, то они должны быть явно оговорены (чего пока не наблюдается). Особенности Nt функций это лишь их особенности(выравнивание или что другое), документированные функции это другое дело. Я рад что ты знаток ядра, но мне это не нужно.