CSAPP第三章
gcc -Og(生成符合原始c代码结构的机器代码) -S(生成所对应的汇编文件) hello.c
在实际开发过程中,会选用-O1或者-O2这种优化选项。但是使用高级别优化生成的代码会严重变形,导致产生的机器代码和最初的源代码之间的关系难以理解
-C会生成机器码,可以用obgdump转为汇编代码查看
在汇编语言中,用.开头的行都是指导汇编器和链接
寄存器
整数寄存器文件:可以存放整形数据和地址,有的用来记录某些重要的程序状态,而其他的寄存器用来保存临时数据过程的参数和局部变量以及函数的返回值
条件码寄存器:保存cpu执行结果的属性,在执行算数和逻辑运算指令写入,可以用来实现if或者while语句。
CF:进位就置1
ZF:结果为零,置1
SF:符号标志,当最近的结果小于零时,置1
OF:溢出标志,溢出就置1
cmp指令:根据两个数的差来设置条件码寄存器,只设置条件码寄存器!
test指令:只设置条件码寄存器
向量寄存器可以用来存放整数和浮点数的数值
rax保存函数的返回值
rsp用来保存程序栈结束的位置
还有六个寄存器可以用来传递函数参数
调用者保存和被调用者保存寄存器
调用者保存寄存器:在函数a中调用函数b,函数a在调用函数b之前保存当前寄存器的数值,然后调用完再回复
被调用者保存寄存器:在函数a中调用函数b,在函数b的头部保存,尾部恢复。
指令
指令分为操作码和操作数
操作数:立即数,寄存器,内存引用
内存引用:当需要进行内存引用时,需要获得目的地址addr和数据长度b。Mb[addr]
进行一次内存引用:(立即数+基址寄存器)+(变址寄存器*比例因子)比例因子可以取值1,2,4,8。
栈区
用户进程的虚拟内存地址偏移最高的一片区域就是栈,栈从高地址向低地址生长。
pushq()用来压入栈,比如在main函数定义一个变量:相当于两个指令 subq(因为栈往下生长),movq
popq()把数据弹出删除,当局部变量释放时会用到:相当于两个指令movq和addq
有关于if的分支问题
if(x<y)
result = y-x;
else
result = x-y;
return result;
会根据x-y结果的条件码寄存器来判断顺序执行还是跳转执行,在现代处理器上,他的执行效率比较低。处理器会根据分支预测器来猜测跳转指令是否运行,发生错误预测的时候会浪费大量时间导致性能严重下降
可以用数据的条件转移来代替控制的条件转移
long result1 = y-x;
long result2 = x-y;
long ntest = (x>=y);
if(ntest)
result1 = result2
return result1;
该代码用到了cmovge:有条件的mov指令,但上一个程序用到了跳转指令
循环语句
循环语句是通过条件测试和跳转的结合来实现的。
for和while的底层实现基本一致
swich
在针对一个测试有多种不同的可能时,swich相当有用,switch通过一个跳转表,使实现更加有效,执行switch的时间和case的情况是无关的
函数调用
在函数p调用函数q的时候,当函数q执行,函数p这一条链上的函数都会被挂起
栈帧:每一次函数的调用,都会在调用栈上维护一个独立的栈帧