这次依然是从汇编开始分析C语言里的一些语法实现,这次还是Windows平台上为主~

直接上最简单的:

 1int z = 0;
 2char s1 = (char)z;
 3
 4// ASM
 5int* z = 0;
 6// 这次就直接显示符号名吧,不看内存地址了
 7// dword ptr就是数据类型声明
 8mov         dword ptr [z],0
 9char* s1 = (char*)z;
10// movzx这个指令,下面讲解,总之就是把z移动到eax寄存器.
11movzx       eax,byte ptr [z]
12// 直接粗暴的进行一个强转,al是AX的第八位,AX是EAX的低16位
13// mov指令要求操作数大小相等,byte ptr只占8个字节,所以这里用AL寄存器
14mov         byte ptr [s1],al

movzx这个指令简单来说就是把小字节操作数移动到大字节寄存器,同时让大字节的高位补零。

为什么这么设计,我们从上面这个movzx这行代码说起,[z]是byte ptr类型,只占用8位也就是1字节。

eax是32位寄存器,能存放4字节,[z]放进eax只能占用低八位,高24位完全用不到,这里就需要用到高位补零了,就是因为怕高位还有字节没清零的情况,导致后续计算直接崩了。


接着看指针运算,这个其实早就学过了,这次只是温故一下,理解指针运算很重要的一点就是在C语言中,数据类型其实毫无意义,所有东西都可以当作内存来看,只是一个内存分配大小的问题。

 1
 2	// Q: 为什么1能转换成指针?
 3	// A: 别惦记这你那逼数据类型了
 4	char* cp = (char*)1;
 5	// char* cp = 1
 6
 7	// cp被转化成int*了,指针指向位int类型,4字节,运算符在指针上的运算为位移,+2就意味着移动两格总计8字节
 8	// 所以i1的值是9
 9	// 简单来说类型转换,不会改变值,但是会改变运算方式
10	int i1 = (int)((int*)cp + 2);
11
12	// 这里也一样,i2为17
13	int* i2 = (int*)i1 + 2;
14
15	// short为2字节,但这里并非指针,只是普通的算术运算
16	// s = 95
17	short s = ((short)i2 + 2) * 5;
18
19	// 这里比较特别,i2被转化为2级指针,int**指向的类型是int*,指针类型占用的字节是8字节
20	// 所以是17 + 8 = 25
21	int** i3 = (int**)i2 + 1;

函数指针,这个东西主要就看看在汇编中是怎么实现的。

 1
 2add(1, 2);
 3call        add (07FF652F01311h)
 4
 5void* a = add;
 6// 实际也没什么特别的,就是把add的函数地址给了进去
 7lea         rax,[add (07FF6F9311311h)]
 8mov         qword ptr [a],rax
 9
10//我们也能做点其他的,比如把这个地址的数据读出来
11int* a = (int*)add;
12int as = *a; // 加*就是解引用,读里面的值, 不加*就只是读取内存地址

image.png

运行完后发现as的HEX值为0x00054ae9,我这台机器数值在内存中为小端存储,也就是e9 4a 05的酱紫存放.

进入到call add进去看看,是不是内存值也是这:

image.png

恩,实际上就是这样.

累死了,不写了。