News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Stupid questions on LINK, LIB and DLLs

Started by bf2, October 12, 2011, 04:22:32 PM

Previous topic - Next topic

bf2

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.

dedndave

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

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

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

clive

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
It could be a random act of randomness. Those happen a lot as well.

bf2

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?

bf2

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...

mineiro

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


bf2

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.

Vortex

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

dedndave

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 ?

bf2

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.

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

bf2

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.

qWord

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"
FPU in a trice: SmplMath
It's that simple!