转发DLL中的数据

Mar*_*wis 5 dll linker

我需要将一组符号从一个DLL转发到另一个DLL(如果你想知道的话,支持一些版本控制方案,PEP 384).它适用于各种功能; 我写了一个模块定义文件,说

LIBRARY "python3"
EXPORTS
  PyArg_Parse=python32.PyArg_Parse
  PyArg_ParseTuple=python32.PyArg_ParseTuple
  PyArg_ParseTupleAndKeywords=python32.PyArg_ParseTupleAndKeywords
[...]
Run Code Online (Sandbox Code Playgroud)

但是,数据失败了.如果我说

PyBaseObject_Type=python32.PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)

然后链接器抱怨PyBaseObject_Type是一个未解析的符号,即使它实际上是从python32.dll导出的.看一下导入库,我注意到,对于数据,只有_imp__符号,所以我试过了

PyBaseObject_Type=python32._imp__PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)

链接器现在实际上创建了一个DLL,但是,在此DLL中,转发转到_imp__符号,然后在运行时无法解析.我也尝试将DATA放入线路(有或没有_imp__); 这没有什么区别.

IIUC,转发数据应该可以正常工作,因为数据是__declspec(dllimport)针对DLL的任何导入器声明的,因此编译器应该正确解释引用.

那么:我如何生成一个执行数据转发的DLL?

Ole*_*leg 6

在我看来,解决方案是在从主DLL(保存数据的DLL)导出数据期间使用DATA.

要重现我的意思,你可以创建一个具有DllDataForward.c的项目:

#include <Windows.h>

EXTERN_C __declspec(dllexport) int myData = 5;

#ifndef _DEBUG
EXTERN_C BOOL WINAPI _DllMainCRTStartup (HINSTANCE hinstDLL, DWORD fdwReason,
                                         LPVOID lpvReserved)
#else
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#endif
{
    if (fdwReason == DLL_PROCESS_ATTACH)
        DisableThreadLibraryCalls(hinstDLL);

    return TRUE;
    UNREFERENCED_PARAMETER (lpvReserved);
}

EXTERN_C __declspec(dllexport) BOOL WINAPI MyFunc()
{
    return TRUE;
}
Run Code Online (Sandbox Code Playgroud)

和DllDataForward.def:

LIBRARY "DllDataForward"
EXPORTS
    myData
    MyFunc
Run Code Online (Sandbox Code Playgroud)

通常一个将使用"myData DATA"而不是"myData".

然后你可以创建一个ForwardingDll.c:

#include <Windows.h>

#ifndef _DEBUG
EXTERN_C BOOL WINAPI _DllMainCRTStartup (HINSTANCE hinstDLL, DWORD fdwReason,
                                         LPVOID lpvReserved)
#else
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#endif
{
    if (fdwReason == DLL_PROCESS_ATTACH)
        DisableThreadLibraryCalls(hinstDLL);

    return TRUE;
    UNREFERENCED_PARAMETER (lpvReserved);
}
Run Code Online (Sandbox Code Playgroud)

与ForwardingDll.def:

LIBRARY "ForwardingDll" 
EXPORTS
    myNewData=DllDataForward.myData DATA
    MyNewFunc=DllDataForward.MyFunc
Run Code Online (Sandbox Code Playgroud)

您应该在构建ForwardingDll.dll期间包含在编译DllDataForward期间创建的导入库DllDataForward.lib作为链接器的输入.这样的导入库可以成功使用,您将收到ForwardingDll.dll.

dumpbin.exe ForwardingDll.dll /EXPORTS
Run Code Online (Sandbox Code Playgroud)

产生作为输出

...
    ordinal hint RVA      name

          1    0          MyNewFunc (forwarded to DllDataForward.MyFunc)
          2    1          myNewData (forwarded to DllDataForward.myData)
...
Run Code Online (Sandbox Code Playgroud)

使用DllDataForward.lib构建的简单测试应用程序只有源test.c:

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>

EXTERN_C __declspec(dllimport) int myNewData;
EXTERN_C __declspec(dllimport) BOOL WINAPI MyNewFunc();

int main()
{
    BOOL isSuccess = MyNewFunc();
    int i=myNewData;
    _tprintf (TEXT("i=%d\nisSuccess=%s\n"),
              i, isSuccess? TEXT("TRUE"): TEXT("FALSE"));
}
Run Code Online (Sandbox Code Playgroud)

产生作为输出

i=5
isSuccess=TRUE
Run Code Online (Sandbox Code Playgroud)

更新:我想添加更多信息为什么在DEF文件中使用"myData DATA"而不是"myData"做一个技巧以及如何使用我建议的现有DLL如python32.dll的技巧而不做任何更改在python32.dll中,没有重新编译它.我将展示原始的python32.lib错过了所有数据变量的导出PyBaseObject_Type.我将展示如何创建一个额外的python32.lib,它具有我们需要的数据符号.

