当前位置:网站首页>VS2013-调试汇编代码-生成asm文件-结构体内存布局-函数参数压栈-调用约定
VS2013-调试汇编代码-生成asm文件-结构体内存布局-函数参数压栈-调用约定
2022-08-10 07:14:00 【插件开发】
有时需要查看下底层汇编代码的编写,或者采用高级语言编写底层的汇编代码,这时可以采用C语言或者C++语言代写,然后查看生成的汇编代码。
1.生成asm文件
项目->属性->c/c+±>输出文件->汇编程序输出
在项目中会有生成后缀为*.asm 的文件。里面有注释,有利于程序分析。如下图所示:
生成之后在Debug目录下有对应文件的汇编代码,如下图所示:
2.使用反汇编方式
在调试模式下可以直接查看,点击调试->>>窗口->>反汇编 快捷键 CTRL+ALT+D。
3.结构体内存布局
一、内存对齐的原因
1.平台原因(移植原因):一些资料上是这样说的,“不是所有的硬件平台都能访问任意地址上的任意数据;某些硬件平台只能在某些特定地址处取某些特定的数据,否则就会抛出硬件异常”。也就是说在计算机在内存读取数据时,只能在规定的地址处读数据,而不是内存中任意地址都是可以读取的。
2.效率原因:正是由于只能在特定的地址处读取数据,所以在访问一些数据时,对于访问未对齐的内存,处理器需要进行两次访问;而对于对齐的内存,只需要访问一次就可以。其实这是一种以空间换时间的做法,但这种做法是值得的。
结构体内存对齐规则:
1.第一个成员在结构体变量偏移量为0 的地址处,也就是第一个成员必须从头开始。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 为编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux默认值为4(当然可以通过#pragma pack修改),但修改只能设置成1,2,4,8,16。
3. 结构体总大小为最大对齐数的整数倍。(每个成员变量都有自己的对齐数)
4.如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
struct struct1 {
char c1;
char c2;
int i;
};
int main()
{
struct1 sobj1;
sobj1.c1 = 'a';
sobj1.c2 = 'b';
sobj1.i = 9;
printf("%d", sizeof(struct1));
}
c1是char型,占一个字节,第一个成员即 c1 在结构体变量偏移量为0 的地址处。
c2是char型,占一个字节,要对齐到对齐数的整数倍的位置。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值,vs中默认值是8,取较小值1,char类型的对齐数是1,所以对齐到1 的整数倍,那就是偏移量为1开始的地址空间。
i是int类型,占四个字节,要对齐到对齐数的整数倍的位置。int类型的对齐数就是 4,所以对齐到4 的整数倍。
4.调用约定与函数参数压栈
VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调用方式,在 DLL 导出函数中,为了跟 Windows API 保持一致,建议使用 __stdcall 方式。
调用约定跟堆栈清除密切相关。如果写一个汇编函数,给 C/C++ 调用,在 __cdecl 方式下,则汇编函数无需清除堆栈,在 __stdcall 方式下,汇编函数需要在返回(RET)之前恢复堆栈。
C 语言有 __cdecl、__stdcall、__fastcall、naked、__pascal。
C++ 语言有 __cdecl、__stdcall、__fastcall、naked、__pascal、__thiscall,比 C 语言多出一种 __thiscall 调用方式。
1、__cdecl
__cdecl调用约定又称为 C 调用约定,是 C/C++ 语言缺省的调用约定。参数按照从右至左的方式入栈,函数本身不清理栈,此工作由调用者负责,返回值在EAX中。 由于由调用者清理栈,所以允许可变参数函数存在,如int sprintf(char* buffer,const char* format,…);。
2、__stdcall
__stdcall 很多时候被称为 pascal 调用约定。pascal 语言是早期很常见的一种教学用计算机程序设计语言,其语法严谨。参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。
3、__fastcall
顾名思义,__fastcall 的特点就是快,因为它通过 CPU 寄存器来传递参数。他用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数,剩下的参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在 EAX 中。
4、naked
naked 是一个很少见的调用约定,一般不建议使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回结果,此调用约定必须跟 __declspec 同时使用。例如定义一个求和程序,如__declspec(naked) int add(int a,int b);。
5、__pascal
这是 pascal 语言的调用约定,跟 __stdcall 一样,参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。VC 中已经废弃了这种调用方式,因此在写 VC 程序时,建议使用 __stdcall 代替。
6、__thiscall
这是 C++ 语言特有的一种调用方式,用于类成员函数的调用约定。如果参数确定,this 指针存放于 ECX 寄存器,函数自身清理堆栈;如果参数不确定,this指针在所有参数入栈后再入栈,调用者清理栈。__thiscall 不是关键字,程序员不能使用。参数按照从右至左的方式入栈。
边栏推荐
猜你喜欢
![[网络安全]实操AWVS靶场复现CSRF漏洞](/img/7f/f08e429e3d8ede03a1c1754e256f99.png)
[网络安全]实操AWVS靶场复现CSRF漏洞

WooCommerce 安装和 rest api 使用

PLSQL学习第一天

浅谈C语言整型数据的存储

杭州公积金修改手机号信息

34. 谈谈为什么要拆分数据库?有哪些方法?

Based on STC8G2K64S4 single-chip microcomputer to display analog photosensitive analog value through OLED screen

About MongoDb query Decimal128 to BigDecimal problem

PLSQL学习第四天

MySQL设置初始密码—注意版本mysql-8.0.30
随机推荐
mysql数据库定时备份(保留近7天的备份)
Please pay attention to me, thank you.
S0:12345:respawn:/bin/start_getty 115200 ttyS0 vt102
Introduction to C integer data storage
裸辞—躺平—刷题—大厂(Android面试的几大技巧)
深入理解LTE网络的CDRX
如何治理资源浪费?百度云原生成本优化最佳实践
navicat for mysql 连接时报错:1251-Client does not support authentication protocol requested by server
Based on STC8G2K64S4 single-chip microcomputer to display analog photosensitive analog value through OLED screen
MySQL事务隔离级别
1413. Stepwise Summation to Get Minimum Positive Numbers
ES13 - ES2022 - 第 123 届 ECMA 大会批准了 ECMAScript 2022 语言规范
MySQL索引事务
Nude speech - lying flat - brushing questions - big factory (several tips for Android interviews)
3.1-3.3 读书笔记
Confluence可以连接数据库但是在下一步就报错了
I would like to ask you guys, when FLink SQL reads the source, specify the time field of the watermark. If the specified field is in the grid
【机器学习】神经网络中的优化器
Elementary Structure
.NET-7.WPF learning experience summary