【编译汇编链接】全局变量 char* g_str 和 char g_str[]

本文探讨了全局变量g_str和g_str1在C++中的不同之处,重点在于它们的声明类型(数组与指针)、访问权限和编译时的权限冲突。通过Debug模式和编译文件分析,揭示了为何在修改g_str1[0]时出现错误,以及为何在Release模式下问题消失。

请在Debug模式下进行文章涉及的操作,以避免Release行为优化了部分细节。

一、产生

针对如下代码,先提出一个问题,g_strg_str1有何异同?LINE 1LINE 2执行情况如何?

// 代码`1-1`
#include <iostream>
char g_str[] = "hello";
char *g_str1 = (char*)"world";
int main()
{
	g_str[0] = '1'; // LINE 1
	g_str1[0] = '1'; // LINE 2
}

二、分析

先回答一下提出的第一个问题:

首先g_strg_str1都是全局变量,并且都存储在静态存储区。
调试截图

但是两者在本质上是有区别的。

  1. 在声明上,g_str是一个长度为6char类型的数组,g_str1是一个char类型的指针。

首先,如果仅仅是执行read操作的话,两者是都可以正常执行的,比如下边这两行代码

// 代码`2-1`
 printf("%s",g_str);
 printf("%s",g_str1);

但是如果你尝试对两者进行修改操作时,结果会怎样?也就是代码1-1中的操作。依次执行,修改g_str[0]正常执行,修改g_str1[0]则会报错写入访问权限冲突,报错情况如下所示:
报错情况——写入访问权限冲突
这个问题解释起来很简单,由于汇编过程中将不同的代码放入了不同的地方,而这些地方的权限也不尽相同,以上操作导致了一个不可被write的数据发生了write行为,所以编译器报错了。这也就引出了第二个不同点。
 
但是,上述问题在Release模式下就不会产生。有待研究

  1. 访问权限不同,一个是常量全局变量,一个是非常量全局变量

可以看到在声明g_str1的时候进行了强制转换的操作,不强制转换的话,编译器会报错,告诉你不能把一个const char *的用来初始化一个char*的实体。
 

这里往往最容易被忽略的一点就是char *g_Str1 = (char*)"world";这行代码中的"world",其实是一个const char *。也就是你在声明并定义g_Str1的时候,其实是把一个const区域的指针强转给了g_str1。因此在修改g_str[0]的时候会出现访问权限拒绝,因为g_str1本身就只指向了一个const的内存段。

三、结合编译文件查看一下上述问题产生的原因

使用Dumpbin工具查看一下代码2-1的.obj文件

从这里开始所提到的段落都是.obj文件中的SECTION HEADER,如SECTION HEADER #5即指段落5。

  1. 首先看一下符号表中的相关项:
    符号表截图
    看到这个,我纳闷了~

明明两种声明编译后的结果一样啊,并且都还在同一个数据段(SECT4),对外类型也是默认的External,本质上都是char *

符号表展示出来的结果确实如此,那接着看,看数据段上是怎么说明的。

数据段是包含一个数据头和段落数据,一个obj文件中有多个数据段,每一个数据段都有自己的特性,包括权限、物理地址、数据大小、重定为,行号等,如下为 SECTION HEADER #4的段落头:
SECTION HEADER #4
基本上,从段落头我们就能看到当前数据段的一些大致信息,比如当前段落是.data段(通常包含已初始化的数据)。由于我们对g_strg_str1均进行了初始化,因此,在该段中,可以看到这两个变量。如下图所示,是段落#4的数据段和冲定向段。
RAW DATA #4 & RELOCATIONS #4
在符号表中我们已经看到了,g_strg_str1都是保存在段落4中的。在上图中得以验证,可以看到在RAW DATA中保存了g_str的初始值,在RELOCATIONS中保存了g_str1的初始值,并且加了其他的描述符在其前后,同时,还是以string类型进行编译的。
 

  • RAW DATA :段落数据。每个段落真正数据保存的位置
  • RELOCATIONS: 重定向段。描述文件中符号的重定向信息。
     

结合以上所看到的段落信息,说明一下:

由此,我们就可以看到,g_str的数据是保存在.data段的数据段(RAW DATA)的,而.data段的权限是Read Write,这也就说明,g_str是可以被.text(通常包含可执行代码)段操作的,准确说是当前文件的.text段。
 
