日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

全局变量初始化顺序探究

發布時間:2023/12/4 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 全局变量初始化顺序探究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

緣起

我在上一篇文章——《調試實戰 —— dll 加載失敗之全局變量初始化篇》中,跟大家分享了一個由于全局變量初始化順序導致的 dll 加載失敗的例子。感興趣的小伙伴兒可以點擊閱讀。

雖然我們知道了是由于全局變量初始化順序導致的問題,也給出了解決方案。但是有一點卻沒有刨根問底——為什么改變文件在工程文件中的順序就可以改變全局變量初始化順序?是怎么影響的呢?本篇文章力求解決這個問題。

了解 Build

我們可以簡單的把整個構建過程分成三個步驟(當然實際還有其它步驟,我們一般不關心):預編譯,編譯,鏈接。

預編譯: 處理宏,#include 展開等。

編譯: 以編譯單元為單位生成對應的 .obj 文件。

鏈接: 把生成的.obj 文件和必要的文件鏈接成最后的應用程序。

猜想

因為編譯是把符號放到對應的 .obj 中,鏈接的時候才把對應的 .obj 文件鏈接成最后的應用程序。鏈接的時候應該是按照 .obj 文件出現的先后順序依次把 .obj 中的符號放到對應的位置。

思路

對比觀察調整順序前和調整順序后的編譯參數,鏈接參數。因為猜測是鏈接導致的問題,我們主要關注鏈接參數。

編譯過程初探

當我們在 vs 中執行 build 時的整個過程如下圖(使用 process monitor 捕獲的):

vs-msbuild-cl-link

可以清晰的看到,vs 在內部會啟動 msbuild.exe 執行后續的操作。msbuild.exe 會間接啟動 cl.exe 進行編譯,link.exe 進行鏈接。我們還發現黃色高亮部分的 Tracker.exe ,這個進程主要用來加速編譯的。具體可以參考《Inside the Microsoft Build Engine Using MSBuild and Team Foundation Build》 這本書的介紹,簡單截圖如下:

filetracker-introduce

簡化編譯過程

因為 vs 會通過 msbuild.exe 執行操作,我們可以直接使用 msbuild.exe 進行構建。msbuild 有一個選項 TrackFileAccess 可以用來控制是否使用 FileTracker。為 false 時,不啟用 FileTracker。

為了簡化問題,我們直接執行 msbuild.exe -p:TrackFileAccess=false project_file_to_build.vcxproj 。

msbuild-cl-link-param

我們發現,傳遞給 cl.exe 和 link.exe 的參數都是文件。猜測,應該是把參數保存到文件中傳遞的。據觀察,這些文件會在執行完后被清理。得想辦法在這些文件被刪除之前保存一份,各位小伙伴兒有什么好辦法嗎?

我們先看下這些參數文件是誰創建和刪除的,什么時候刪除的。創建很簡單,肯定是 msbuild.exe。刪除呢?是 cl.exe / link.exe 還是 msbuild.exe 呢?又是什么時候刪除的呢?相信下圖能很好的回答這些問題了。

msbuild-remove-param-file

我想到兩個思路:

  • 因為這些文件是 msbuild.exe 創建/刪除的,可以在 msbuild.exe 中文件操作的地方加斷點。

  • 可以暫停 cl.exe/link.exe 的執行,拷貝我們需要的文件到桌面。

  • 第一個思路相對來說比較復雜,今天我們嘗試第二個思路。我們該如何暫停呢?請出 gflags.exe。

    中斷 link.exe

    我們可以在 gflags.exe 中進行如下設置,這樣當 link.exe 啟動時就會中斷到 windbg.exe 中了。

    gflags-set-debug-link

    斷下來后,我們可以在 windbg 中輸入 !peb 觀察參數,里面包含了我們需要拷貝的文件路徑。

    windbg-command-line

    有了文件路徑,我們就可以手動復制對應的文件到桌面慢慢研究了。

    對比鏈接參數

    調整 Test1.cpp Test2.cpp 在 .vcxproj 中的順序,按上面的方法分別保存傳遞給 link.exe 的參數文件,對比如下圖(格式有調整):

    obj-link-order

    發現在兩次鏈接過程中,Test1.obj Test2.obj 出現的順序是不一樣的。

    結論

    哪個源碼文件在 .vcxproj 中先出現,其對應的 .obj 文件在傳遞給 link.exe 的參數文件(.rsp)中越靠前,會被優先處理。.obj 中包含的全局變量會被優先處理。當進程啟動時,執行全局變量初始化的時候會按照先后順序初始化。

    總結

    • vs 內部會使用 msbuild.exe 編譯,我們也可以直接使用 msbuild.exe 進行編譯。

    • 使用 msbuild.exe -p:TrackFileAccess=false 可以在編譯的過程中不啟動 Tracker.exe,對我們調查問題有幫助。

    • 我們可以在一個進程啟動時就中斷到調試器,可以使用 gflags.exe 幫我們實現這一點。

    • !peb 可以查看啟動參數,環境變量等信息。

    • .vcxproj 中文件的順序會影響最后鏈接時的順序。

    參考資料

    《Inside the Microsoft Build Engine Using MSBuild and Team Foundation Build》

    https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?redirectedfrom=MSDN&view=vs-2019

    http://www.cppblog.com/xlshcn/archive/2007/12/07/37088.html

    需要你的

    總結

    以上是生活随笔為你收集整理的全局变量初始化顺序探究的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。