使用 ld.exe 链接到 kernel32.dll

问题描述

我使用以下命令组装了我的汇编程序:

nasm -f win64 -o test.obj test.asm

test.asm 包含一些调用 Win32 函数函数,如 GetStdHandle、HeapAlloc 等

通常,我会像这样链接我的装配项目之一:

ld -LC:/Windows/System32 -lkernel32 -e main -o test.exe test.obj

它会按预期生成一个 test.exe 文件

但是,一旦我开始使用 Win32 函数利用堆,例如 HeapAlloc、HeapFree、GetProcessHeap,我在链接时会收到以下错误

C:\msys64\mingw64\bin\ld.exe: ertr000016.o:(.rdata+0x0): undefined reference to '_pei386_runtime_relocator'

然后我可以假设它与链接的 MinGW 文件有关。所以我尝试在没有它们的情况下编译它:

ld -nostdlib -nostartfiles -LC:/Windows/System32 -lkernel32 -e main -o test.exe test.obj

并得到以下错误

C:\msys64\mingw64\bin\ld.exe: cannot find -lkernel32

所以,我的问题是:我应该如何使用 ld.exe(不包括 startfiles 或 stdlib)链接到 kernel32,因为无论我尝试什么,我都无法让它工作。

感谢您的帮助!

(我想要一个不只是告诉我使用 GoLink 的答案,除非这是唯一可能的解决方案)。

解决方法

我已经意识到答案现在就在评论中,但为了清楚起见,我会在此处发布所有步骤:

  1. 为要使用的 DLL 创建一个 .def 文件。可以这样做:
LIBRARY [name of the dll]
EXPORTS
    [required export #1]
    [required export #2]
    [etc.]
  1. 使用 dlltool.exe.def 文件创建存档库文件:
dlltool -d "[path to the .def file]" -l "[path to output file C,defined below]"

在此命令中,ClibXXX.a,其中 XXX 更改为不同的名称(最好是不带扩展名的原始 dll 的名称)。

  1. 不要使用 ld.exe,而是使用内置于 gcc.exe 中的链接器。此外,更改包含 -L 存档文件的目录的 libXXX.a 之后的目录,并更改 XXX 中已替换的 libXXX.a 后面的 dll 名称}.在原始问题的上下文中,这些步骤将是:
[Kernel32.def file]

LIBRARY KERNEL32.DLL
EXPORTS
    HeapAlloc
    HeapFree
    [...]
dlltool -d "kernel32.def" -l "libkernel32.a"
gcc -LC:/path/to/this/directory/ -lkernel32 -e main -o test.exe test.obj
,
... -LC:/Windows/System32 -lkernel32 ...

这绝对是错误的:-lkernel32 不会搜索名为 kernel32.dll 的 DLL 文件,而是搜索名为 libkernel32.a 的库文件。

... 并且 libkernel32.a 肯定不在 C:/Windows/System32 中。

我将如何使用 dlltool.exe 生成我自己的 libkernel32.a

对于 64 位 Windows,这比对于 32 位 Windows 更容易(因为在 32 位 Windows 中,函数在 DLL 和目标文件中的命名不同)。

首先,您创建一个如下所示的定义文件 (.def):

LIBRARY KERNEL32.DLL
EXPORTS
    HeapAlloc
    HeapFree
    GetProcessHeap
    CreateFileA
    ReadFile

有第三方工具,可以读取.dll文件,生成包含DLL所有函数的.def文件;但是,您可以手动执行此操作,并且只添加您需要的功能。

然后运行以下命令行:

dlltool -d kernel32.def -l libkernel32.a

很遗憾,我无法告诉您这是否解决了您的 _pei386_runtime_relocator 问题。

编辑

undefined reference to 'SetFilePointer'

SetFilePointer 也是 kernel32.dll 中定义的函数。您是否将 SetFilePointer 添加到 .def 文件中?

LIBRARY KERNEL32.DLL
EXPORTS
    HeapAlloc
    HeapFree
    GetProcessHeap
    CreateFileA
    ReadFile
    SetFilePointer     <-- HERE?

我正在使用以下命令进行链接:

可能还有第二个问题:

某些版本的 gcc 需要特定顺序的命令行参数。或许 ld 也是如此。

尝试将 -L-l 参数移到行尾:

ld ... -o test.exe test.o -L... -lkernel32