-
Currently i´m using MS´s stuff for linking, looking for a more lightweight alternative i saw you use linkw.exe and libw.exe in your makefiles. I couldn´t find sufficient documetation or a manual for these. Running linkw/libw from a console with "?" outputs a list of command line options, which unfortunately lacks some information, e.g. there are no listed options for "sys(tem)" for linkw. From your makefile i can see "con_32" and "con_64", which means: console 32/64 i guess. But what to use for a GUI app and how to create a DLL or a LIB. I would prefer giving options in a command line and a list of files via command file and having all of this in a batch file. Could you supply a (link to a) manual or more comprehensive documentation for linkw and libw please (and add these to your package, if possible). |
Beta Was this translation helpful? Give feedback.
Replies: 13 comments
-
LINKW is a fork of JWLINK, which in turn is a fork of the Open Watcom linker WLINK. I added a few changes to the 64 bit section to make it more compatible with Visual Studio (mostly for creating libraries), and some command line options (like wildcards). However, newer version of VS (2019+) added some changes to the import library format so LIBW is not compatible with these changes. It works for static libraries so LIBC is built using LIBW, but the import libraries are built using LIB to enable debugging using VS. I haven't really looked into to it yet but I guess it's a trivial issue to fix as LINKW works fine with the import created by LIB and VS works fine with the libraries created by LIBW. LINKW uses a default configuration file (LINKW.LNK) in the current directory if exists, or (in this case) the EXE directory if present. The default system targets used are defined there. There some samples in the test directory for some of the system targets. |
Beta Was this translation helpful? Give feedback.
-
I see - thanks. So, what is your recommendation? Should i stick to MS´s stuff or should i switch to libw and linkw? |
Beta Was this translation helpful? Give feedback.
-
There's also a linker integrated in Asmc so technically you don't need any of them. It's rather limited but most one-source samples and tools are built without any external linker. I tend to use LINKW for most releases as it creates more compact binaries with less dependencies. Asmc do however provide full symbolic debug information and integration into Visual Studio and most (if not all) sources and libraries are built specifically for this. So it's a mixed bag where a project may have both a makefile and a VS project file configuration.
Most tool-chains provides modules and tools to produce independent binaries, and they usually have a specific entry and naming convention into a static library of sorts. Whats provided here is some static (and dynamic) entries to Open Watcom (mostly 16/32-bit), Linux (mostly 64-bit), and Windows (32/64, ANSI/UNICODE). The startup modules for Windows are [w]WinMainCRTStartup and [w]mainCRTStartup This means you have 8 different static modules for Windows. 4 located in The linker configurations is then made specifically for use with these local modules. If you have your own startup modules you may create a new configuration file or add sections to the current one. |
Beta Was this translation helpful? Give feedback.
-
Here's an example with 8 different modules for the same source using the standard macros. This sample loads the include htmlhelp.inc
include stdio.inc
include conio.inc
include tchar.inc
.code
_tmain proc
HtmlHelp(GetDesktopWindow(),
"..\\..\\..\\..\\..\\bin\\asmc.chm::/index.htm>Mainwin", HH_DISPLAY_TOPIC, NULL )
_getch()
.return(0)
_tmain endp
end _tstart The 4 dynamic versions: A(32), W(32), A(64), and W(64)
The 4 static versions:
Most API calls are technically macros in the same way as the |
Beta Was this translation helpful? Give feedback.
-
There's also a LINK section in the sample directory which illustrate how the naming convention works. If no entry point is set (normally by using Console example: include stdio.inc
include stdlib.inc
include winnt.inc
extern __ImageBase:IMAGE_DOS_HEADER ; created by LINK
.code
main proc
printf("Address of __ImageBase:\t%p\n", &__ImageBase)
printf("Address of main:\t%p\n", &main)
lea rdx,__ImageBase
mov eax,__ImageBase.e_lfanew
mov eax,[rdx+rax].IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint
add rdx,rax
printf("Address Of EntryPoint:\t%p\n", rdx)
.return(0)
main endp
mainCRTStartup proc
exit(main())
mainCRTStartup endp
end asmc -win64 -D_MSVCRT $*.asm
link /map /libpath:%AsmcDir%\lib\x64 /machine:x64 /subsystem:console test.obj GUI example: wWinMain endp
wWinMainCRTStartup proc
ExitProcess(wWinMain(GetModuleHandle(0), 0, 0, SW_SHOWDEFAULT))
wWinMainCRTStartup endp
end asmc -win64 -ws -D_MSVCRT $*.asm
link /map /libpath:%AsmcDir%\lib\x64 /machine:x64 test.obj If you remove the entry: if 0
wWinMainCRTStartup proc
...
wWinMainCRTStartup endp
endif
If you change
So in addition to the fixed entry names LINK uses |
Beta Was this translation helpful? Give feedback.
-
Thanks for the links and further explanation - i´m going to give it a try. |
Beta Was this translation helpful? Give feedback.
-
I stumbled over yet another linking problem: there is a third party 32 bit DLL i want to use. I don´t have a .lib file and this DLL exports undecorated procedure names, the calling convention is stdcall. Using these names in a .def file for creating a .lib file doesn´t work, the linker keeps complaining of unresolved externals.
Commandline switch /zze doesn´t help, /zt0|1|2 can make the linker actually expect "DLLFUNCTION", but then all other procedure names are undecorated too and lead to "unresolved externals"... "DLLFUNCTION proto basic:dword" works, but only for procedures with one parameter, because this calling convention expects undecorated names, unfortunately it also reverses parameter order. Adding "C" works as well, but then i mess up the stack. So how can i make this work? Is there a directive i can add to "proto", which leaves stdcall calling convention but without expecting decorated names. I know that every unresolved proto is seen as extern(def), is it possible to individually influence how it is created (undecorated in this case), or can i define it myself somehow? |
Beta Was this translation helpful? Give feedback.
-
There's different logic creating private functions in system libraries . These functions are typically called by compilers and libraries associated with a specific tool chain. VS will normally use C decoration with SYSCALL calling convention (to prevent people like you from using them :). Example: __int64 square(__int64 num) {
return(num * num);
} if you compile this (using Compiler Explorer) with x86 MSVC it will produce this code: mov ecx, DWORD PTR _num$[esp]
mov eax, DWORD PTR _num$[esp-4]
push ecx
push eax
push ecx
push eax
call __allmul
ret 0 So arguments are pushed left-to-right with no stack adjustment after the call (STDCALL/PASCAL) with a C decorated function name ( When you build a static library (some of) these functions needs to be added for the tool-chain you plan on using. The __llmul:: ; PellesC
_allmul::
push ebx
mov eax,4[esp+4]
mov edx,4[esp+8]
mov ebx,4[esp+12]
mov ecx,4[esp+16]
call _U8M
pop ebx
ret 16 PellesC uses If you plan on using them (not recommended as the may change or become obsolete with newer versions) they should be proto typed as C with no arguments and called manually (CALL, not INVOKE). |
Beta Was this translation helpful? Give feedback.
-
So "proto c" does the trick, except for the stack beeing wrong, if i keep implementing "invoke". Coding without invoke will be cumbersome, so i tried adjusting the stack by adding "sub esp, ..." to compensate for "add esp, ..." after invoke. Counting parameters and adjusting the stack afterwards seems easier than dropping invoke, it comes at the price of two useless instructions (add esp, ... followed by sub esp, ...), but it works! The best solution would be getting the assembler to omit adding "add esp, ..." after invoke. maybe "proto nodec ..." or something like that |
Beta Was this translation helpful? Give feedback.
-
As you need the proto to resolve the import it's difficult to get around without using a pointer. There's a switch ( include stdio.inc
include tchar.inc
_allmul proto stdcall :int64_t, :int64_t
.code
_tmain proc
_tprintf("3 * 2 = %d\n", _allmul(3, 2))
.return(0)
_tmain endp
end _tstart Using a pointer: include stdio.inc
include stdlib.inc
include tchar.inc
type typedef proto stdcall :int64_t, :int64_t
.code
_tmain proc
.new mymul:ptr type = &_allmul
_tprintf("3 * 2 = %d\n", mymul(3, 2))
.return(0)
_tmain endp
end _tstart You could also use a macro to convert from C to STDCALL cstd macro name, args:vararg
local def, type
... create type from args..
lea eax,name
assume eax:ptr type
eax(args)
assume eax:nothing
retm<eax>
endm
...
_tprintf("3 * 2 = %d\n", cstd(_allmul, 0, 3, 0, 2)) |
Beta Was this translation helpful? Give feedback.
-
This one seems to work, at least for static library functions. include stdio.inc
include stdlib.inc
include tchar.inc
cstd macro name, args:vararg
local def, type
def CatStr <type typedef proto stdcall>
for x,<args>
def CatStr def, <, :ptr>
endm
def
lea eax,name
assume eax:ptr type
eax(args)
assume eax:nothing
retm<eax>
endm
.code
_tmain proc
_tprintf("3 * 2 = %d\n", cstd(_allmul, 3, 0, 2, 0))
.return(0)
_tmain endp
end _tstart |
Beta Was this translation helpful? Give feedback.
-
cstd throws an error 2008, but i can get it working by coding, what the macro does, by hand - works with dynamic libraries (my dll) as well. So i have two ways to go: correct the stack or call via pointer - thanks! |
Beta Was this translation helpful? Give feedback.
-
Well, Technically |
Beta Was this translation helpful? Give feedback.
LINKW is a fork of JWLINK, which in turn is a fork of the Open Watcom linker WLINK.
I added a few changes to the 64 bit section to make it more compatible with Visual Studio (mostly for creating libraries), and some command line options (like wildcards).
However, newer version of VS (2019+) added some changes to the import library format so LIBW is not compatible with these changes. It works for static libraries so LIBC is built using LIBW, but the import libraries are built using LIB to enable debugging using VS.
I haven't really looked into to it yet but I guess it's a trivial issue to fix as LINKW works fine with the import created by LIB and VS works fine with the libraries created by…