问题
我有一个用汇编程序(nasm)编写的函数“bob”,它利用了 kernel32.dll 中的函数。我在 FreePascal 中有一个名为“bob”的程序。
我将 nasm 用于:
nasm -fwin32 bob.asm
在 FreePascal 中,我声明:
{$link bob.obj}
function bob(s:pchar):longint; stdcall; external name 'bob';
但是当我使用 fpc 编译时出现错误,告诉它没有找到在 bob.asm 中声明为 extern 的 GetStdHandle 和 WriteConsoleA(没有 @n 后缀)。我想告诉 fpc 在 kernel32.dll 或适当的导入库中查找它们。
但是,当我在纯汇编程序中使用相同的函数时,它可以很好地与 nasm 和 golink 一起使用。当我不调用 DLL 函数时,我可以毫无问题地与 FreePascal 链接。
如何将 kernel32 函数与 FreePascal 链接,以便汇编函数“看到”它们?
一个办法
由贝尼贝拉提供。我更改名称以便事情易于理解。
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.
在汇编中,在 myget.asm 中:
section .text
extern AliasGetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call AliasGetStdHandle
ret 4
WindowsGetStdHandle是 kernel32.dll 中 GetStdHandle 的另一个名称。
WrapperGetStdHandle只跳到前面,这里是为别名或公共名称能力:我们为外部对象命名为 AliasGetStdHandle。这是重要的部分,该功能对汇编程序可见。
AsmGetStdHandle是汇编函数gethandle在 FreePascal 中的名称。它调用 WrapperStdHandle(昵称 AliasGetStdHandle),它跳转到 DLL 函数 WindowsGetStdHandle。
我们完成了,现在可以链接汇编程序,而无需更改其中的任何内容。所有的重命名机制都是在调用它的 pascal 程序中完成的。
唯一的缺点:需要一个包装函数,但对于名称的精细控制来说,它的价格并不高。
另一种解决方案
如果在 WindowsGetStdHandle 的声明中未指定 kernel32.dll,但使用 {$linklib kernel32},则该符号在 pascal 程序中链接的目标文件中可见。但是,似乎仅 $linklib 指令是不够的,仍然需要在 pascal 中声明一些引用它的函数
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.
用下面的汇编程序。AliasGetStdHandle 被 GetStdHandle 取代,它现在直接指向 kernel32 函数。
section .text
extern GetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call GetStdHandle
ret 4
但这仅在使用外部链接器(gnu ld)时有效,带有命令
fpc -Xe dlltest.pas
省略 opton '-Xe' 时,fpc 给出以下错误
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