Ассемблер MASM не видит функции из "Windows API"-ских библиотек

Изучаю Ассемблер для архитектур x86 Intel-овских процессоров на Windows. Новичок.

Ассемблер MASM не видит функции из "Windows API"-ских библиотек. Вот весь мой код "Hello world"-а через MessageBox. (".inc"-файлы и прочее использовать не хочу, хочу в деталях самим расписывать и без них делать. Использую не MASM32 из сайта masm32.com, а ml.exe из папки Visual Studio (использую Visual Studio 2019 года. У самого́ Windows 7)).

; Код на MASM

.386    ; Указывается процессор с минимальным набором функций (так как новые процессоры Intel (в линейке "x86") совместимы (пока что) к инструкциям старых процессоров Intel той же линейки)

option      casemap:none    ; Насколько я понял, функции из Windows API без чувствительности к регистру не работают

; **** Импорт того что нужно ****

includelib  "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86\kernel32.lib"   ; Загружаю главную статическую библиотеку без которой (насколько я понял) не заработает ни одна Windows-программа (то есть неконсольная)

extern      LoadLibraryA:near     ; Загружаю из статических библиотек используемые в этой программе функции (не знаю near использовать или far, но буду использовать near, так как читал что библиотеки (статические и динамические) загружаются прямо в пространство памяти самой программы)
extern      GetProcAddress:near   ; ^
extern      FreeLibrary:near      ; ^
extern      ExitProcess:near      ; ^

; **** Объявление сегментов памяти ****

.model flat     ; Директива, без которой, походу, 32-битное приложение не напишешь

.data

        header                  db  'Title of hello world', 0   ; Заголовок "Text Box"-овского окна
        text                    db  'Hello world', 0            ; Текст в "Text Box"-овском окне

        nameOfDLL               db  'user32.dll', 0             ; Здесь хранится имя подключаемой DLL библиотеки
        nameOfProcedureOfDLL    db  'MessageBoxA', 0            ; Здесь хранится имя подключаемой процедуры

        handlerToModule         dd  0
        addressOfProcedureOfDLL dd  0                           ; Зарезервировал для передачи сюда (на хранение) адреса DLL-овской функции

.code

; **** Точка входа в программу ****

_StartOfProgram:    ; Ассемблер MASM почему-то рекомендует ставить знак "_" перед меткой точки входа в программу

        push    offset nameOfDLL
        call    LoadLibraryA             ; Динамически подключаю DLL чтобы потом взять из неё функцию
        
        mov     handlerToModule, eax
        
        push    offset nameOfProcedureOfDLL
        push    eax                         ; Соглашение о вызове у функций Windows API используется stdcall - значит аргументы передаются задом наперёд, поэтому регистр eax последним. В eax пока что содержится адрес функции, поэтому лучше использовать регистр, процессор быстрее работает с регистрами
        call    GetProcAddress

        mov     addressOfProcedureOfDLL, eax   ; Сохраняю адрес процедуры MessageBox (чтоб тыщу раз потом не вызывать GetProcAddress)

        push    0
        push    offset text
        push    offset header
        push    0
        call    eax                     ; В eax адрес функции MessageBoxA. То есть вызываю эту функцию. Так как вместо регистров(то есть в данном случае eax) подставляется не адрес(как у меток), а само значение, то есть, в данном случае, адрес функции

        push    0
        call    ExitProcess

end _StartOfProgram

А консоль выдаёт вот что:

Microsoft Windows [Version 6.1.7601]
(c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.

C:\Windows\system32>"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x86\ml.exe" "C:\Assembler\Main.asm" /link /subsystem:windows
Microsoft (R) Macro Assembler Version 14.29.30138.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: C:\Assembler\Main.asm
C:\Assembler\Main.asm(43) : error A2006:undefined symbol : LoadLibraryA
C:\Assembler\Main.asm(46) : error A2006:undefined symbol : ExitProcess
C:\Assembler\Main.asm(50) : error A2006:undefined symbol : GetProcAddress
C:\Assembler\Main.asm(61) : error A2006:undefined symbol : ExitProcess

Не понимаю как это решить, чтобы MASM видел что эти функции (LoadLibraryA, и т.д.) находятся в "kernel32.dll" (на которую в теории должна указывать "kernel32.lib" подключенная с помощью директивы "includelib")


Ответы (1 шт):

Автор решения: Developer

Решил сам. Оказывается просто надо было все функции объявлять с подчёркиванием "_" в начале имени функции и "собакой" "@" на конце имени функции после которой указываются количество байт занимаемых параметрами процедуры.

Вот исправленный код объявления их внешними:

extern      _LoadLibraryA@4:near
extern      _GetProcAddress@8:near
extern      _FreeLibrary@4:near
extern      _ExitProcess@4:near

И при использовании (например через "call") тоже надо прописывать их так. Проверял по другому - не работает - писать нужно только так (Windows API-ские функции только, а свои можно хоть как (но надо ли "@" в своих функциях использовать не знаю)):

call    _LoadLibraryA@4

А в 64-битной программе эти функции по другому вызываются, без подчёркивания "_" и без указания собаки "@" и без указания байт параметров после неё.

call    LoadLibraryA

Но при передаче в функцию "GetProcAddress" имени функции которую нужно взять из DLL, нужно писать просто имя функции без этих символов.

Только осталась проблема что файл ".exe" сассемблировался не в нужную папку и теперь либо он не сассемблировался, либо его искать надо, но это уже другая тема, не этого вопроса, а сам вопрос решён.
[Решил] Оказывается надо прописать сначала в командной строке путь к папке в которой должен появится файл с помощью "cd", например " cd "Путь к файлу" "

И, кстати, только что узнал что нужно использовать процедуры с "A" символом на конце, а не "W", если используешь кавычки ' ' или " " для вписывания символов в память, иначе будешь получать иероглифы

→ Ссылка