# 函数
# 定义
类型 函数名 (参数类型 参数名,)
{
//内容
}
# 裸函数
编译器不会自动编译(函数中不会有任何代码),通过__asm 可以写入汇编代码。一定记得写 ret,使函数执行后返回。
void _declspec(naked)/*设置为裸函数*/ hanshu()
{
__asm//汇编代码指令
{
ret//汇编代码 返回
}
}
# 实操(实现简单的功能)
在这里插入图片描述
void _declspec(naked)/*设置为裸函数*/ hanshu()
{
__asm//汇编代码指令
{
//保留栈底
push ebp
//提升堆栈
mov ebp,esp
sub esp,0x40
//保留现场
push ebx
push esi
push edi
//填充缓冲区
mov esx,0xCCCCCCCC//CC==int 3 中断指令
mov ecx,0x10
lea edi,dword ptr ds:[ebp-0x40]//算出后传给edi
rep stosd
//rep 根据ecx决定执行次数
// stosd 将eax的值存入edi指定的地址中,此时edi会自动加4个字节
//函数功能
mov eax,dword ptr ds:[ebp+0x8]
//ebp+0x4 是保留的栈底的值
add eax,dword ptr ds:[ebp+0xc]
//恢复现场
pop edi
pop esi
pop ebx
//降低堆栈
mov esp,ebp
pop ebp
ret//汇编代码 返回
}
}
# 调用约定
void _cdecl/*设置调用约定*/ hanshu(int x,int y)
{
}
_cdecl: 默认方式,从右到左压入,函数外平衡堆栈
_stdcall:从右到左压入,函数内平衡堆栈
-sam
ret 8
//8==esp+8
fastcall:从左到右压入,特点是快。但只有前两个分别压入 ecx、edx。其余的还需 push,流程类似于 stdcall。
# 数据类型 & 数据存储
三要素:
1. 存储数据的宽度
2. 存储数据的格式
3. 作用范围(作用域)
# 基本类型
# 整数类型:char short int long
char | 8bit | 1 字节 | byte |
---|---|---|---|
short | 16bit | 2 字节 | word |
int | 32bit | 4 字节 | dword |
long | 32bit | 4 字节 |
整数类型分为有符号(signed)和无符号(unsigned)。
1. 存储方式完全一致
2. 在做运算时需要注意
# 浮点类型
IEEE
# 数据存储
# 全局变量
写入时一般直接写到某固定地址的为全局变量,程序运行时就创建了
# 局部变量
写入时一般直接写到栈的偏移位置,函数运行时才会在堆栈中分配地址,
# 扩展
对于有符号和无符号的使用不同的扩展方式,保证数据真值正确。
# 结构体
# 注意点
1.struct(结构体),它等价于 int、char 等
2. 结构体之间可以相互调用,但不能调用自己,
3. 结构体在搭建的时候并不会分配空间,只有在调用的时候才会分配。
四:可以以套娃:比如一个调用 aa.bb.cc.dd.x(表示有四个结构体套娃)
# 重点
连续地址:
等宽 —— 数组
不等宽 —— 结构体
# sizeof
返回所占空间大小
可以是类型、变量、数组、结构体。
# 对齐问题
改变对齐字节个数
#pragma pack(x)//x可取:1、2、4、8
结构体{}
#pragma pack()