如何与调用DLL的NASM程序FreePascal链接? 问题
我有一个用汇编语言(nasm)编写的函数“bob”,它利用了kernel32.dll中的函数。我有一个用FreePascal编写的程序,叫做“bob” 我将nasm用于:如何与调用DLL的NASM程序FreePascal链接? 问题,dll,nasm,freepascal,Dll,Nasm,Freepascal,我有一个用汇编语言(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编译时,我得到一个错误,告诉它找不到GetStdHandle和WriteC
nasm -fwin32 bob.asm
在FreePascal中,我声明:
{$link bob.obj}
function bob(s:pchar):longint; stdcall; external name 'bob';
但是当我用fpc编译时,我得到一个错误,告诉它找不到GetStdHandle和WriteConsoleA(没有@n后缀),它们在bob.asm中声明为extern。我想告诉fpc在kernel32.dll或适当的导入库中查找它们
然而,当我在纯汇编程序中使用相同的函数时,它在nasm和golink中运行良好。当我不调用DLL函数时,我可以毫无困难地链接到FreePascal
如何将kernel32函数与FreePascal链接,以便汇编函数“看到”它们
解决办法 由BeniBela给出。我改名字,这样事情就容易理解了
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仅跳到前面,它是用于or功能的:我们为外部对象命名为AliasGetStdHandle。这是一个重要的部分,函数对汇编程序是可见的
AsmGetStdHandle是汇编函数gethandle在FreePascal中的名称。它调用WrapperStdHandle(昵称为AliasGetStdHandle),它跳转到WindowsGetStdHandle,即DLL函数
section .text
extern GetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call GetStdHandle
ret 4
我们完成了,现在汇编程序可以链接了,而不需要改变其中的任何内容。所有重命名机器都是在调用它的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,它现在直接指向内核32函数
section .text
extern GetStdHandle
global gethandle
gethandle:
mov eax, [esp+4]
push eax
call GetStdHandle
ret 4
但这仅在使用外部链接器(GNULD)时起作用,命令为
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
我怀疑有一些导入库由nasm自动链接,以便与nasm代码一起使用,可能您也需要链接该库中的相关存根 修订: 这可能是智能链接的问题。如上所述,FPC动态生成导入存根,但仅在需要时生成。由于Windows单元(包含所有核心WINAPI调用)非常大,因此会为其激活智能链接(仅添加您使用的内容)。(还有其他原因) 源自NASM的obj不在FPC的控制范围内,因此不会为其生成相关功能 如果是这样的话,BeniBela的代码可能会起作用,因为它强制引用FPC代码,并在符号中链接。但这只是猜测,可能是装饰的原因,也可能是主下划线的原因 测试很简单,使用pascal代码中的函数,而不使用Benibela的声明
顺便说一句,FPC的默认值不是stdcall,因此BenBela的函数可能需要一个stdcall修饰符我不知道如何直接修复链接问题,但您可以声明从Pascal源导出这些函数的公共包装函数 例如:
Nasm不是链接器。我与nasm一起使用的链接器Golink可以直接读取DLL文件,而无需导入库(命令为:Golink/console bob.obj kernel32.DLL)。所以,我的问题是,向freepascal显示我的链接对象文件对dll有外部依赖性(golink会自动看到),并解决这些依赖性。这就是我的观点。FPC的内部链接器也可以做到这一点,但可能只对其本机代码,而不是外部的.objs。我以前试过,它不起作用,除非使用public再次导出函数。在导入的函数本身上设置public也不起作用。我没有找到一种方法来指定链接器的内容,以强制将对象文件链接到给定的库。我不太清楚它是否需要导入库,或者它是否可以将ld直接用于dll,无论如何,它似乎不起作用(可能我错过了一个决定性的命令行选项或其他内容)。@edit:因为您从我的示例中删除了别名。如果添加'alias:'GetStdHandle';它应该会起作用。(虽然我用过_GetStdHandle@4在pascal和assembly中。您也可以同时使用这两个别名)愚蠢的我!我不太理解这个“别名”的东西,但现在我看到它对您的解决方案至关重要。我现在就修改这个,我修改了我的答案。试图对贝尼贝拉的发现发表评论。但这似乎与进口LIB有关。显然,FPC链接器只为FPC拥有的符号生成那些存根。@Marco看起来你是对的:单独使用$linklib时,它不起作用,但如果我在Pascal中声明对GetStdHandle的引用,我可以在汇编中使用该符号。我想知道是否可以直接使用Windows单元,但我找不到正确的名称(我想是像_Windows$$\u GetStdHandle这样的名称,但我会遇到奇怪的错误,其中$$被替换为路径)。另请参见名称损坏。现在,我正确地使用了alias指令,但我不太理解它。我将再等一段时间,看看是否有人提出了不涉及包装器的解决方案,但这个已经很好了。谢谢!顺便说一下,根据FP文档,“alias”已被弃用,应替换为“public name”(参见问题中的链接)。这并没有减损你答案的价值。我甚至没有意识到这一点(别名不赞成,所以不要反对BeniBela;-)顺便说一句:这些不是stdcall吗