簡體   English   中英

如何包裝要在 Wine 中使用的 Linux 庫? 我不斷收到 BAD_IMAGE_FORMAT

[英]How to wrap a Linux library to be used in Wine? I keep getting BAD_IMAGE_FORMAT

我有一個可以通過插件擴展的僅限 Windows 的游戲,以及我想使用的 Linux 庫。 該應用程序(Unity 游戲)在 Wine/Proton 下運行良好。 我發現 Winelib 可以做到這一點,並且我遵循了用戶指南,特別是第 5 節,其中提到了我的確切用例。

經過一些嘗試(比如從釀酒師中刪除 --single-target arg),我到了 Proton 調試日志一直顯示 c000007b 似乎是 STATUS_BAD_IMAGE_FORMAT 的地步。

請注意,我重命名了 Linux 庫(並與之鏈接),以避免它與我的包裝器之間的潛在沖突。

我只有一個 64 位版本的庫,它是使用 cdecl 調用約定從 C# 代碼調用的。 這是我迄今為止嘗試過的(以及這些的組合):

  • 添加了帶有內容的 a.spec 文件(首先沒有 -arch 並且具有不同的序數):
1 cdecl -arch=x86_64 LibraryFunc (long ptr ptr) LibraryFuncWine
  • 添加了庫的 header 和 a.c 文件:
#include "library_header.h"
#include <windef.h> /* Part of the Wine header files */

enum ELibResult WINAPI LibraryFuncWine(Version version, struct CreateParams* params, struct ICore** result)
{
    enum ELibResult ret = LibraryFunc(version, params, result);

    return ret;
}
  • 使用釀酒師作為winemaker --nosource-fix --dll --nomfc -I. -L. -llinux_library. winemaker --nosource-fix --dll --nomfc -I. -L. -llinux_library. 然后make
  • 將.dll.so文件復制到游戲各處
  • 將 .dll.so 文件復制到 steamapps/common/Proton 5.0/dist/lib64/wine/ 並將本機庫復制到更高級別(lib64/)並刪除其他庫
  • 還嘗試復制到 lib/ 而不是 lib64/
  • 為文件添加了 dll 覆蓋並將其設置為內置
  • 從 makefile 中刪除了引用的 DLL(odbc32、ole32、oleaut32、winspool、odbccp32)和庫(uuid)
  • --mno-cygwin添加到編譯器標志
  • -m64-fPIC添加到編譯器/鏈接器標志(基於Wine 規范文件
  • 我也試過制作一個.def文件並使用它
  • 添加 --nomsvcrt 參數並再次使用--nomsvcrt並運行make (header 文件包括 string.h)

從質子日志(+模塊,其他人沒有為我提供更多信息):

00dc:trace:module:load_dll looking for L"Z:\\D\\a\\library\\path\\library_name" in L"Z:\\D\\gamepath;C:\\windows\\system32;C:\\windows\\system;C:\\windows;C:\\Program Files (x86)\\Steam;.;C:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem;C:\\windows\\system32\\WindowsPowershell\\v1.0"
00dc:trace:module:get_load_order looking for L"Z:\\D\\a\\library\\path\\library_name.dll"
00dc:trace:module:get_load_order_value got standard key b for L"library_name"
00dc:trace:module:load_builtin_dll Trying built-in L"library_name.dll"
00dc:trace:module:load_so_dll loading L"\\??\\Z:\\D\\a\\library\\path\\library_name.dll" from so lib "/D/Games/SteamLibrary/steamapps/common/Proton 5.0/dist/bin/../lib64/wine/library_name.dll.so"
00dc:warn:module:load_dll Failed to load module L"Z:\\D\\a\\library\\path\\library_name"; status=c000007b

使用和不使用.dll 並以 lib 開頭(library_name.dll、liblibrary_name 和 liblibrary_name.dll)重復相同的操作。

除了該錯誤代碼之外,我無法獲得更多關於究竟出了什么問題的日志。

在 C# 端(由 Unity 在 Proton 中運行)會導致 DllNotFoundException。

Wine 版本 (winebuild, winegcc): 5.9 (staging) - gcc 9.0.1

質子版本:5.0 - wine-5.0-603-g068dee4

可能有一個僅適用於您的二進制文件的解決方案。 .so使用 RPC。

但是,由於許多/大多數 linux 庫都有源代碼,那么具體的庫是什么[沒有]? 是否有類似的替代庫? 如果您足夠努力,可能會有二進制庫的源代碼。

但是,我假設必須使用二進制 linux 庫。

但是,這可能涉及比您願意做的更多的工作。 那么,你有多想要這個? ;-)

這是用於生產還是僅供個人使用? 我假設只是供個人使用,因為您正試圖讓 WinX 游戲在 wine 下工作。

.so就公共 API 函數[您的 wine 程序需要調用]的數量而言有多大? 涉及多少種不同的結構?

您可能需要為每個 API 調用和結構創建粘合/接口例程。

基本方法是使用[某種] RPC [遠程過程調用]機制(例如) https://en.wikipedia.org/wiki/Remote_procedure_call

您創建了一個 linux 服務器,其中包含所需的 [僅限 linux] 庫。 您編寫將 RPC 調用轉換為庫的 API 調用的包裝例程。

在游戲中,您的插件會發出 RPC 調用,然后發送到服務器,服務器進行處理,然后發回結果。

有一些工具可以幫助您(例如rpcgen

通常,RPC 是通過網絡/套接字連接完成的。 出於您的目的,這可以通過 localhost 或使用AF_UNIX連接。 也許這對您的目的來說已經足夠快了。

否則,您可能必須建立一個共享的 memory 緩沖池並將其添加為 RPC 調用的附件。


更新:

謝謝,但你能提供更多關於為什么使用 Winelib 不可行的信息嗎? 在指南中,我認為我可以將 Linux 庫鏈接到我的庫。

可以編寫一些膠水函數。 這樣做可能會有問題。 但是,根據我在 Discord SDK 中找到的內容,您也許可以繞過 [all] 。 見下文。


ABI 差異:在 WinX 中,前四個 arguments 在 regs 中傳遞,在 linux 中,前六個 arguments 在 regs 中傳遞。 寄存器不同 可以通過建立新堆棧幀並將值移動到 linux 的正確寄存器的“thunk”例程來處理。 請參閱: https://en.wikipedia.org/wiki/X86_calling_conventions

但是,至少在我的機器上, wine最終會轉到/usr/bin/wine32 ,這是一個 32 位可執行文件。 但是,您的 linux 庫是 64 位的。 這個問題不容易解決。 請參閱: 是否可以在 64 位 Linux 的同一可執行文件中同時使用 64 位和 32 位指令? 就個人而言,如果我必須這樣做,我會 go RPC 路由。


該庫導出 2 個函數,我只對 1 個感興趣,該功能的 rest 是通過 function 指針(我不確定這些是否適用於 wine,但還沒有)。 該庫實際上是 Discord 的游戲 SDK 所以沒有替代品,但這只是一個愛好。

我剛剛從網站上下載discord_game_sdk.zip並解壓縮。 它有源代碼示例程序。 並且,必要的.h文件。

有一個lib/x86子目錄,其中包含: discord_game_sdk.dlldiscord_game_sdk.dll.lib ,它們是 32 位 PE 格式文件。 而且,還有一個lib/x86_64子目錄 [其中有一個.so ]

那么,代替 linux .so ,您可以直接鏈接到那些 PE 格式文件嗎? (例如)它們可能可以使用LoadLibrary加載


如果沒有直接的方法,我可以使用 sockets (但是創建 unix 套接字不會有同樣的問題嗎?我當然可以使用 localhost)。

然后,考慮這是一個后備 position。

對 localhost 的PF_INET套接字調用非常快,並且 [通過一些“技巧”] 您可以在您的插件 [在wine下] 和一個服務器程序 [您創建的] 之間建立共享的 memory 空間,該服務器程序具有 linux .so鏈接到它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM