I have a function "bob" written in assembler (nasm), which makes use of functions in kernel32.dll. And I have a program in FreePascal, that calls "bob".
I use nasm with:
nasm -fwin32 bob.asm
In FreePascal I declare:
{$link bob.obj}
function bob(s:pchar):longint; stdcall; external name 'bob';
But I get an error when I compile with fpc, telling it doesn't find GetStdHandle and WriteConsoleA (without @n suffix), which are declared extern in bob.asm. I would like to tell fpc to look for them in kernel32.dll, or in an adequate import library.
However, when I use the same function in pure assembly program, it works fine with nasm and golink. And when I don't call DLL functions, I can link with FreePascal with no trouble.
How can I link kernel32 functions with FreePascal, so that assembly functions "see" them ?
Given by BeniBela. I change names so that things are easy to follow.
program dlltest;
function WindowsGetStdHandle(n: longint): longint; stdcall;
external 'kernel32.dll' name 'GetStdHandle';
{$asmmode intel}
procedure WrapperGetStdHandle; assembler; public name 'AliasGetStdHandle';
asm
jmp WindowsGetStdHandle
end;
{$link myget.obj}
function AsmGetStdHandle(n: longint): longint; stdcall;
external name 'gethandle';
const STDOUT = -11;
begin
writeln(AsmGetStdHandle(STDOUT));
writeln(WindowsGetStdHandle(STDOUT));
end.
With this in assembly, in myget.asm:
section .text
extern AliasGetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call AliasGetStdHandle
ret 4
WindowsGetStdHandle is another name for GetStdHandle in kernel32.dll.
WrapperGetStdHandle only jump to the preceding, it's here for the alias or public name capability : we give it the name AliasGetStdHandle for external objects. This is the important part, the function get visible to the assembly program.
AsmGetStdHandle is the name in FreePascal of the assembly function gethandle. It calls WrapperStdHandle (nicknamed AliasGetStdHandle), which jumps to WindowsGetStdHandle, the DLL function.
And we are done, now the assembly program can be linked, without changing anything in it. All the renaming machinery is done in the pascal program calling it.
The only drawback: the need for a wrapper function, but it's not overpriced for a fine control of names.
If kernel32.dll is not specified in declaration of WindowsGetStdHandle, but with {$linklib kernel32}, then the symbol gets visible in object files linked in the pascal program. However, it seems the $linklib directive alone is not enough, one still has to declare in pascal some function refering to it
program dlltest;
{$linklib kernel32}
function WindowsGetStdHandle(n: longint): longint; stdcall;
external name 'GetStdHandle';
{$link myget.obj}
function AsmGetStdHandle(n: longint): longint; stdcall;
external name 'gethandle';
const STDOUT = -11;
begin
writeln(AsmGetStdHandle(STDOUT));
writeln(WindowsGetStdHandle(STDOUT));
end.
With the following assembly program. AliasGetStdHandle is replaced with GetStdHandle, which now points directly to kernel32 function.
section .text
extern GetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call GetStdHandle
ret 4
But this only works when using the external linker (gnu ld), with command
fpc -Xe dlltest.pas
When omitting opton '-Xe', fpc gives the following error
Free Pascal Compiler version 2.6.0 [2011/12/25] for i386
Copyright (c) 1993-2011 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling dlltest.pas
Linking dlltest.exe
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_dir_kernel32.dll
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_names_kernel32.dll
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_fixup_kernel32.dll
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_dll_kernel32.dll
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_names_end_kernel32.dll
dlltest.pas(17,1) Error: Asm: Duplicate label __imp_fixup_end_kernel32.dll
dlltest.pas(17,1) Fatal: There were 6 errors compiling module, stopping
Fatal: Compilation aborted
I do not know how to fix the linking issue directly, but you could declare public wrapper functions that export these functions from the Pascal source.
E.g.:
{$ASMMODE INTEL}
procedure WrapperGetStdHandle; assembler; public; alias: '_GetStdHandle@4';
asm jmp GetStdHandle end;
procedure WrapperWriteConsoleA; assembler; public; alias: '_WriteConsoleA@20';
asm jmp WriteConsoleA end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With