I was trying to see if I can write, assemble and link a simple source file without using any of the MASM32 includes and includelibs, i.e. just using plain MASM.
So my source code was this:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
EXTERN MessageBoxA@16:NEAR
EXTERN ExitProcess@4:NEAR
.DATA
MB_OK EQU 0
caption DB "Caption", 0
text DB "Text", 0
hWindow DD ?
.CODE
start:
PUSH MB_OK
PUSH OFFSET caption
PUSH OFFSET text
PUSH hWindow
CALL MessageBoxA@16
PUSH 0
CALL ExitProcess@4
END start
I know I have to now somehow tell the linker that ExitProcess is in kernel32.dll and MessageBox is in user32.dll.
Question 1a: Why doesn't the LINK utility accept a DLL name as input? Or does it? According to MSDN, input to the linker can only be .OBJ, .LIB etc, but not a .DLL file. I can specify a DLL name to the GCC linker (using the -l switch) but not to the Microsoft linker. Why?
Question 1b: What is the purpose of a LIB file when the DLL already has all the information about the function?
Question 2: If I do have to create a LIB file out of kernel32.dll and user32.dll - how do I do that? The LIB utility doesn't appear to accept a DLL as input.
Thanks in advance.
first of all, you must understand what some of the files are that exist in the masm32 package
windows.inc, kernel32.inc, user32.inc, etc, define windows functions and constants
these are part of windows - not really part of the masm32 library, per se
they are derived from the windows.h, kernel32.h, user32.h, etc, files that MS provides for C compilers
that's not to say it isn't a lot of work (mostly on Hutch's part) to translate them for ASM :P
masm32.inc, masm32.lib, macros.asm, and a few others, are the actual masm32 functions and macro defintions
these functions were written by Hutch and friends and added to the package
when we use a function from, say, user32.dll, we do it by way of an "export library" named user32.lib
Hutch has a batch file that creates these export libraries when you install the package
if you look at masm32\include\bldlibs.bat, you can see how the export libraries are created during installation
to go a little beyond your questions, you can do a lot by using LoadLibrary and GetProcAddress (you'd also want FreeLibrary)
of course, these are kernel32 functions, so you at least need that lib :P
if you were so inclined, you could create an export library or object file that had just those 3 functions to write a program
but, they can be used at run-time to load a dll and get the address of a function
this may be nit picking but the API functions and equate values and structures are defined by the operating system but the include files are part of MASM32.
bf2, Microsoft languages, C and ASM use the LIB or OBJECT module format for the contents of DLLs, there are tools to make your own libraries but you need either libraries or object modules to access DLL functions. As Dave mentioned if you provide the library for LoadLibrary(), GetProcAddress() and FreeLibrary() you can avoid the rest but there is little point in doing so.
The old syntax,
EXTERN MessageBoxA@16:NEAR
EXTERN ExitProcess@4:NEAR
is no longer supported by MASM and this is from more than 10 years ago.
Quotethis may be nit picking but the API functions and equate values and structures
are defined by the operating system but the include files are part of MASM32.
my bad, Hutch :U
Quote from: bf2
Question 1a: Why doesn't the LINK utility accept a DLL name as input? Or does it? According to MSDN, input to the linker can only be .OBJ, .LIB etc, but not a .DLL file. I can specify a DLL name to the GCC linker (using the -l switch) but not to the Microsoft linker. Why?
Question 1b: What is the purpose of a LIB file when the DLL already has all the information about the function?
I think it's just the way Microsoft attacked the problem, but being able to supply a .DLL as a template makes more sense than spitting out LIB/EXP files. Linux's use of ELF files makes the difference between an static object (obj), an executable (exe) and a shared object (dll) only marginally different.
It has a lot to do with linkage, the .LIB contains a "x: jmp [__imp__x]" type construct, which you could presumable avoid by using call [__imp__ExitProcess@4] in your code. That might cause a lot more fun with imports and fixups, as Microsoft would prefer to corral all that off in the IAT and have a singular link to the exporting DLL.
The other issue is that the DLL *doesn't* have to export functions by name, some use ordinals primarily for the purpose of obfuscating things.
The DLL is also system/install specific, the LIB provides generic linkage not tied to a specific DLL implementation (NT4 vs W2K, or MP vs UP). There are DLL hell issues, but then again Linux has issues binding against specific files/distributions which make it a pig to provide code in binary form, probably intentionally so.
The other classic trick has been to take a DLL, generate a DEF file from the exports, and then used the linker to convert that to a form it likes. It's been a while, but I think IMPLIB is a tool you should look at.
Microsoft (R) Import Library Manager Version 1.50
Copyright (C) Microsoft Corp 1984-1993. All rights reserved.
Usage: IMPLIB [options] <output library> <.DEF/.DLL file list>
Options: /?
/help
/nowep
/noignorecase
/nologo
/ntdll
Quote from: hutch-- on October 12, 2011, 04:45:43 PM
The old syntax,
EXTERN MessageBoxA@16:NEAR
EXTERN ExitProcess@4:NEAR
is no longer supported by MASM and this is from more than 10 years ago.
Hutch,
Not sure I understand. What would be the new syntax if I don't want to use PROTO or INVOKE?
OK, got it. Thanks very much everyone for the responses.
Created two plain text files: kernel32.DEF and user32.DEF.
kernel32.DEF contains:
EXPORTS
ExitProcess
user32.DEF contains:
EXPORTS
MessageBoxA
Then created two LIB files out of these: kernel32.LIB and user32.LIB, using the commands:
lib /def:kernel32.def /out:kernel32.lib
lib /def:user32.def /out:user32.lib
Finally, included my LIB files in the source:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
EXTERN MessageBoxA:NEAR
EXTERN ExitProcess:NEAR
.DATA
MB_OK EQU 0
caption DB "Caption", 0
text DB "Text3", 0
hWindow DD ?
.CODE
start:
PUSH MB_OK
PUSH OFFSET caption
PUSH OFFSET text
PUSH hWindow
CALL MessageBoxA
PUSH 0
CALL ExitProcess
END start
And we are done...
Hello Sr bf2, you can hardcode the addresses too:
This example uses no lib. The bad thing is about the static addresses, in your machine can be different, and this example will not work. You can get the addresses of functions in your machine using 'dependency walker'. If you like to use another dll without be kernel32 or ntdll, so you need load that dll using 'loadlibrary".
.386
.model flat,stdcall
.code
org 7c800000h
KERNEL32:
org KERNEL32 + 0001cafah
ExitProcess:
org 00h
start:
push 0
call ExitProcess - 401000h
end start
Now I want to use PROTO and INVOKE, but still want to use my own LIBs.
How do I do that?
I have tried the following:
Attempt 1:
kernel32.def
EXPORTS
ExitProcess
user32.def
EXPORTS
MessageBoxA
Main program:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
ExitProcess PROTO :DWORD
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
.CONST
MB_OK EQU 0
.DATA
caption DB "Caption", 0
text DB "Text4", 0
hWindow DD ?
.CODE
start:
INVOKE MessageBoxA, hWindow, ADDR text, ADDR caption, MB_OK
INVOKE ExitProcess, 0
END start
Result:
Assembles fine but linking fails with 'unresolved external symbol error' for _ExitProcess@4 and _MessageBoxA@16.
Attempt 2:
kernel32.def
EXPORTS
ExitProcess@4
user32.def
EXPORTS
MessageBoxA@16
Main program:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
ExitProcess PROTO :DWORD
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
.CONST
MB_OK EQU 0
.DATA
caption DB "Caption", 0
text DB "Text4", 0
hWindow DD ?
.CODE
start:
INVOKE MessageBoxA, hWindow, ADDR text, ADDR caption, MB_OK
INVOKE ExitProcess, 0
END start
Result:
Assembles fine, links fine but crashes at runtime with the message: 'The procedure entry point ExitProcess@4 could not be located in the dynamic link library kernel32.dll'. If I comment out the call to ExitProcess, then I get the same error for MessageBoxA.
Thanks in advance.
Hi bf2,
You cannot import an export the same functions at one time. Try to write your own DLL exporting different function names. ExitProcess is exported by kernel32.dll and MessageBoxA by user32.dll
hi Erol
i think what he is trying to do is to create a small import library for user32.dll and kernel32.dll
then use those instead of the ones like those provided with the masm32 package
i doubt it will offer any advantage :P
not sure if he thinks it will create a smaller exe - it won't
but, he may be doing it just to learn how the mechanism works
at any rate, i think the prototypes for the imported modules should preceed the includelib directives
not sure if you need a typedef or what - never tried it
externdef _imp___CIacos:PTR c_msvcrt
crt__CIacos equ <_imp___CIacos>
maybe it has to do with how the lib's are created ?
Quote from: dedndave on October 18, 2011, 08:59:52 PM
but, he may be doing it just to learn how the mechanism works
Yes, that was my purpose.
The general drift in creating import ibraries is to understand that they match the DLL that has the functions in it to export. If you want to use shell32.dll functions, you need to create a shell32.lib that contains the exports contained in shell32.dll. Same for all of the other system DLLs.
Now you can call each function once you have the import library working with historical PUSH / CALL notation but if you want the convenience of defining prototypes and calling those functions with "invoke" it is to your advantage to also create matching include files so that you have a shell32.inc file to match the shell32.lib file. As again the same with all of the system DLLs.
This gets you from the barest PUSH / CALL notation to the "invoke" format, if you want to add science to the bare mechanics of calling system functions you start on the MASM pre-processor, its MACRO engine and start writing macros that make more things easier and faster to use. If you do it all correctly you still get the mimimum precision code that is possible in MASM but with close to high level language convenience and speed.
Quote from: dedndave on October 18, 2011, 08:59:52 PMat any rate, i think the prototypes for the imported modules should preceed the includelib directives
not sure if you need a typedef or what - never tried it
externdef _imp___CIacos:PTR c_msvcrt
crt__CIacos equ <_imp___CIacos>
maybe it has to do with how the lib's are created ?
Just opened the MASM32 lib file kernel32.lib in a text browser. Whereas my kernel32.def file exports the function ExitProcess, the MASM32 file kernel32.lib has _ExitProcess@4 and __imp__ExitProcess@4 in it.
I have tried exporting these labels from my DEF file. Still doesn't work.
hi,
you can simply create your own dummy-DLLs and use the corresponding lib's
For building the DLL's:
ink /SUBSYSTEM:WINDOWS /DLL /DEF:user32.def /OUT:"user32.dll" "user32.obj"
__imp__ExitProcess@4 is the one you want
however, i am not sure how to tell it how many parameters it has :P
after that, you need a line something like this so that you don't have to use the mangled name
ExitProcess equ <__imp__ExitProcess@4>
Attempt 3:
kernel32.def contains
EXPORTS
_imp__ExitProcess@4
For user32.lib, I am using the MAMS32 library - just to keep the number of unknowns small.
Source code:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDELIB \masm32\lib\user32.lib ; MASM32 library
INCLUDELIB kernel32.lib ; My library, created from kernel32.def
ExitProcess equ <_imp__ExitProcess>
ExitProcess PROTO :DWORD
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
.CONST
MB_OK EQU 0h
.DATA
caption DB "Caption", 0
text DB "Text4", 0
hWindow DD ?
.CODE
start:
INVOKE MessageBoxA, hWindow, ADDR text, ADDR caption, MB_OK
INVOKE ExitProcess, 0
END start
Result: Assembles fine, links fine, but crashes at runtime with error 'The procedure entry point _imp__ExitProcess@4 could not be located in the dynamic link libary kernel32.dll'.
Hi bf2,
Here is how to create your own module definition files and import libraries :
\masm32\tools\l2def\l2def.exe \masm32\lib\kernel32.lib
\masm32\tools\l2def\l2def.exe \masm32\lib\user32.lib
The commands above will extract the decorated .def files from import libraries. The following commands are creating the import libraries :
\masm32\bin\polib /OUT:kernel32.lib /DEF:kernel32.def /MACHINE:X86
\masm32\bin\polib /OUT:user32.lib /DEF:user32.def /MACHINE:X86
Quote from: Vortex on October 19, 2011, 05:52:00 PM
Hi bf2,
Here is how to create your own module definition files and import libraries :
\masm32\tools\l2def\l2def.exe \masm32\lib\kernel32.lib
\masm32\tools\l2def\l2def.exe \masm32\lib\user32.lib
The commands above will extract the decorated .def files from import libraries. The following commands are creating the import libraries :
\masm32\bin\polib /OUT:kernel32.lib /DEF:kernel32.def /MACHINE:X86
\masm32\bin\polib /OUT:user32.lib /DEF:user32.def /MACHINE:X86
Hi Vortex
I used the LIB command to create kernel32.lib from kernel32.def:
lib /def:kernel32.def /out:kernel32.lib
Hi bf2,
lib.exe can create import libraries too but the sizes are much more large.
i finally got it to work :P
i used the masm32 LIB's, but if your LIB's are correct, they should work
.386
.MODEL Flat,StdCall
OPTION CaseMap:None
;--------------------------------------------------------
MB_OK EQU 0
;-------------------------------
pr1 TYPEDEF PROTO :DWORD
pr4 TYPEDEF PROTO :DWORD,:DWORD,:DWORD,:DWORD
;-------------------------------
EXTERNDEF _imp__ExitProcess@4:PTR pr1
ExitProcess EQU <_imp__ExitProcess@4>
EXTERNDEF _imp__MessageBoxA@16:PTR pr4
MessageBox EQU <_imp__MessageBoxA@16>
;--------------------------------------------------------
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\user32.lib
;--------------------------------------------------------
.DATA
caption1 db 'Caption',0
text1 db 'Text',0
;--------------------------------------------------------
.CODE
_main PROC
INVOKE MessageBox,0,offset text1,offset caption1,MB_OK
INVOKE ExitProcess,0
_main ENDP
;--------------------------------------------------------
END _main
test.asm
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDELIB \masm32\lib\user32.lib ; MASM32 library
INCLUDELIB kernel32.lib ; My library, created from kernel32.def
ExitProcess PROTO :DWORD
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
.CONST
MB_OK EQU 0h
.DATA
caption DB "Caption", 0
text DB "Text4", 0
hWindow DD ?
.CODE
start:
INVOKE MessageBoxA, hWindow, ADDR text, ADDR caption, MB_OK
INVOKE ExitProcess, 0
END start
kernel32.def
LIBRARY kernel32
EXPORTS
_ExitProcess@4
\masm32\bin\polib /machine:ix86 /def:kernel32.def /out:kernel32.lib
ml -coff test.asm -link /SUBSYSTEM:WINDOWS
C:\MASM>\masm32\bin\polib /machine:ix86 /def:kernel32.def /out:kernel32.lib
C:\MASM>ml -coff test.asm -link /SUBSYSTEM:WINDOWS
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
Assembling: test.asm
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/SUBSYSTEM:WINDOWS
"test.obj"
"/OUT:test.exe"
test.exe runs correctly.
LIB will not generate the correct linkage for this to work, use POLIB.
Clive's looks simpler than mine :P
Quote from: dedndave on October 19, 2011, 06:53:31 PM
Clive's looks simpler than mine
It just reinforces what a half-assed job most vendors do with object files and linkers, which becomes painfully evident if you try to do things slightly outside the norm, but really should be achievable.
Even with something like ELF I had to build tools to get WATCOM ELF objects to be viable under Linux.
The linker really should be able to use a DLL as a template in the absence of a LIB, or at the very least be able to synthesize the LIB directly from the DLL or a DEF file properly.
Thanks very much gents! Much appreciate your patience and help.