Win x64, выравнивание стека на 16 байт. Выравнивание чего?

Тема в разделе "WASM.X64", создана пользователем wmaster575, 30 сен 2021.

  1. wmaster575

    wmaster575 New Member

    Публикаций:
    0
    Регистрация:
    22 сен 2017
    Сообщения:
    6
    Всем привет. Везде пишут, что перед вызовом WinApi функций стек должен быть выровнен на границу 16 байт, ESP должен быть кратен 16.
    Компилирую простую программу на fasm:
    Код (ASM):
    1.  
    2. format PE64 GUI 5.0
    3. entry start
    4.  
    5. include 'include\win64a.inc'
    6.  
    7. section '.data' data readable writeable
    8.  
    9. Caption db 'Msg', 0
    10. Message db 'Hello World!', 0
    11.  
    12. section '.text' code readable executable
    13. start:
    14.     sub rsp, 8*5
    15.     mov rcx, 0
    16.     mov rdx, Message
    17.     mov r8, Caption
    18.     mov r9, 0  
    19.     call [MessageBox]
    20.  
    21.     xor rcx, rcx
    22.     call [ExitProcess]
    23.  
    24. section '.idata' import data readable writeable
    25.  
    26.     library kernel32, 'kernel32.dll',\
    27.         user32, 'user32.dll'
    28.  
    29.     include 'include\api\kernel32.inc'
    30.     include 'include\api\user32.inc'
    31.  
    Смотрю под отладчиком:
    [​IMG]

    Как видно на входе RSP уже не кратен 16 - 000000000006FF58h. И в вызове MessageBox RSP будет равен 000000000006FF28h (sub rsp, 8*5 и адрес возврата). То есть он не выравнен на 16 байт. И всё работает.

    Если я попытаюсь выравнять перед вызовом, например так:
    Код (ASM):
    1. start:
    2.     and rsp, 0fffffffffffffff0h
    3.  
    4.     sub rsp, 8*5
    5.     mov rcx, 0
    6.     mov rdx, Message
    7.     mov r8, Caption
    8.     mov r9, 0
    9.     call [MessageBox]
    10.  
    11.     xor rcx, rcx
    12.     call [ExitProcess]
    То получаю EXCEPTION_ACCESS_VIOLATION:
    [​IMG]

    Я подумал это ошибка доступа к памяти, но если я заменю в коде
    Код (Text):
    1.  
    2. start:
    3.     sub rsp, 8*5
    4.     mov rcx, 0
    5.     mov rdx, Message
    6.     mov r8, Caption
    7.     mov r9, 0  
    8.     call [MessageBox]
    9.  
    10.     xor rcx, rcx
    11.     call [ExitProcess]
    12.  
    Код (Text):
    1. sub rsp, 8*5
    на
    Код (Text):
    1. sub rsp, 8*3
    То в таком варианте даже ошибки нет.

    Так относительно чего должен быть RSP кратен 16? Относительно того RSP, который имеется на входе в программу?
     
    Последнее редактирование: 30 сен 2021
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    В версии 0.7 стандарта abi стек должен был выровнен на 16 байтах.
    А в версии 0.9 уже на 8 байт.
    А мелко-мягкие в своем компилятор сделали 8 а документацию забыли поправить
    --- Сообщение объединено, 30 сен 2021 ---
    А не вру ноги ростут из
    https://www.uclibc.org/docs/psABI-x86_64.pdf
    17 страница последний параметр переданный в стек должен быть выровнен на 16 байт.
    А а следующей что выровнен на 8
     
    wmaster575 нравится это.
  3. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Стек должен быть выровнен на 16, но кодер должен выравнивать его на 8, потому что call запушит еще адрес возврата.
     
    wmaster575 нравится это.
  4. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    352
    Да, относительно того RSP, который имеется на входе в программу. Простая арифметика, которая все проясняет. Выше вы писали про адреса 000000000006FF58h и 000000000006FF28h (58h - 28h = 30h). 30h - это 48, а 48/16=3. Т.е. стек выровнен на 16.

    https://pirogov-vju.livejournal.com/1128.html

    https://www.cyberforum.ru/assembler-x64/thread1190788.html

    https://devblogs.microsoft.com/oldnewthing/20040114-00/?p=41053

    https://devblogs.microsoft.com/oldnewthing/20040114-00/?p=41053

    https://www.codeproject.com/Articles/17263/Moving-to-Windows-Vista-x64

    Pavia, что-то вы меня совсем запутали. Ладно там Инди, которому я доверяю процентов на 50 :) , но вы-то у меня в белом списке доверенных лиц :) В общем, взял 19 студию скомпилировал функции с 4,5,6 аргументами - все выравнивается на 16 байт. Не знаю как вы, а я пока буду равнять как 19-я студия :)
     
    wmaster575 нравится это.
  5. wmaster575

    wmaster575 New Member

    Публикаций:
    0
    Регистрация:
    22 сен 2017
    Сообщения:
    6
    Всем спасибо, разобрался)
     
  6. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    352
    Я еще до кучи хотел добавить сюда шедевр на FASM от Mikl___ . В этом файле тоже есть хитрое выравнивание, но самое главное, это конечно, РАЗМЕР и НЕСТАНДАРТНОСТЬ EXE-файла!!! До этого я думал, что выравнивание в PE-файле меньше, чем 200 не сделаешь. Но как оказалось - я ошибался. Можно сделать выравнивание и 4 байта. Так же заслуживает внимания и таблица импорта. В общем, шедевр - он и есть шедевр!!!


    Код (ASM):
    1. format binary as 'exe'
    2.  
    3. IMAGE_DOS_SIGNATURE        equ 5A4Dh
    4. IMAGE_NT_SIGNATURE        equ 00004550h
    5. PROCESSOR_AMD_X8664        equ 8664h
    6. IMAGE_SCN_CNT_CODE        equ 00000020h
    7. IMAGE_SCN_MEM_READ        equ 40000000h
    8. IMAGE_SCN_MEM_WRITE        equ 80000000h
    9. IMAGE_SCN_CNT_INITIALIZED_DATA    equ 00000040h
    10. IMAGE_SUBSYSTEM_WINDOWS_GUI    equ 2
    11. IMAGE_NT_OPTIONAL_HDR64_MAGIC    equ 20Bh
    12. IMAGE_FILE_RELOCS_STRIPPED    equ 1
    13. IMAGE_FILE_EXECUTABLE_IMAGE    equ 2
    14. IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE equ 8000h
    15.  
    16. include 'win64a.inc'
    17. org 0
    18. use64
    19. IMAGE_BASE = 400000h
    20. Signature:        dw IMAGE_DOS_SIGNATURE,0
    21. ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
    22. ;image_header--------------------------
    23. .Machine        dw PROCESSOR_AMD_X8664
    24. .Count_of_section    dw 0
    25. .TimeStump        dd 0
    26. .Symbol_table_offset    dd 0;ntHeader
    27. .Symbol_table_count    dd 0
    28. .Size_of_optional_header dw EntryPoint-optional_header
    29. .Characteristics    dw 0x20 or IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE
    30. ;20h Handle >2Gb addresses
    31. ;-------------------------------------
    32. optional_header:
    33. .Magic_optional_header    dw IMAGE_NT_OPTIONAL_HDR64_MAGIC
    34. .Linker_version_major_and_minor dw 9
    35. .Size_of_code        dd 0
    36. .Size_of_init_data    dd 0;xC0
    37. .Size_of_uninit_data    dd 0
    38. .entry_point        dd EntryPoint
    39. .base_of_code        dd ntHeader
    40. .image_base        dq IMAGE_BASE
    41. .section_alignment    dd 4
    42. .file_alignment     dd 4
    43. .OS_version_major_minor dw 5,2
    44. .image_version_major_minor dd 0
    45. .subsystem_version_major_minor dw 5,2
    46. .Win32_version        dd 0
    47. .size_of_image        dd EndOfImage
    48. .size_of_header     dd EntryPoint
    49. .checksum        dd 0
    50. .subsystem        dw IMAGE_SUBSYSTEM_WINDOWS_GUI
    51. .DLL_flag        dw IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
    52. .Stack_allocation    dq 0x100000
    53. .Stack_commit        dq 0x1000
    54. .Heap_allocation    dq 0x100000
    55. .Heap_commit        dq 0x1000
    56. .loader_flag        dd 0
    57. .number_of_dirs     dd (EntryPoint-export_RVA_size)/8
    58. export_RVA_size        dq 0
    59. .import_RVA        dd import_
    60. .import_size        dd end_import-import_
    61. ;------------------------------------------------
    62. EntryPoint:
    63.    enter 20h,0          ; space for 4 arguments + 16byte aligned stack
    64.    xor ecx, ecx           ; 1. argument: rcx = hWnd = NULL
    65.    mov r9, rcx              ; 4. argument: r9d = uType = MB_OK = 0
    66.    mov edx,MsgCaption+IMAGE_BASE  ; 2. argument: edx = window text
    67.    mov r8,rdx              ; 3. argument: r8  = caption
    68.    call [MessageBox]
    69.    leave
    70.    ret
    71. ;------------------------------------------------
    72. MsgCaption    db "Iczelion's tutorial #2a",0
    73. ;-------------------------------------------------
    74. Import_Table:
    75. user32_table:
    76. MessageBox  dq _MessageBox
    77. import_:
    78. dd 0,0,0,user32_dll,user32_table
    79. dd 0
    80. user32_dll    db "user32",0,0
    81. dw 0
    82. _MessageBox    db 0,0,"MessageBoxA"
    83. end_import:
    84. times 268-end_import db 0  ;filling up to 268 bytes
    85. EndOfImage: