接下来的课程会涉及到计算机体系结构和汇编语言,解释C/C++代码片段是如何编译成汇编代码的,内存模型,函数调用,函数返回的类型等。
4字节变量的例子:
int i;
int j;
i=10;
j=i+7;
j++;
对应的汇编代码:
M[R1+4]=10;//store operation(将栈段中某个区域的值进行了更新)
R2=M[R1+4];//load operation
R3=R2+7;//ALU operation
M[R1]=R3;//store operation
R2=M[R1];
R2=R2+1;
M[R1]=R2;
注意:
1.大写的M代表整个RAM的名字,可以将整个RAM看做一个非常大的字节数组,M则是这个数组的名字,R1存储着基地址,4是偏移量。
2.不能直接进行M[R1]++操作,因为这里的汇编语言指令不允许任意内存地址作为ALU运算操作的操作数,必须先使用load操作,然后使用寄存器的值作为操作数执行ALU操作,然后再将结果写回内存中。这样的操作会令我们的汇编语言更加简单,并且当指令简单时,时钟频率也会较快。
3.默认情况下load、store以及ALU操作处理的都是4字节的数据,因为在C\C++语言中指针和int类型是非常常用的类型,因此硬件对这种4字节的内存的存取进行了优化。
非4字节变量的例子:
int i;
short s1;
short s2;
i=200;
s1=i;
s=s1+1;
对应的汇编代码:
M[R1+4]=200;
R2=M[R1+4];
M[R1+2]=.2 R2;//将寄存器R2中最低的2个字节的内容更新到M[R1+2]这个地址对应的内存
R2=.2 M[R1+2];
R3=R2+1;
M[R1]=.2 R3;
注意:
使用.2屏蔽掉默认处理4个字节这个规则,因为默认的规则假定所有这类的指令都隐含一个.4,当想要移动2个字节或者1个字节时就需要写上.2或者.1。
int arr[4];
int i;
for(i=0;i<4;i++) {
arr[i]=0;
}
i--;
对应的汇编代码:
M[R1]=0;
R2=M[R1];
BGE(R2,4,PC+40)//40为该行代码到跳出for循环的代码的距离乘以4
R3=M[R1];
R4=R3*4;//R4存储的是偏移量
R5=R1+4;//R5存储的是整个数组的基地址
R6=R4+R5;//R6存储着在这次的迭代中array中应该赋值为0的地址
M[R6]=0;
R2=M[R1];
R2=R2+1;
M[R1]=R2;
JMP PC-40//跳到第2行代码,相差10条指令,因此为10*4=40
//跳出for循环
R2=M[R1];
R2=R2-1;
M[R1]=R2;
注意:
1.分支指令(branch instructions)的缩写:BEQ,BNE,BLT,BLE,BGT,BGE。
2.在所有的汇编代码中都不能使用sizeof(int),必须手动计算C和C++中的类型所占空间大小。
指令编码:
R1=M[R2+4];//load指令
R1=1000;//立即数load指令
R3=R6*R10;//ALU指令
M[R1-20]=R19;//store指令
这四条指令的用6为字节表示opcode(也就是硬件能够看懂的01机器码)都不同,硬件会在时钟周期的前一部分查看前6位是什么,然后再决定如何解释剩下的26位。
struct fraction{
int num;
int denum;
}
struct fraction pi;
pi.num=22;
pi.denum=7;
((struct fraction*)&pi.denum)->denum=451;
对应的汇编代码:
M[R1+8]=451
M[R1]=22;
M[R1+4]=7;
在生成的汇编代码中是没有与强制类型转换相对应的指令,强制转换作用是只是允许编译器能够产生汇编代码。强制类型转换让编译器允许绕过类型检查的机制进而通过编译生成代码。