Кроме того, проверить Стив Гибсон малого прекрасно окна сборки стартера комплект.
Джереми
Отказ от использования c-библиотек - довольно странное ограничение. Необходимо вызвать некоторую библиотеку в операционной системе MS-Windows. вероятно, kernel32.dll. Написал ли Microsoft это на c или на Паскале, это не имеет значения. Означает ли это, что могут быть вызваны только функции, предоставляемые ОС, что в системе типа Unix будет называться системными вызовами?
Альберт ван дер Хорст
Я предполагаю, что с библиотеками C он или она имеет в виду не использовать библиотеки времени выполнения C, подобные тем, которые поставляются с GCC или MSVC. Конечно, ему или ей придется использовать некоторые стандартные библиотеки DLL Windows, например, kernel32.dll.
Руди
2
Различие между kernel32.dll и библиотекой времени выполнения gcc заключается не в формате (оба являются dll) и не в языке (оба, вероятно, c, но это скрыто). Разница в том, поставляется ОС или нет.
Альберт ван дер Хорст
Я тоже искал это, лол, не мог найти ничего с fasm без
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World"on one lineand
; then exits. It needs to be linked with a C library.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
message:
db 'Hello, World', 10, 0
16-битный код с системными вызовами MS-DOS: работает в эмуляторах DOS или в 32-битной Windows с поддержкой NTVDM . Невозможно запустить "напрямую" (прозрачно) под любой 64-битной Windows, потому что ядро x86-64 не может использовать режим vm86.
В вопросе явно упоминается «без использования библиотек C»
Мехрдад Афшари,
25
Неправильно. Сама библиотека C, очевидно, может, так что это возможно. На самом деле это лишь немного сложнее. Вам просто нужно вызвать WriteConsole () с правильными 5 параметрами.
MSalters
12
Хотя во втором примере не вызывается никакая функция библиотеки C, это тоже не программа Windows. Виртуальная машина DOS будет запущена для ее запуска.
Rômulo Ceccon
7
@Alex Hart, его второй пример предназначен для DOS, а не для Windows. В DOS программы в крошечном режиме (файлы .COM, общий код + данные + стек меньше 64 КБ) начинаются с 0x100h, потому что первые 256 байт в сегменте заняты PSP (аргументы командной строки и т. Д.). См. Эту ссылку: en.wikipedia.org/wiki/Program_Segment_Prefix
zvolkov
7
Это не то, о чем просили. В первом примере используется библиотека C, а во втором - MS-DOS, а не Windows.
Пауло Пинто
131
В этом примере показано, как перейти непосредственно к Windows API, а не ссылаться на стандартную библиотеку C.
Это примеры Win32 и Win64 с использованием вызовов Windows API. Они предназначены для MASM, а не для NASM, но взгляните на них. Вы можете найти более подробную информацию в этой статье.
Это использует MessageBox вместо вывода на стандартный вывод.
Win32 MASM
;---ASM Hello World Win32 MessageBox
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
title db 'Win32', 0
msg db 'Hello World', 0
.code
Main:
push0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
subrsp, 28hmovrcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
Чтобы собрать и связать их с помощью MASM, используйте это для 32-битного исполняемого файла:
Почему Windows x64 необходимо зарезервировать 28 байт пространства стека перед a call? Это 32 байта (0x20) теневого пространства или домашнего пространства, как того требует соглашение о вызовах. И еще 8 байт для повторного выравнивания стека на 16, потому что соглашение о вызовах требует РСП быть 16-байтовый выровнены передcall тем . (Это mainсделал наш вызывающий (в коде запуска CRT). 8-байтовый адрес возврата означает, что RSP находится на расстоянии 8 байтов от 16-байтовой границы при входе в функцию.)
Теневое пространство может использоваться функцией для выгрузки своих аргументов регистра рядом с тем местом, где могут быть любые аргументы стека (если есть). A system callтребует 30h (48 байтов), чтобы также зарезервировать место для r10 и r11 в дополнение к ранее упомянутым 4 регистрам. Но вызовы DLL - это просто вызовы функций, даже если они являются оболочкой для syscallинструкций.
Интересный факт: не Windows, то есть соглашение о вызовах x86-64 System V (например, в Linux) вообще не использует теневое пространство и использует до 6 целочисленных аргументов / указателей регистров и до 8 аргументов FP в регистрах XMM. .
Используя invokeдирективу MASM (которая знает соглашение о вызовах), вы можете использовать один ifdef, чтобы создать его версию, которая может быть 32-битной или 64-битной.
Вариант макроса одинаков для обоих, но так вы не научитесь сборке. Вместо этого вы изучите asm в стиле C. invokeдля stdcallили fastcallпока cinvokeявляется для cdeclили переменного аргумента fastcall. Ассемблер знает, что использовать.
Вы можете разобрать вывод, чтобы увидеть, насколько invokeрасширен.
+1 за ваш ответ. Не могли бы вы добавить код сборки для Windows и на ARM (WOA)?
Энни
1
Почему rsp требует 0x28 байт, а не 0x20? Все ссылки на соглашение о вызовах говорят, что должно быть 32, но, похоже, на практике требуется 40.
douggard
В вашем 32-битном коде окна сообщения по какой-то причине, когда я использую titleимя метки, я сталкиваюсь с ошибками. Однако, когда я использую что-то другое в качестве названия ярлыка mytitle, все работает нормально.
user3405291
как это сделать без включения?
bluejayke
13
Плоский Ассемблер не требует дополнительного компоновщика. Это упрощает программирование на ассемблере. Он также доступен для Linux.
Это hello.asmиз примеров Fasm:
include'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
где path_to_link может быть C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin или где бы ни была ваша программа link.exe на вашем компьютере,
path_to_libs может быть C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6.3 \ um \ x64 или где бы то ни было ваши библиотеки (в этом случае и kernel32.lib, и user32.lib находятся в одном месте, в противном случае используйте один вариант для каждого нужного опции необходимо, чтобы линкер не жаловался на адреса слишком долго (в данном случае для user32.lib). Кроме того, как это сделано здесь, если компоновщик Visual вызывается из командной строки, необходимо предварительно настроить среду (запустить один раз vcvarsall.bat и / или просмотреть MS C ++ 2010 и mspdb100.dll пути) и / largeaddressaware: no ).
Я настоятельно рекомендую использовать его default relв верхней части файла, чтобы эти режимы адресации ( [msg]и [title]) использовали относительную адресацию RIP вместо 32-битной абсолютной.
Питер Кордес
Спасибо, что объяснили, как связать! Вы спасли мое психическое здоровье. Я начал выдирать волосы из-за «ошибки LNK2001: неразрешенный внешний символ ExitProcess» и подобных ошибок ...
Ник,
5
Если вы не вызовете какую-либо функцию, это совсем не тривиально. (И, серьезно, нет реальной разницы в сложности между вызовом printf и вызовом функции api win32.)
Даже DOS int 21h на самом деле просто вызов функции, даже если это другой API.
Если вы хотите сделать это без посторонней помощи, вам нужно напрямую поговорить с вашим видеооборудованием, вероятно, записывая растровые изображения букв «Hello world» во фреймбуфер. Даже тогда видеокарта выполняет работу по преобразованию этих значений памяти в сигналы VGA / DVI.
Обратите внимание, что на самом деле ничто из этого, вплоть до аппаратного обеспечения, в ASM не интереснее, чем в C. Программа "hello world" сводится к вызову функции. В ASM есть одна приятная особенность: вы можете довольно легко использовать любой ABI; вам просто нужно знать, что это за ABI.
Это отличный момент - ASM и C полагаются на функцию, предоставляемую ОС (_WriteFile в Windows). Так где же волшебство? Он находится в коде драйвера устройства для видеокарты.
Асад Ибрагим
2
Это совершенно не по существу. Плакат просит ассемблерную программу, работающую «под Windows». Это означает, что можно использовать средства Windows (например, kernel32.dll), но нельзя использовать другие средства, такие как libc в Cygwin. Для крика вслух плакат явно говорит, что нет c-библиотек.
Альберт ван дер Хорст
5
Лучшие примеры - с fasm, потому что fasm не использует компоновщик, который скрывает сложность программирования Windows другим непрозрачным уровнем сложности. Если вас устраивает программа, которая записывает данные в окно графического интерфейса пользователя, то есть пример для этого в каталоге примеров fasm.
Если вам нужна консольная программа, которая позволяет перенаправлять стандартный вход и стандартный выход, что также возможно. Доступен (очень нетривиальный) пример программы, которая не использует графический интерфейс и работает строго с консолью, то есть с самим fasm. Это можно проредить до самого необходимого. (Я написал четвертый компилятор, который является еще одним примером, не связанным с графическим интерфейсом, но он также нетривиален).
В такой программе есть следующая команда для создания правильного заголовка для 32-разрядного исполняемого файла, обычно выполняемая компоновщиком.
FORMAT PE CONSOLE
Раздел под названием '.idata' содержит таблицу, которая помогает окнам во время запуска связывать имена функций с адресами среды выполнения. Он также содержит ссылку на KERNEL.DLL, которая является операционной системой Windows.
Формат таблицы определяется окнами и содержит имена, которые просматриваются в системных файлах при запуске программы. FASM скрывает некоторые сложности за ключевым словом rva. Итак, _ExitProcess @ 4 - это метка fasm, а _exitProcess - это строка, которую ищет Windows.
Ваша программа находится в разделе '.text'. Если вы объявляете этот раздел доступным для чтения, записываемым и исполняемым, это единственный раздел, который вам нужно добавить.
section '.text' code executable readable writable
Вы можете вызвать все объекты, которые вы заявили в разделе .idata. Для консольной программы вам понадобится _GetStdHandle, чтобы найти файловые дескрипторы для стандартных входов и стандартных выходов (с использованием символических имен, таких как STD_INPUT_HANDLE, которые fasm находит во включаемом файле win32a.inc). Когда у вас есть файловые дескрипторы, вы можете выполнять WriteFile и ReadFile. Все функции описаны в документации kernel32. Вы, вероятно, знаете об этом, иначе вы не стали бы пробовать программировать на ассемблере.
В итоге: есть таблица с именами asci, которые связаны с ОС Windows. Во время запуска она преобразуется в таблицу вызываемых адресов, которую вы используете в своей программе.
FASM может не использовать компоновщик, но он все равно должен собрать PE-файл. Это означает, что на самом деле он не просто ассемблирует код, но и берет на себя работу, которую обычно выполняет компоновщик, и поэтому, по моему скромному мнению, ошибочно называть отсутствие компоновщика «скрывающей сложностью», как раз наоборот. - задача ассемблера - собрать программу, но предоставить компоновщику возможность встроить программу в образ программы, который может зависеть от многих вещей. Таким образом, я считаю, что разделение между компоновщиком и ассемблером - это хорошо , и, похоже, вы не согласны с этим.
атп
@amn Подумайте об этом иначе. Если вы используете компоновщик для создания вышеуказанной программы, дает ли он вам больше информации о том, что программа делает или из чего она состоит? Если я посмотрю на исходный код fasm, я знаю полную структуру программы.
Альберт ван дер Хорст,
Честная оценка. С другой стороны, отделение ссылок от всего остального тоже имеет свои преимущества. Обычно у вас есть доступ к объектному файлу (который имеет большое значение для проверки структуры программы, независимо от формата файла образа программы), вы можете вызвать другой компоновщик по своему усмотрению с различными параметрами. Речь идет о возможности повторного использования и компоновки. Имея это в виду, FASM делает все, потому что это «удобно», нарушает эти принципы. Я принципиально не против - я вижу у них оправдание, - но мне, например, это не нужно.
атп
получить ошибку из-за незаконного нарушения в верхней строке в 64-битных окнах fasm
bluejayke
@bluejayke Возможно, у вас не было под рукой документации по fasm. FORMAT PE генерирует 32-битный исполняемый файл, который 64-битные окна отказываются запускать. Для 64-битной программы вам понадобится FORMAT PE64. Также убедитесь, что вы используете правильные 64-битные инструкции в своей программе.
Альберт ван дер Хорст,
3
Если вы хотите использовать NASM и компоновщик Visual Studio (link.exe) с примером Hello World от anderstornvig, вам придется вручную установить связь с библиотекой времени выполнения C, содержащей функцию printf ().
Ответы:
Примеры NASM .
Вызов libc stdio
printf
, реализацияint main(){ return printf(message); }
; ---------------------------------------------------------------------------- ; helloworld.asm ; ; This is a Win32 console program that writes "Hello, World" on one line and ; then exits. It needs to be linked with a C library. ; ---------------------------------------------------------------------------- global _main extern _printf section .text _main: push message call _printf add esp, 4 ret message: db 'Hello, World', 10, 0
Тогда беги
nasm -fwin32 helloworld.asm gcc helloworld.obj a
Также существует The Clueless Newbies Guide to Hello World в Nasm без использования библиотеки C. Тогда код будет выглядеть так.
16-битный код с системными вызовами MS-DOS: работает в эмуляторах DOS или в 32-битной Windows с поддержкой NTVDM . Невозможно запустить "напрямую" (прозрачно) под любой 64-битной Windows, потому что ядро x86-64 не может использовать режим vm86.
org 100h mov dx,msg mov ah,9 int 21h mov ah,4Ch int 21h msg db 'Hello, World!',0Dh,0Ah,'$'
Встройте это в
.com
исполняемый файл, чтобы он загружалсяcs:100h
со всеми сегментными регистрами, равными друг другу (крошечная модель памяти).Удачи.
источник
В этом примере показано, как перейти непосредственно к Windows API, а не ссылаться на стандартную библиотеку C.
global _main extern _GetStdHandle@4 extern _WriteFile@20 extern _ExitProcess@4 section .text _main: ; DWORD bytes; mov ebp, esp sub esp, 4 ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE) push -11 call _GetStdHandle@4 mov ebx, eax ; WriteFile( hstdOut, message, length(message), &bytes, 0); push 0 lea eax, [ebp-4] push eax push (message_end - message) push message push ebx call _WriteFile@20 ; ExitProcess(0) push 0 call _ExitProcess@4 ; never here hlt message: db 'Hello, World', 10 message_end:
Для компиляции вам понадобятся NASM и LINK.EXE (из Visual Studio Standard Edition).
источник
gcc hello.obj
Это примеры Win32 и Win64 с использованием вызовов Windows API. Они предназначены для MASM, а не для NASM, но взгляните на них. Вы можете найти более подробную информацию в этой статье.
Это использует MessageBox вместо вывода на стандартный вывод.
Win32 MASM
;---ASM Hello World Win32 MessageBox .386 .model flat, stdcall include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib .data title db 'Win32', 0 msg db 'Hello World', 0 .code Main: push 0 ; uType = MB_OK push offset title ; LPCSTR lpCaption push offset msg ; LPCSTR lpText push 0 ; hWnd = HWND_DESKTOP call MessageBoxA push eax ; uExitCode = MessageBox(...) call ExitProcess End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox extrn MessageBoxA: PROC extrn ExitProcess: PROC .data title db 'Win64', 0 msg db 'Hello World!', 0 .code main proc sub rsp, 28h mov rcx, 0 ; hWnd = HWND_DESKTOP lea rdx, msg ; LPCSTR lpText lea r8, title ; LPCSTR lpCaption mov r9d, 0 ; uType = MB_OK call MessageBoxA add rsp, 28h mov ecx, eax ; uExitCode = MessageBox(...) call ExitProcess main endp End
Чтобы собрать и связать их с помощью MASM, используйте это для 32-битного исполняемого файла:
ml.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
или это для 64-битного исполняемого файла:
ml64.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
Почему Windows x64 необходимо зарезервировать 28 байт пространства стека перед a
call
? Это 32 байта (0x20) теневого пространства или домашнего пространства, как того требует соглашение о вызовах. И еще 8 байт для повторного выравнивания стека на 16, потому что соглашение о вызовах требует РСП быть 16-байтовый выровнены передcall
тем . (Этоmain
сделал наш вызывающий (в коде запуска CRT). 8-байтовый адрес возврата означает, что RSP находится на расстоянии 8 байтов от 16-байтовой границы при входе в функцию.)Теневое пространство может использоваться функцией для выгрузки своих аргументов регистра рядом с тем местом, где могут быть любые аргументы стека (если есть). A
system call
требует 30h (48 байтов), чтобы также зарезервировать место для r10 и r11 в дополнение к ранее упомянутым 4 регистрам. Но вызовы DLL - это просто вызовы функций, даже если они являются оболочкой дляsyscall
инструкций.Интересный факт: не Windows, то есть соглашение о вызовах x86-64 System V (например, в Linux) вообще не использует теневое пространство и использует до 6 целочисленных аргументов / указателей регистров и до 8 аргументов FP в регистрах XMM. .
Используя
invoke
директиву MASM (которая знает соглашение о вызовах), вы можете использовать один ifdef, чтобы создать его версию, которая может быть 32-битной или 64-битной.ifdef rax extrn MessageBoxA: PROC extrn ExitProcess: PROC else .386 .model flat, stdcall include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib endif .data caption db 'WinAPI', 0 text db 'Hello World', 0 .code main proc invoke MessageBoxA, 0, offset text, offset caption, 0 invoke ExitProcess, eax main endp end
Вариант макроса одинаков для обоих, но так вы не научитесь сборке. Вместо этого вы изучите asm в стиле C.
invoke
дляstdcall
илиfastcall
покаcinvoke
является дляcdecl
или переменного аргументаfastcall
. Ассемблер знает, что использовать.Вы можете разобрать вывод, чтобы увидеть, насколько
invoke
расширен.источник
title
имя метки, я сталкиваюсь с ошибками. Однако, когда я использую что-то другое в качестве названия ярлыкаmytitle
, все работает нормально.Плоский Ассемблер не требует дополнительного компоновщика. Это упрощает программирование на ассемблере. Он также доступен для Linux.
Это
hello.asm
из примеров Fasm:include 'win32ax.inc' .code start: invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK invoke ExitProcess,0 .end start
Fasm создает исполняемый файл:
А это программа в IDA :
Вы можете увидеть три вызова:
GetCommandLine
,MessageBox
иExitProcess
.источник
Чтобы получить .exe с помощью компилятора NASM и компоновщика Visual Studio, этот код отлично работает:
global WinMain extern ExitProcess ; external functions in system libraries extern MessageBoxA section .data title: db 'Win64', 0 msg: db 'Hello world!', 0 section .text WinMain: sub rsp, 28h mov rcx, 0 ; hWnd = HWND_DESKTOP lea rdx,[msg] ; LPCSTR lpText lea r8,[title] ; LPCSTR lpCaption mov r9d, 0 ; uType = MB_OK call MessageBoxA add rsp, 28h mov ecx,eax call ExitProcess hlt ; never here
Если этот код сохранен, например, в "test64.asm", то для компиляции:
nasm -f win64 test64.asm
Производит "test64.obj" Затем для ссылки из командной строки:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
где path_to_link может быть C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin или где бы ни была ваша программа link.exe на вашем компьютере, path_to_libs может быть C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6.3 \ um \ x64 или где бы то ни было ваши библиотеки (в этом случае и kernel32.lib, и user32.lib находятся в одном месте, в противном случае используйте один вариант для каждого нужного опции необходимо, чтобы линкер не жаловался на адреса слишком долго (в данном случае для user32.lib). Кроме того, как это сделано здесь, если компоновщик Visual вызывается из командной строки, необходимо предварительно настроить среду (запустить один раз vcvarsall.bat и / или просмотреть MS C ++ 2010 и mspdb100.dll пути) и / largeaddressaware: no ).
источник
default rel
в верхней части файла, чтобы эти режимы адресации ([msg]
и[title]
) использовали относительную адресацию RIP вместо 32-битной абсолютной.Если вы не вызовете какую-либо функцию, это совсем не тривиально. (И, серьезно, нет реальной разницы в сложности между вызовом printf и вызовом функции api win32.)
Даже DOS int 21h на самом деле просто вызов функции, даже если это другой API.
Если вы хотите сделать это без посторонней помощи, вам нужно напрямую поговорить с вашим видеооборудованием, вероятно, записывая растровые изображения букв «Hello world» во фреймбуфер. Даже тогда видеокарта выполняет работу по преобразованию этих значений памяти в сигналы VGA / DVI.
Обратите внимание, что на самом деле ничто из этого, вплоть до аппаратного обеспечения, в ASM не интереснее, чем в C. Программа "hello world" сводится к вызову функции. В ASM есть одна приятная особенность: вы можете довольно легко использовать любой ABI; вам просто нужно знать, что это за ABI.
источник
Лучшие примеры - с fasm, потому что fasm не использует компоновщик, который скрывает сложность программирования Windows другим непрозрачным уровнем сложности. Если вас устраивает программа, которая записывает данные в окно графического интерфейса пользователя, то есть пример для этого в каталоге примеров fasm.
Если вам нужна консольная программа, которая позволяет перенаправлять стандартный вход и стандартный выход, что также возможно. Доступен (очень нетривиальный) пример программы, которая не использует графический интерфейс и работает строго с консолью, то есть с самим fasm. Это можно проредить до самого необходимого. (Я написал четвертый компилятор, который является еще одним примером, не связанным с графическим интерфейсом, но он также нетривиален).
В такой программе есть следующая команда для создания правильного заголовка для 32-разрядного исполняемого файла, обычно выполняемая компоновщиком.
Раздел под названием '.idata' содержит таблицу, которая помогает окнам во время запуска связывать имена функций с адресами среды выполнения. Он также содержит ссылку на KERNEL.DLL, которая является операционной системой Windows.
section '.idata' import data readable writeable dd 0,0,0,rva kernel_name,rva kernel_table dd 0,0,0,0,0 kernel_table: _ExitProcess@4 DD rva _ExitProcess CreateFile DD rva _CreateFileA ... ... _GetStdHandle@4 DD rva _GetStdHandle DD 0
Формат таблицы определяется окнами и содержит имена, которые просматриваются в системных файлах при запуске программы. FASM скрывает некоторые сложности за ключевым словом rva. Итак, _ExitProcess @ 4 - это метка fasm, а _exitProcess - это строка, которую ищет Windows.
Ваша программа находится в разделе '.text'. Если вы объявляете этот раздел доступным для чтения, записываемым и исполняемым, это единственный раздел, который вам нужно добавить.
section '.text' code executable readable writable
Вы можете вызвать все объекты, которые вы заявили в разделе .idata. Для консольной программы вам понадобится _GetStdHandle, чтобы найти файловые дескрипторы для стандартных входов и стандартных выходов (с использованием символических имен, таких как STD_INPUT_HANDLE, которые fasm находит во включаемом файле win32a.inc). Когда у вас есть файловые дескрипторы, вы можете выполнять WriteFile и ReadFile. Все функции описаны в документации kernel32. Вы, вероятно, знаете об этом, иначе вы не стали бы пробовать программировать на ассемблере.
В итоге: есть таблица с именами asci, которые связаны с ОС Windows. Во время запуска она преобразуется в таблицу вызываемых адресов, которую вы используете в своей программе.
источник
Если вы хотите использовать NASM и компоновщик Visual Studio (link.exe) с примером Hello World от anderstornvig, вам придется вручную установить связь с библиотекой времени выполнения C, содержащей функцию printf ().
nasm -fwin32 helloworld.asm link.exe helloworld.obj libcmt.lib
Надеюсь, это кому-то поможет.
источник