Ассемблер 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 шт):
Решил сам. Оказывается просто надо было все функции объявлять с подчёркиванием "_" в начале имени функции и "собакой" "@" на конце имени функции после которой указываются количество байт занимаемых параметрами процедуры.
Вот исправленный код объявления их внешними:
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", если используешь кавычки ' ' или " " для вписывания символов в память, иначе будешь получать иероглифы