Всем привет. Везде пишут, что перед вызовом WinApi функций стек должен быть выровнен на границу 16 байт, ESP должен быть кратен 16. Компилирую простую программу на fasm: Код (ASM): format PE64 GUI 5.0 entry start include 'include\win64a.inc' section '.data' data readable writeable Caption db 'Msg', 0 Message db 'Hello World!', 0 section '.text' code readable executable start: sub rsp, 8*5 mov rcx, 0 mov rdx, Message mov r8, Caption mov r9, 0 call [MessageBox] xor rcx, rcx call [ExitProcess] section '.idata' import data readable writeable library kernel32, 'kernel32.dll',\ user32, 'user32.dll' include 'include\api\kernel32.inc' include 'include\api\user32.inc' Смотрю под отладчиком: Как видно на входе RSP уже не кратен 16 - 000000000006FF58h. И в вызове MessageBox RSP будет равен 000000000006FF28h (sub rsp, 8*5 и адрес возврата). То есть он не выравнен на 16 байт. И всё работает. Если я попытаюсь выравнять перед вызовом, например так: Код (ASM): start: and rsp, 0fffffffffffffff0h sub rsp, 8*5 mov rcx, 0 mov rdx, Message mov r8, Caption mov r9, 0 call [MessageBox] xor rcx, rcx call [ExitProcess] То получаю EXCEPTION_ACCESS_VIOLATION: Я подумал это ошибка доступа к памяти, но если я заменю в коде Код (Text): start: sub rsp, 8*5 mov rcx, 0 mov rdx, Message mov r8, Caption mov r9, 0 call [MessageBox] xor rcx, rcx call [ExitProcess] Код (Text): sub rsp, 8*5 на Код (Text): sub rsp, 8*3 То в таком варианте даже ошибки нет. Так относительно чего должен быть RSP кратен 16? Относительно того RSP, который имеется на входе в программу?
В версии 0.7 стандарта abi стек должен был выровнен на 16 байтах. А в версии 0.9 уже на 8 байт. А мелко-мягкие в своем компилятор сделали 8 а документацию забыли поправить --- Сообщение объединено, 30 сен 2021 --- А не вру ноги ростут из https://www.uclibc.org/docs/psABI-x86_64.pdf 17 страница последний параметр переданный в стек должен быть выровнен на 16 байт. А а следующей что выровнен на 8
Стек должен быть выровнен на 16, но кодер должен выравнивать его на 8, потому что call запушит еще адрес возврата.
Да, относительно того 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-я студия
Я еще до кучи хотел добавить сюда шедевр на FASM от Mikl___ . В этом файле тоже есть хитрое выравнивание, но самое главное, это конечно, РАЗМЕР и НЕСТАНДАРТНОСТЬ EXE-файла!!! До этого я думал, что выравнивание в PE-файле меньше, чем 200 не сделаешь. Но как оказалось - я ошибался. Можно сделать выравнивание и 4 байта. Так же заслуживает внимания и таблица импорта. В общем, шедевр - он и есть шедевр!!! Код (ASM): format binary as 'exe' IMAGE_DOS_SIGNATURE equ 5A4Dh IMAGE_NT_SIGNATURE equ 00004550h PROCESSOR_AMD_X8664 equ 8664h IMAGE_SCN_CNT_CODE equ 00000020h IMAGE_SCN_MEM_READ equ 40000000h IMAGE_SCN_MEM_WRITE equ 80000000h IMAGE_SCN_CNT_INITIALIZED_DATA equ 00000040h IMAGE_SUBSYSTEM_WINDOWS_GUI equ 2 IMAGE_NT_OPTIONAL_HDR64_MAGIC equ 20Bh IMAGE_FILE_RELOCS_STRIPPED equ 1 IMAGE_FILE_EXECUTABLE_IMAGE equ 2 IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE equ 8000h include 'win64a.inc' org 0 use64 IMAGE_BASE = 400000h Signature: dw IMAGE_DOS_SIGNATURE,0 ntHeader dd IMAGE_NT_SIGNATURE;'PE' ;image_header-------------------------- .Machine dw PROCESSOR_AMD_X8664 .Count_of_section dw 0 .TimeStump dd 0 .Symbol_table_offset dd 0;ntHeader .Symbol_table_count dd 0 .Size_of_optional_header dw EntryPoint-optional_header .Characteristics dw 0x20 or IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE ;20h Handle >2Gb addresses ;------------------------------------- optional_header: .Magic_optional_header dw IMAGE_NT_OPTIONAL_HDR64_MAGIC .Linker_version_major_and_minor dw 9 .Size_of_code dd 0 .Size_of_init_data dd 0;xC0 .Size_of_uninit_data dd 0 .entry_point dd EntryPoint .base_of_code dd ntHeader .image_base dq IMAGE_BASE .section_alignment dd 4 .file_alignment dd 4 .OS_version_major_minor dw 5,2 .image_version_major_minor dd 0 .subsystem_version_major_minor dw 5,2 .Win32_version dd 0 .size_of_image dd EndOfImage .size_of_header dd EntryPoint .checksum dd 0 .subsystem dw IMAGE_SUBSYSTEM_WINDOWS_GUI .DLL_flag dw IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE .Stack_allocation dq 0x100000 .Stack_commit dq 0x1000 .Heap_allocation dq 0x100000 .Heap_commit dq 0x1000 .loader_flag dd 0 .number_of_dirs dd (EntryPoint-export_RVA_size)/8 export_RVA_size dq 0 .import_RVA dd import_ .import_size dd end_import-import_ ;------------------------------------------------ EntryPoint: enter 20h,0 ; space for 4 arguments + 16byte aligned stack xor ecx, ecx ; 1. argument: rcx = hWnd = NULL mov r9, rcx ; 4. argument: r9d = uType = MB_OK = 0 mov edx,MsgCaption+IMAGE_BASE ; 2. argument: edx = window text mov r8,rdx ; 3. argument: r8 = caption call [MessageBox] leave ret ;------------------------------------------------ MsgCaption db "Iczelion's tutorial #2a",0 ;------------------------------------------------- Import_Table: user32_table: MessageBox dq _MessageBox import_: dd 0,0,0,user32_dll,user32_table dd 0 user32_dll db "user32",0,0 dw 0 _MessageBox db 0,0,"MessageBoxA" end_import: times 268-end_import db 0 ;filling up to 268 bytes EndOfImage: