一次Linux下 .net 調試經歷

背景
Xt160Api, 之前在windows下用.net調用,沒有任何問題。
但是移植到Linux去后,.net程序 調用 init(config_path) 總是報錯 /root/test 找不到 traderApi.ini (/root/test 是程序目錄) 然后退出程序

解決過程:
于是考慮是不是參數傳錯了,但是無論這個參數是什么, 報錯內容始終如此。
甚至某些情況下,比如加了幾句Console.WriteLIne(app_exe_folder) 還會出現段錯誤,這個問題至今也沒想明白。
尊崇愛因斯坦的指導意見: 不要做相同的事情,期望得到不同的結果
用Visual Studio遠程編譯 Linux C++ 程序 調用 init函數 。 發現 confg_path 可以被識別,如果config_path下沒有ini存在,他會報錯沒有在 config_path下找到 traderApi.ini 而不是 .net 那樣永遠顯示: /root/test 下找不到traderApi.ini
這個讓我極度困惑,我甚至嘗試用 unsafe模式,硬編碼字符串,傳入 init的參數, 但是輸出依舊。

我甚至認為這個api收到了 .net 的路徑影響,因為linux調用 .net 形如 dotnet ./MyApp.dll 這個api在查找ini時用的是 dotnet 的路徑,而顯示的時候用的是dll的路徑。(最后證明這個邏輯完全不對) 所以我在 dotnet 的文件夾下添加了 traderApi.ini , 依舊如故。

于是我又轉而認為2點,

  1. api 的指針有問題,可能我的EntryPoint寫錯了?
  2. 虛表有問題,什么地方寫錯了?但是 init 函數是第3個函數,前2個是 析構函數,setCallbak 函數, 之后就是 init 函數

非常疑惑,而且沮喪,覺得很無聊,甚至在想是不是.net core 3.1的bug? 要不要換.net8試試? 搞得我很煩。
但是還是掩蓋煩躁,開始用c++寫 so文件 TestSO.so
如下:
test.cpp:

#include "mylib.h"
#include "XtTraderApi.h"
#include<cstdio>extern "C"
{void MyInit(void* api, const char* path){printf("%s", "start start!!!");auto xt_api = (xti::XtTraderApi*)api;xt_api->init(path);printf("%s", path);printf("ok ok ok\r\n");		//auto xtApi = (xti::XtTraderApi*)api;//xtApi->init(path);}
}

mylib.h

#ifndef MYLIB_H
#define MYLIB_H#ifdef __cplusplus
extern "C" 
{
#endif// 聲明 MyInit 函數void MyInit(void* api, const char* path);#ifdef __cplusplus
}
#endif#endif // MYLIB_H

遠程編譯后,把 so文件送入 /lib64 (映射后實際位置為/usr/lib64)
然后 ldconfig
最后用 ldconfig -p | grep libTest確認生效:
在這里插入圖片描述
接下去先用c++ 程序調用TestSO.so, 傳入 api的地址和config_path,一切正常!
說明so文件運行正確。
接下去就用C#程序調用TestSO.so, 傳入 .net 中根據EntryPoint得到的 api地址,這次在so文件中調用 init函數居然一切正常!!
這樣我們幾乎就確定了那個我們認為最不可能有問題的 虛表 問題了!
但是怎么會?如果虛表有問題,說明函數地址是錯的,調用不應該是直接崩潰,或者輸出的是其他信息,怎么會返回 init函數的錯誤信息呢?
覺得非常不可思議,不可能啊。(但是,就是如此,原因很難想象)

如果虛表有問題,我還是只能從 C++ 是如何調用 api->init 的代碼,反匯編,看看 init 在虛表中的位置。
Visual Studio 支持 Linux 遠程反匯編 nice!
api->init 的匯編如下:

0x0000000000400fc1 e8 8a fe ff ff       callq  0x400e50 <_ZN3xti11XtTraderApi17createXtTraderApiEPKc@plt> 
0x0000000000400fc6 48 89 45 c0          mov    %rax,-0x40(%rbp) 
0x0000000000400fca 48 8b 45 c0          mov    -0x40(%rbp),%rax 
0x0000000000400fce 48 8b 00             mov    (%rax),%rax 
0x0000000000400fd1 48 83 c0 18          add    $0x18,%rax 
0x0000000000400fd1 48 83 c0 18          add    $0x18,%rax 
0x0000000000400fd5 48 8b 10             mov    (%rax),%rdx 
0x0000000000400fd8 48 8b 45 c0          mov    -0x40(%rbp),%rax 
0x0000000000400fdc be 80 7f 40 00       mov    $0x407f80,%esi 
0x0000000000400fe1 48 89 c7             mov    %rax,%rdi 
0x0000000000400fe4 ff d2                callq  *%rdx

注意這兩句不知道為什么被Visual Studio 重復了2行,注意看他們地址是一樣的,說明是一條指令,而不是兩條指令。
而且這條語句極其重要,確定了init函數在虛表的位置。

0x0000000000400fd1 48 83 c0 18          add    $0x18,%rax 
0x0000000000400fd1 48 83 c0 18          add    $0x18,%rax 

神奇的是,deepseek直接把他們正確的識別為了1條語句。下面是他的解答:

This is a more complex snippet of x86-64 assembly code. Let’s break it down step by step:

  1. 0x0000000000400fc1 e8 8a fe ff ff callq 0x400e50 _ZN3xti11XtTraderApi17createXtTraderApiEPKc@plt

Address: 0x0000000000400fc1
Opcode: e8 8a fe ff ff

Instruction: callq 0x400e50

Description: This calls the function
_ZN3xti11XtTraderApi17createXtTraderApiEPKc located at address 0x400e50. The function name is mangled and corresponds to a C++ method
xti::XtTraderApi::createXtTraderApi(char const*). The @plt indicates
that this is a dynamically linked function via the Procedure Linkage
Table (PLT).

Purpose: This is likely creating an instance of the XtTraderApi class.

  1. 0x0000000000400fc6 48 89 45 c0 mov %rax,-0x40(%rbp)

Address: 0x0000000000400fc6

Opcode: 48 89 45 c0

Instruction: mov %rax, -0x40(%rbp)

Description: The return value of the createXtTraderApi function
(stored in rax) is moved into the memory location at -0x40 bytes
offset from the base pointer (rbp). This is likely storing the pointer
to the newly created XtTraderApi object in a local variable.

  1. 0x0000000000400fca 48 8b 45 c0 mov -0x40(%rbp),%rax

Address: 0x0000000000400fca

Opcode: 48 8b 45 c0

Instruction: mov -0x40(%rbp), %rax

Description: The pointer to the XtTraderApi object (stored at
-0x40(%rbp)) is loaded back into the rax register.

  1. 0x0000000000400fce 48 8b 00 mov (%rax),%rax

Address: 0x0000000000400fce

Opcode: 48 8b 00

Instruction: mov (%rax), %rax

Description: This dereferences the pointer in rax (which points to the
XtTraderApi object) and loads the value at that memory location into
rax. In C++ terms, this is likely accessing the vtable (virtual table)
pointer of the XtTraderApi object, which is typically the first member
of an object with virtual methods.

  1. 0x0000000000400fd1 48 83 c0 18 add $0x18,%rax

Address: 0x0000000000400fd1

Opcode: 48 83 c0 18

Instruction: add $0x18, %rax

Description: This adds 0x18 (24 in decimal) to the value in rax. Since
rax currently holds the vtable pointer, this is likely calculating the
address of a specific entry in the vtable. The offset 0x18 suggests
that this is the 4th entry in the vtable (assuming each entry is 8
bytes on a 64-bit system).

  1. 0x0000000000400fd5 48 8b 10 mov (%rax),%rdx

Address: 0x0000000000400fd5

Opcode: 48 8b 10

Instruction: mov (%rax), %rdx

Description: This dereferences the address in rax (which now points to
a specific vtable entry) and loads the value at that memory location
into rdx. This value is likely a function pointer corresponding to a
virtual method in the XtTraderApi class.

  1. 0x0000000000400fd8 48 8b 45 c0 mov -0x40(%rbp),%rax

Address: 0x0000000000400fd8

Opcode: 48 8b 45 c0

Instruction: mov -0x40(%rbp), %rax

Description: The pointer to the XtTraderApi object (stored at
-0x40(%rbp)) is loaded back into rax. This is likely preparing the this pointer for the virtual method call.

  1. 0x0000000000400fdc be 80 7f 40 00 mov $0x407f80,%esi

Address: 0x0000000000400fdc

Opcode: be 80 7f 40 00

Instruction: mov $0x407f80, %esi

Description: The immediate value 0x407f80 is moved into the esi
register. This is likely an argument being passed to the virtual
method.

  1. 0x0000000000400fe1 48 89 c7 mov %rax,%rdi

Address: 0x0000000000400fe1

Opcode: 48 89 c7

Instruction: mov %rax, %rdi

Description: The pointer to the XtTraderApi object (in rax) is moved
into rdi. In the System V AMD64 ABI, rdi is used for the first
argument to a function, which in this case is the this pointer for the
virtual method call.

  1. 0x0000000000400fe4 ff d2 callq *%rdx

Address: 0x0000000000400fe4

Opcode: ff d2

Instruction: callq *%rdx

Description: This calls the function whose address is stored in rdx.
Since rdx holds a function pointer from the vtable, this is invoking a
virtual method of the XtTraderApi object.

Summary:
A XtTraderApi object is created, and its pointer is stored on the stack.
The vtable pointer of the object is accessed.
A specific virtual method (at offset 0x18 in the vtable) is resolved.
The virtual method is called with the XtTraderApi object (this pointer) as the first argument and 0x407f80 as the second argument.
This is typical C++ behavior for calling a virtual method on an object. The vtable is used to dynamically resolve the correct method to call at runtime.

因此我們確定了 init 函數在虛表中的位置是 0x18 也就是24, 那么24/8 = 3 , 所以是 0,8,16,24 在虛表中是第4個!

但是,但是,我們的虛表顯示,ini是第3個函數,也就是位置 16 的那個函數!? windows下也用這個虛表,而且我們其他工程都是虛表(windows與linux)一致的啊!
這是怎么回事!!!??
下面展示部分頭文件,大家看看能明白怎么回事嗎:

 class XT_API_EXPORT XtTraderApi{public:virtual ~XtTraderApi(){};/*** @brief 獲取XtTraderApi實例* @param [in] address XtApiService監聽端口*/static XtTraderApi* createXtTraderApi(const char* address);/*** @brief 設置數據回調對象* @param [in] pCallback XtTraderApiCallback類實例*/virtual void setCallback(XtTraderApiCallback* pCallback) = 0;/*** @brief 創建api實例,并進行初始化* @param [in] configFilePath 配置文件夾目錄,默認是"../config",運行目錄上一層的config下*/virtual bool init(const char* configFilePath = "../config") = 0;

你看, 析構函數,static函數, setCallback, init 但是 那個 static函數不可能寫在虛表里啊,windows下就是被撇除的,所以是 析構函數,setCallback, init 這個次序啊。
但是,Linux的反匯編已經說了, init 的位置是 第4個函數!!也就是 static函數 也被算在虛表里了。LINUX 下!
服了,之前其他工程,頭文件類聲明中的確沒有 static函數。。。。。。。
這個在 windows中和Linux中實現是不一樣的!!!
所以我們回過頭,再去看之前的錯誤,我們認為我們一直在調用init函數,其實調用的是 setCallback(*pCallback) 函數, 我們以為傳入的是字符串,但是api認為你傳入的是pCallback, 而且最 搞笑 的是, setCallback 函數會檢查 traderApi.ini 是否被加載過,沒有則顯示的錯誤和 init 顯示的錯誤一致!
這錯誤顯示太沒有邏輯了!直接誤導我了幾天!!!!!!
于是修改了虛表, all done!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72559.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72559.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72559.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

iOS底層原理系列01-iOS系統架構概覽-從硬件到應用層

1. 系統層級結構 iOS系統架構采用分層設計模式&#xff0c;自底向上可分為五個主要層級&#xff0c;每層都有其特定的功能職責和技術組件。這種層級化結構不僅使系統更加模塊化&#xff0c;同時也提供了清晰的技術抽象和隔離機制。 1.1 Darwin層&#xff1a;XNU內核、BSD、驅動…

k8s 修改節點驅逐閾值

編輯 /var/lib/kubelet/config.yaml 文件 kind: KubeletConfiguration evictionHard:nodefs.available: "5%" # 降低磁盤壓力觸發閾值imagefs.available: "10%" # 調整容器鏡像存儲觸發閾值nodefs.inodesFree: "3%

日志存儲與分析

日志是系統運行的詳細記錄&#xff0c;包含各種事件發生的主體、時間、位置、內容等關鍵信息。出于運維可觀測、網絡安全監控及業務分析等多重需求&#xff0c;企業通常需要將分散的日志采集起來&#xff0c;進行集中存儲、查詢和分析&#xff0c;以進一步從日志數據里挖掘出有…

PHP與MySQL的高效數據交互:最佳實踐與優化技巧

在現代Web開發中&#xff0c;PHP與MySQL的組合仍然是最常見的技術棧之一。PHP作為一種廣泛使用的服務器端腳本語言&#xff0c;與MySQL這一強大的關系型數據庫管理系統相結合&#xff0c;能夠構建出功能強大且高效的Web應用。然而&#xff0c;隨著數據量的增長和用戶需求的提升…

Flutter 邊框按鈕:OutlinedButton 完全手冊與設計最佳實踐

目錄 1. 引言 2. OutlinedButton 的基本用法 3. 主要屬性 3.1 核心屬性詳解 3.2 ButtonStyle 子屬性詳解 (styleFrom/copyWith) 狀態響應優先級說明 4. 自定義按鈕樣式 4.1 修改邊框顏色和文本顏色 4.2 修改按鈕形狀 4.3 修改按鈕大小 4.4 集中演示 5. 結論 相關推…

【Node.js入門筆記4---fs 目錄操作】

Node.js入門筆記4 Node.js---fs 目錄操作一、目錄操作1.fs.mkdir()&#xff1a;創建目錄。異步&#xff0c;非阻塞。創建單個目錄創建多個目錄創建目前之前需要確認是否存在&#xff1a; 2. fs.mkdirSync()&#xff1a;用于創建一個新的目錄。異步&#xff0c;非阻塞。3.fs.rmd…

IP風險度自檢,互聯網的安全“指南針”

IP地址就像我們的網絡“身份證”&#xff0c;而IP風險度則是衡量這個“身份證”安全性的重要指標。它關乎著我們的隱私保護、賬號安全以及網絡體驗&#xff0c;今天就讓我們一起深入了解一下IP風險度。 什么是IP風險度 IP風險度是指一個IP地址可能暴露用戶真實身份或被網絡平臺…

【軟考-架構】5.3、IPv6-網絡規劃-網絡存儲-補充考點

?資料&文章更新? GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目錄 IPv6網絡規劃與設計建筑物綜合布線系統PDS&#x1f4af;考試真題第一題第二題 磁盤冗余陣列網絡存儲技術其他考點&#x1f4af;考試真題第一題第二題 IPv6 網絡規劃與設計…

數據結構------線性表(順序表)

一、線性表順序存儲詳解 &#xff08;一&#xff09;線性表核心概念 1. 結構定義 // 數據元素類型 typedef struct person {char name[32];char sex;int age;int score; } DATATYPE;// 順序表結構 typedef struct list {DATATYPE *head; // 存儲空間基地址int tlen; …

SVN學習筆記

svn:版本控制軟件 解決&#xff1a;1.協作開發 2.遠程開發 3.版本回退 服務端軟件&#xff1a; VisualSVN http://www.visualsvn.com 客戶端軟件:Tortoisesvn http://tortoisesvn.net/downloads 1.checkout(檢出) 第一查更新數據到本地&#xff0c; 2.update&#xf…

uniapp-x js 限制

1.String(str) 不允許&#xff0c;android模擬室報錯&#xff0c;找不到String 2.JSON.parse不接受泛類型 export const genData function<T> (initData:T) : T {return JSON.parse<T>(JSON.stringify(initData))!;//不可以&#xff0c;必須明確類型 } error: …

PyTorch使用-張量的創建

文章目錄 張量的創建1. 安裝 PyTorch2. 基本創建方式2.1 torch.tensor 根據指定數據創建張量2.2. torch.Tensor 根據形狀創建張量, 其也可用來創建指定數據的張量2.3. 指定類型的張量創建2.3.1. torch.IntTensor&#xff1a;創建整數類型張量2.3.2. torch.FloatTensor&#xff…

基于asp.net實現的連鎖餐廳收銀系統[包運行成功+永久免費答疑輔導]

基于ASP.NET實現的連鎖餐廳收銀系統背景&#xff0c;可以從以下幾個方面進行闡述&#xff1a; 一、技術背景 ASP.NET框架的普及與優勢&#xff1a; ASP.NET是微軟開發的一種用于構建Web應用程序的框架&#xff0c;它基于.NET Framework&#xff0c;提供了豐富的類庫和開發工具…

PyTorch 深度學習實戰(11):強化學習與深度 Q 網絡(DQN)

在之前的文章中&#xff0c;我們介紹了神經網絡、卷積神經網絡&#xff08;CNN&#xff09;、循環神經網絡&#xff08;RNN&#xff09;、Transformer 等多種深度學習模型&#xff0c;并應用于圖像分類、文本分類、時間序列預測等任務。本文將介紹強化學習的基本概念&#xff0…

92.HarmonyOS NEXT開發學習路徑與最佳實踐總結:構建高質量應用

溫馨提示&#xff1a;本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦&#xff01; HarmonyOS NEXT開發學習路徑與最佳實踐總結&#xff1a;構建高質量應用 文章目錄 HarmonyOS NEXT開發學習路徑與最佳實踐總結&#xff1a;構建高質…

HarmonyOS-應用程序框架基礎

應用程序框架與應用模型的區別 應用框架可以看做是應用模型的一種實現方式&#xff0c;開發人員可以用應用模型來描述應用程序的結構和行為的描述&#xff0c;然后使用應用程序框架來實現這些描述。 應用模型 應用模型是一個應用程序的模型&#xff0c;它是一種抽象的描述&a…

審批工作流系統xFlow

WorkFlow-審批流程系統 該項目為完全開源免費項目 可用于學習或搭建初始化審批流程系統 希望有用的小伙伴記得點個免費的star gitee倉庫地址 仿釘釘飛書工作審批流系統 介紹 前端技術棧: vue3 ts vite arcodesign eslint 后端技術棧:springbootspring mvc mybatis mavenmysq…

數據傳輸對象 DTO

1. DTO 數據傳輸對象&#xff08;DTO, Data Transfer Object&#xff09;是一種設計模式&#xff0c;用于在不同系統或應用層之間封裝和傳輸數據。它通常用于解耦領域模型&#xff08;如數據庫實體&#xff09;和外部接口&#xff08;如API請求/響應&#xff09;&#xff0c;避…

本地算力部署大模型詳細流程(二)

1、前景回顧 上一篇我們通過ollama本地部署了一個DeepSeek&#xff0c;因為沒有前端操作頁面&#xff0c;我們只能使用cmd的方式和deepseek對話體驗感并不是很好&#xff0c;下面我們通過Docker部署一個前端頁面&#xff08;Open WebUI&#xff09; Open WebUI地址&#xff1a;…

django+vue3實現前后端大文件分片下載

效果&#xff1a; 大文件分片下載支持的功能&#xff1a; 展示目標文件信息提高下載速度&#xff1a;通過并發請求多個塊&#xff0c;可以更有效地利用網絡帶寬斷點續傳&#xff1a;支持暫停后從已下載部分繼續&#xff0c;無需重新開始錯誤恢復&#xff1a;單個塊下載失敗只…