g_str1是以重定向的方式被保存在数据段4中。保存的名字是??_C@_05MCBCHHEJ@world@,那我们就在obj文件中查找一个这个值真正保存的位置在哪。
从符号表查找??_C@_05MCBCHHEJ@world@,显示如下:
??_C@_05MCBCHHEJ@world@查找结果
可以看到其保存在段落5中。回到.obj文件中查看段落5,截图如下:
SECTION HEADER #5

看到段落5之后是不是有一种,守得云开见月明的感觉。数据段保存的是g_str1的源数据world,而数据段的访问权限是Read only

因此,在调用g_strq[0] = '1'的时候,发生了写入访问权限冲突的异常。

请仔细阅读分析下面函数,进行优化后,采用C/C++11标准,完整推导并重构可编译的全部代码 特别注意: 1.确保所有函数调用逻辑完整保留 2.提高执行效率,降低计算复杂度 3.详细的注释,使用中文 4.不使用auto,使用显式for循环 5.结构体采用32位定义 6.不拆分函数,保持一个大函数内 7.严格保持protobuf字段映射关系 8.使用protobuf反射方式读取数据 void __fastcall HDDMTileType::allocatetileports(HDDMTileType *this) { __int64 n4; // rbx char **v2; // r12 __int64 v3; // rax HDDMTileEdge *v4; // rbp HDDMTileEdge **qword230; // rax bool v6; // zf __int64 qword230_1; // rax HDDMTileType *p_char248; // rbp HDDMTileType *qword250; // r12 __int64 p_char248_1; // rax int tileType_code6_high; // eax int tileType_code6_high_2; // r13d char *v13; // rbp char *v14; // r14 __int64 v15; // rax HDDMTileFace *v16; // rbp HDDMTileEdge *v17; // rax HDDMTileFace **qword20; // rdx __int64 qword20_1; // rdx HDDMTileEdge *v20; // r14 HDDMTileEdge *qword40; // r15 HDDMTileEdge *p_char38; // rbp __int64 p_char38_1; // rax __int64 qword28; // r15 HDDMTileEdge *qword280; // r14 HDDMTileEdge *p_char278; // rbp __int64 p_char278_1; // rax char **v28; // [rsp+0h] [rbp-268h] __int64 n4_1; // [rsp+30h] [rbp-238h] int tileType_code6_high_1; // [rsp+48h] [rbp-220h] char v31; // [rsp+6Eh] [rbp-1FAh] BYREF char v32; // [rsp+6Fh] [rbp-1F9h] BYREF _QWORD v33[2]; // [rsp+70h] [rbp-1F8h] BYREF HDDMTileEdge *v34; // [rsp+80h] [rbp-1E8h] BYREF _QWORD v35[2]; // [rsp+90h] [rbp-1D8h] BYREF _QWORD v36[2]; // [rsp+A0h] [rbp-1C8h] BYREF _QWORD *v37; // [rsp+B0h] [rbp-1B8h] BYREF _QWORD v38[2]; // [rsp+C0h] [rbp-1A8h] BYREF char *v39; // [rsp+D0h] [rbp-198h] BYREF char *v40; // [rsp+D8h] [rbp-190h] __int64 v41; // [rsp+E0h] [rbp-188h] __int64 v42; // [rsp+E8h] [rbp-180h] __int64 v43; // [rsp+F0h] [rbp-178h] __int64 v44; // [rsp+F8h] [rbp-170h] __int64 v45; // [rsp+100h] [rbp-168h] __int64 v46; // [rsp+108h] [rbp-160h] int n16; // [rsp+118h] [rbp-150h] char *v48; // [rsp+120h] [rbp-148h] char *v49; // [rsp+128h] [rbp-140h] __int64 v50; // [rsp+200h] [rbp-68h] char v51; // [rsp+208h] [rbp-60h] char v52; // [rsp+209h] [rbp-5Fh] __int64 v53; // [rsp+210h] [rbp-58h] __int64 v54; // [rsp+218h] [rbp-50h] __int64 v55; // [rsp+220h] [rbp-48h] __int64 v56; // [rsp+228h] [rbp-40h] n4 = *(_QWORD *)(qword_992F660 - 24LL); std::vector<HDDMTileEdge *>::reserve(&this->qword228, (int)n4); if ( (int)n4 > 0 ) { v2 = &v39; n4_1 = 0; while ( 1 ) { v3 = qword_992F660; if ( *(int *)(qword_992F660 - 8LL) >= 0 ) { std::string::_M_leak_hard((std::string *)&qword_992F660); v3 = qword_992F660; } std::string::string(v33, 1, (unsigned int)*(char *)(v3 + n4_1), v2); v4 = (HDDMTileEdge *)operator new(0x60u); HDDMTileEdge::HDDMTileEdge(v4, this, n4_1, (const std::string *)v33); qword230 = (HDDMTileEdge **)this->qword230; v6 = qword230 == (HDDMTileEdge **)this->qword238; v34 = v4; if ( v6 ) { std::vector<HDDMTileEdge *>::_M_emplace_back_aux<HDDMTileEdge * const&>(&this->qword228, &v34); } else { if ( qword230 ) { *qword230 = v4; qword230_1 = this->qword230; } else { qword230_1 = 0; } this->qword230 = qword230_1 + 8; } p_char248 = (HDDMTileType *)&this->char248; if ( !this->qword250 ) goto LABEL_49; v28 = v2; qword250 = (HDDMTileType *)this->qword250; do { while ( (int)std::string::compare((std::string *)&qword250->gname, (const std::string *)v33) >= 0 ) { p_char248 = qword250; qword250 = *(HDDMTileType **)&qword250->tileType_code4; if ( !qword250 ) goto LABEL_14; } qword250 = *(HDDMTileType **)&qword250->tileType_code6; } while ( qword250 ); LABEL_14: v2 = v28; if ( &this->char248 == (_QWORD *)p_char248 || (int)std::string::compare((std::string *)v33, (const std::string *)&p_char248->gname) < 0 ) { LABEL_49: v39 = (char *)v33; p_char248_1 = std::_Rb_tree<std::string,std::pair<std::string const,HDDMTileEdge *>,std::_Select1st<std::pair<std::string const,HDDMTileEdge *>>,std::less<std::string>,std::allocator<std::pair<std::string const,HDDMTileEdge *>>>::_M_emplace_hint_unique<std::piecewise_construct_t const&,std::tuple<std::string const&>,std::tuple<>>( this->gap240, p_char248, &qword_7B6AC49, v2, v36); } else { p_char248_1 = (__int64)p_char248; } *(_QWORD *)(p_char248_1 + 40) = v34; if ( (_DWORD)n4_1 == 4 ) break; if ( (n4_1 & 1) != 0 ) tileType_code6_high = HIWORD(this->tileType_code6); else tileType_code6_high = LOWORD(this->tileType_code6); tileType_code6_high_1 = tileType_code6_high; if ( tileType_code6_high ) goto LABEL_21; LABEL_42: std::string::_Rep::_M_dispose(v33[0] - 24LL, v2); if ( (int)n4 <= (int)++n4_1 ) return; } tileType_code6_high_1 = 1; LABEL_21: tileType_code6_high_2 = 0; v13 = (char *)`VTT for'std::ostringstream[1]; v14 = (char *)`VTT for'std::ostringstream[2]; do { std::ios_base::ios_base((std::ios_base *)(v2 + 11)); v39 = v13; v50 = 0; v51 = 0; v52 = 0; v53 = 0; v54 = 0; v55 = 0; v49 = (char *)&`vtable for'std::ios + 16; v56 = 0; *(char **)((char *)&v39 + *((_QWORD *)v13 - 3)) = v14; std::ios::init((char *)v2 + *((_QWORD *)v39 - 3), 0); v41 = 0; v42 = 0; v43 = 0; v44 = 0; v45 = 0; v46 = 0; v39 = (char *)&`vtable for'std::ostringstream + 24; v49 = (char *)&`vtable for'std::ostringstream + 64; v40 = (char *)&`vtable for'std::streambuf + 16; std::locale::locale((std::locale *)(v2 + 8)); n16 = 16; v40 = (char *)&`vtable for'std::stringbuf + 16; v48 = (char *)&std::string::_Rep::_S_empty_rep_storage + 24; std::ios::init(v2 + 11, v2 + 1); v15 = std::__ostream_insert<char,std::char_traits<char>>(v2, v33[0], *(_QWORD *)(v33[0] - 24LL)); std::ostream::operator<<(v15, (unsigned int)tileType_code6_high_2); std::stringbuf::str(v35, v2 + 1); v16 = (HDDMTileFace *)operator new(0x30u); HDDMTileFace::HDDMTileFace(v16, v34, tileType_code6_high_2, (const std::string *)v35); v17 = v34; v36[0] = v16; qword20 = (HDDMTileFace **)v34->qword20; if ( qword20 == (HDDMTileFace **)v34->qword28 ) { std::vector<HDDMTileFace *>::_M_emplace_back_aux<HDDMTileFace * const&>(&v34->qword18, v36); v20 = v34; } else { if ( qword20 ) { *qword20 = v16; qword20_1 = v17->qword20; v20 = v34; } else { v20 = v34; qword20_1 = 0; } v17->qword20 = qword20_1 + 8; } qword40 = (HDDMTileEdge *)v20->qword40; p_char38 = (HDDMTileEdge *)&v20->char38; if ( !qword40 ) goto LABEL_45; do { while ( (int)std::string::compare((std::string *)&qword40->qword20, (const std::string *)v35) >= 0 ) { p_char38 = qword40; qword40 = (HDDMTileEdge *)qword40->qword10; if ( !qword40 ) goto LABEL_31; } qword40 = (HDDMTileEdge *)qword40->qword18; } while ( qword40 ); LABEL_31: if ( &v20->char38 == (char *)p_char38 || (int)std::string::compare((std::string *)v35, (const std::string *)&p_char38->qword20) < 0 ) { LABEL_45: v37 = v35; p_char38_1 = std::_Rb_tree<std::string,std::pair<std::string const,HDDMTileFace *>,std::_Select1st<std::pair<std::string const,HDDMTileFace *>>,std::less<std::string>,std::allocator<std::pair<std::string const,HDDMTileFace *>>>::_M_emplace_hint_unique<std::piecewise_construct_t const&,std::tuple<std::string const&>,std::tuple<>>( v20->gap30, p_char38, &qword_7B6AC49, &v37, &v31); } else { p_char38_1 = (__int64)p_char38; } qword28 = v36[0]; *(_QWORD *)(p_char38_1 + 40) = v36[0]; qword280 = (HDDMTileEdge *)this->qword280; p_char278 = (HDDMTileEdge *)&this->char278; if ( !qword280 ) goto LABEL_44; do { while ( (int)std::string::compare((std::string *)&qword280->qword20, (const std::string *)v35) >= 0 ) { p_char278 = qword280; qword280 = (HDDMTileEdge *)qword280->qword10; if ( !qword280 ) goto LABEL_39; } qword280 = (HDDMTileEdge *)qword280->qword18; } while ( qword280 ); LABEL_39: if ( p_char278 == (HDDMTileEdge *)&this->char278 || (int)std::string::compare((std::string *)v35, (const std::string *)&p_char278->qword20) < 0 ) { LABEL_44: v38[0] = v35; p_char278_1 = std::_Rb_tree<std::string,std::pair<std::string const,HDDMTileFace *>,std::_Select1st<std::pair<std::string const,HDDMTileFace *>>,std::less<std::string>,std::allocator<std::pair<std::string const,HDDMTileFace *>>>::_M_emplace_hint_unique<std::piecewise_construct_t const&,std::tuple<std::string const&>,std::tuple<>>( this->gap270, p_char278, &qword_7B6AC49, v38, &v32); qword28 = v36[0]; p_char278 = (HDDMTileEdge *)p_char278_1; } p_char278->qword28 = qword28; ++tileType_code6_high_2; std::string::_Rep::_M_dispose(v35[0] - 24LL, v38); v39 = (char *)&`vtable for'std::ostringstream + 24; v49 = (char *)&`vtable for'std::ostringstream + 64; v40 = (char *)&`vtable for'std::stringbuf + 16; std::string::_Rep::_M_dispose(v48 - 24, v38); v40 = (char *)&`vtable for'std::streambuf + 16; std::locale::~locale((std::locale *)(v2 + 8)); v13 = (char *)`VTT for'std::ostringstream[1]; v14 = (char *)`VTT for'std::ostringstream[2]; v39 = v13; *(char **)((char *)&v39 + *((_QWORD *)v13 - 3)) = v14; v49 = (char *)&`vtable for'std::ios + 16; std::ios_base::~ios_base((std::ios_base *)(v2 + 11)); } while ( tileType_code6_high_2 < tileType_code6_high_1 ); goto LABEL_42; } }
10-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧恩意

如有帮助,感谢打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值