全局变量初始化顺序探究

缘起

我在上一篇文章——《调试实战 —— 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.exelink.exe 的参数都是文件。猜测,应该是把参数保存到文件中传递的。据观察,这些文件会在执行完后被清理。得想办法在这些文件被删除之前保存一份,各位小伙伴儿有什么好办法吗?

我们先看下这些参数文件是谁创建和删除的,什么时候删除的。创建很简单,肯定是 msbuild.exe。删除呢?是 cl.exe / link.exe 还是 msbuild.exe 呢?又是什么时候删除的呢?相信下图能很好的回答这些问题了。

msbuild-remove-param-file

我想到两个思路:

  1. 因为这些文件是 msbuild.exe 创建/删除的,可以在 msbuild.exe 中文件操作的地方加断点。

  2. 可以暂停 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

需要你的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java基础知识——面向对象基本概念

文章目录Java基本概念源文件声明规则Java包Import语句继承类型继承的特性继承关键字super 与 this 关键字构造器方法的重写规则重载(Overload)重写与重载之间的区别java 接口接口与类相似点:接口与类的区别:接口特性抽象类和接口的区别接口的声明接口的实…

[JavaWeb-MySQL]多表查询练习

-- 部门表 CREATE TABLE dept (id INT PRIMARY KEY PRIMARY KEY, -- 部门iddname VARCHAR(50), -- 部门名称loc VARCHAR(50) -- 部门所在地 );-- 添加4个部门 INSERT INTO dept(id,dname,loc) VALUES (10,教研部,北京), (20,学工部,上海), (30,销售部,广州), (40,财务部,深圳)…

基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)

上一篇完成了全网各大平台的热点新闻数据的抓取,本篇继续围绕抓取完成后的操作做一个提醒。当每次抓取完数据后,自动发送邮件进行提醒。在开始正题之前还是先玩一玩之前的说到却没有用到的一个库PuppeteerSharp。PuppeteerSharp:Headless Chr…

创建型模式——工厂模式

一、 实验目的与要求 1.练习使用工厂模式。设计相关的模拟场景并进行实施,验证模式特性,掌握其优缺点。 2.实验结束后,对相关内容进行总结。 二、实验内容 1.模式应用场景说明 作为一个青年人,最好的伙伴就是手机。而手机最重…

[JavaWeb-MySQL]事务的基本介绍

事务的基本介绍 1. 概念:* 如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。2. 操作:1. 开启事务: start transaction;2. 回滚:rollback;3. 提交&#xff…

dotNET Core 3.X 依赖注入

如果说在之前的 dotNET 版本中,依赖注入还是个比较新鲜的东西,那么在 dotNET Core 中已经是随处可见了,可以说整个 dotNET Core 的框架是构建在依赖注入框架之上。本文说说对 dotNET Core 中依赖注入的理解。什么是依赖在面向对象的语言中&am…

创建型模式——抽象工厂模式

一、 实验目的与要求 1.练习使用工厂模式。设计相关的模拟场景并进行实施,验证模式特性,掌握其优缺点。 2.实验结束后,对相关内容进行总结。 二、实验内容 1.模式应用场景说明 手机CPU生产工厂:在一个工厂里面,有A…

[JavaWeb-MySQL]多表查询概述

多表查询: * 查询语法:select列名列表from表名列表where.... * 准备sql# 创建部门表CREATE TABLE dept(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20));INSERT INTO dept (NAME) VALUES (开发部),(市场部),(财务部);# 创建员工表CREATE TABLE em…

【壹刊】Azure AD(三)Azure资源的托管标识

一,引言来个惯例,吹水!????????????????????前一周因为考试,还有个人的私事,一下子差点颓废了。想了想,写博客这种的东西还是得坚持,再忙,也要检查。要养成一种…

自定义View

自定义View重写构造方法和onDraw方法 MyView.java package com.example.jrtt;import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Lo…

[JavaWeb-JDBC]JDBC概念

JDBC: 1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口…

创建型模式——建造者模式

一、 实验目的与要求 1.练习使用工厂模式。设计相关的模拟场景并进行实施,验证模式特性,掌握其优缺点。 2.实验结束后,对相关内容进行总结。 二、实验内容 1.模式应用场景说明 Decis创建一个获取多套餐信息,包含A套餐&#xf…

[JavaWeb-MySQL]事务的四大特征和隔离级别

事务的四大特征: 1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。3. 隔离性:多个事务之间。相互独立。4. 一致性&am…

android studio模拟器的安装与使用

来回弄了好几遍,网上也都搜过下载过很多版本,其中夜神模拟器是真的方便,也好用,棒极了!那么我就来分享一下: 第一,肯定是下载啦 下载链接:夜神模拟器官方 接着就是连接了&#xff0c…

如何训练解决问题的能力?

作为程序员,技术能力固然很重要,但平时除了提升技术能力也别忽略了其它方面的能力。你可以写一辈子代码,但你不能一辈子只写代码。当你的技术能力足以使你在公司站稳脚跟时,你可以停下来锻炼自己的管理能力,比如职场中…

[JavaWeb-MySQL]DCL管理用户,授权

DCL: * SQL分类:1. DDL:操作数据库和表2. DML:增删改表中数据3. DQL:查询表中数据4. DCL:管理用户,授权* DBA:数据库管理员* DCL:管理用户,授权1. 管理用户1…

PS照片换底色

因为写简历嘛,手边没有白色底的照片,就用ps换了个底色,记录一下,下次可能还要用。这里我用幂幂的照片来代替。 打开ps,点击文件,点击打开,找到你需要处理的照片。 -点击旁边的对象选择工具&…

小心 HttpClient 中的 FormUrlEncodeContent 的 bug

小心 HttpClient 中的 FormUrlEncodeContent 的 bugIntro最近发现活动室预约项目里的上传图片有时候会有问题,周末找时间测试了一下,发现小图片的上传没问题,大图片上传会有问题,而且异常信息还很奇怪,System.UriForma…

IDEA导入MySQL的jdbc驱动出现“java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver”

目录 一、一般的解决思路 1、JDBC下载链接 2、选择下载内容,并进行下载 3、将驱动导入java项目 二、依然导入驱动失败怎么办 当我们在idea中使用java操作mysql数据库时会出现: Exception in thread "main" java.lang.ClassNotFoundExce…

Android程序设计基础-设计布局之伪今日头条主界面

一、 实验目的 (1) 掌握Andriod Studio的基本使用方法; (2) 掌握Andriod Studio中常用的控件及其使用方法; 二、实验内容 (1)使用Android Studio编写任意一个Android程序并运行&a…