Перейти к основному содержимому

Windows x64, WinAPI и отличия от Linux

Разработчику

Контекст: Windows x64, NASM, Intel. Первый запуск и MessageBox (32-bit) — Первая программа. Linux syscall — архитектура программ и справочник.

Два способа попросить ОС о работе

Linux (user mode)Windows (user mode)
syscall с номером в RAXвызов функций из DLL (kernel32.dll, ntdll.dll, …)
аргументы в RDI, RSI, …Microsoft x64 ABI + таблицы импорта PE
исполняемый ELFисполняемый PE (Portable Executable)

Программа на ассемблере под Windows не вызывает ядро напрямую: она зовёт WinAPI (или CRT), а те уже обращаются к системе.


Microsoft x64 calling convention

Первые четыре целочисленных или указательных аргумента:

ПорядокРегистр
1RCX
2RDX
3R8
4R9

Далее — стек (справа налево при подготовке). Вещественные аргументы 1–4 — в XMM0XMM3.

Shadow space (home space): вызывающий резервирует 32 байта на стеке перед call, даже если функция принимает ≤4 аргументов. Это место, куда callee может временно сохранить регистровые аргументы.

Выравнивание: перед call RSP кратен 16 (с учётом того, что call кладёт 8 байт return address).

Возврат:

  • целое / указатель — RAXRDX для 128 бит);
  • float/doubleXMM0.

Callee-saved: RBX, RBP, RDI, RSI, R12R15, XMM6XMM15 (нижние 128 бит XMM6–15).

Это не System V AMD64 из статьи про C на Linux: порядок регистров другой, есть shadow space.


Импорт функций из DLL

В 32-битном stdcall имена декорированы: _MessageBoxA@16 (16 байт аргументов). В 64-битном C-стиле — без суффикса @N, с ведущим подчёркиванием в зависимости от линкера.

; NASM, Win64, консольная подсистема
default rel
section .data
msg db 'Hello, Windows x64', 13, 10
msg_len equ $ - msg
bytes_written dq 0

section .text
global main
extern GetStdHandle
extern WriteFile
extern ExitProcess

main:
push rbp
mov rbp, rsp
sub rsp, 48 ; shadow + выравнивание + локальные

mov rcx, -11 ; STD_OUTPUT_HANDLE
call GetStdHandle
mov rbx, rax ; handle в rbx (callee-saved)

mov rcx, rbx
lea rdx, [msg]
mov r8, msg_len
lea r9, [bytes_written]
mov qword [rsp+32], 0 ; lpOverlapped = NULL (5-й аргумент в shadow+stack)
call WriteFile

xor ecx, ecx
call ExitProcess

Сборка (пример с Microsoft toolchain):

nasm -f win64 hello.asm -o hello.obj
link hello.obj kernel32.lib /subsystem:console /entry:main

Точка входа может быть main (с CRT) или _start при -nostdlib — как в первой программе.


Сравнение с Linux syscall

Linux sys_write:

mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, len
syscall

Windows WriteFile — больше параметров, handle консоли через GetStdHandle, другой ABI. Номера и регистры не переносятся между ОС.


Файлы — CreateFile, ReadFile, CloseHandle

Типичная цепочка (логика, не полный листинг):

  1. CreateFileA/W — открыть или создать (RCX = имя, RDX = access, R8 = share, R9 = security; остальное на стеке).
  2. ReadFile / WriteFile — handle в RCX, буфер в RDX, размер в R8, указатель на DWORD «сколько прочитано» в R9.
  3. CloseHandleRCX = handle.

Ошибки — через GetLastError (возвращает код в RAX после вызова API в некоторых обёртках; уточняйте документацию вызываемой функции).


PE и линковка (кратко)

  • Секции .text, .data, .rdata аналогичны ELF по роли.
  • Таблица импорта подключает kernel32.dll автоматически при линковке с kernel32.lib.
  • Дизассемблирование: objdump из MinGW или dumpbin из MSVC — см. чтение листинга, формат другой, идея та же.

32-бит и 64-бит на Windows

32-bit64-bit
Вызов APIчаще stdcall, аргументы на стекерегистры + shadow
Имена@N суффиксбез байтового суффикса
РегистрыEAX, EBX, …RAX, RBX, …

Учебный MessageBox в 7.mdwin32 stdcall. Портирование на x64 требует перекладки аргументов в RCX, RDX, R8, R9 и shadow space.


Когда выбирать Windows-трек

  • драйверы и Win32-утилиты под заказчиков на Windows;
  • отладка чужих .exe / DLL;
  • сравнение с курсом на Linux в одной энциклопедии.

Для кроссплатформенного ядра знаний сначала закрепите Linux x86-64 + NASM (7 в варианте syscall, 12), затем переносите идеи на WinAPI с заменой ABI.


Связанные материалы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).