首先,我希望在DEF文件中从"myData DATA"更改为"myData"之后,清除导入库中的所需更改.首先让我们使用具有"myData DATA"的DEF文件编译DllDataForward.dll,然后查看导入库DllDataForward.LIB的内部:

dumpbin.exe DllDataForward.lib /all >%TEMP%\DllDataForward-lib.txt
notepad %TEMP%\DllDataForward-lib.txt
Run Code Online (Sandbox Code Playgroud)

我们将看到lib有6个公共符号:

  224 __IMPORT_DESCRIPTOR_DllDataForward
  46A __NULL_IMPORT_DESCRIPTOR
  5A8 DllDataForward_NULL_THUNK_DATA
  776 __imp__myData
  708 _MyFunc@0
  708 __imp__MyFunc@0
Run Code Online (Sandbox Code Playgroud)

接下来将DEF文件从"myData DATA"更改为"myData",创建dll和导入库并再次查看其内部.我们将看到导入库现在有7个(!!!)而不是6个公共符号:

  23A __IMPORT_DESCRIPTOR_DllDataForward
  480 __NULL_IMPORT_DESCRIPTOR
  5BE DllDataForward_NULL_THUNK_DATA
  78C __imp__myData
  78C _myData
  71E _MyFunc@0
  71E __imp__MyFunc@0
Run Code Online (Sandbox Code Playgroud)

因此,我们在使用具有"myData DATA"的DEF文件时遇到问题,因为创建的导入库不包含公共符号_myData.

我们可以使用具有"myData DATA" 的正确 DLL,并创建另一个_myData手动导出的第二个导入库.我们不会对DllDataForward.dll进行任何更改,只需手动创建和使用其他库.

为此,我们转储DllDataForward.dll的导出dumpbin.exe DllDataForward.dll /exports.我们会看到:

...
    ordinal hint RVA      name

          1    0 00001020 MyFunc = _MyFunc@0
          2    1 00003000 myData = _myData
...
Run Code Online (Sandbox Code Playgroud)

现在我们创建一个新的DllDataForward.def在其他目录下的文件仅在输出基础dumpbin.exe DllDataForward.dll /exports:

LIBRARY "DllDataForward"
EXPORTS
    myData = _myData
Run Code Online (Sandbox Code Playgroud)

接下来使用命令

lib.exe /DEF:DllDataForward.def /OUT:DllDataForward.lib /MACHINE:X86
Run Code Online (Sandbox Code Playgroud)

我们创建了第二个DllDataForward.lib(在另一个目录中创建了原始文件DllDataForward.lib).现在我们可以使用两个 编译ForwardingDll.dll DllDataForward.lib并接收我们需要的DLL.Test.exe将显示批准工作.

完全以同样的方式检查当前版本3.2a3中的python32.lib:

dumpbin.exe "C:\Program Files\Python32\libs\python32.lib" /all >python32-lib.txt
notepad python32-lib.txt
Run Code Online (Sandbox Code Playgroud)

我们将找到以下行(约在文件的开头)

1957 public symbols
…
1BCCC _PyArg_Parse
1BCCC __imp__PyArg_Parse
…
1BFF6 __imp__PyBaseObject_Type
…
Run Code Online (Sandbox Code Playgroud)

我们也可以验证

dumpbin C:\Windows\system32\python32.dll /exports >%TEMP%\python32-exports.txt
notepad %TEMP%\python32-exports.txt
Run Code Online (Sandbox Code Playgroud)

符号PyBaseObject_Type将导出为

 14    D 001DD5D0 PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)

所以我们可以从python32.def文件创建额外的python32.lib

LIBRARY "python32"
EXPORTS
    PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)

运用

lib /DEF:python32.def /OUT:python32.lib /MACHINE:X86
Run Code Online (Sandbox Code Playgroud)

现在您可以定义dll的DEF

LIBRARY "python3"
EXPORTS
  PyArg_Parse=python32.PyArg_Parse
  PyArg_ParseTuple=python32.PyArg_ParseTuple
  PyArg_ParseTupleAndKeywords=python32.PyArg_ParseTupleAndKeywords
  PyBaseObject_Type=python32.PyBaseObject_Type DATA
Run Code Online (Sandbox Code Playgroud)

就像你想要的,可是我们将使用两个 "C:\ Program Files文件\ Python32 \库\ python32.lib",而我们在连接过程中产生的小秒针python32.lib.

我自己不使用python而且不​​知道它的大小PyBaseObject_Type,但如果我将其声明为int

EXTERN_C __declspec(dllimport) int PyBaseObject_Type;
Run Code Online (Sandbox Code Playgroud)

我可以验证第一部分PyBaseObject_Type是1.它有效!

对于那些读完所有答案直到这个地方的所有人,我们很抱歉.