汇编语言综合研究——使用寄存器
王爽汇编语言综合研究 使用寄存器
1、使用寄存器编程
main函数是c语言编写程序的入口函数,但是main中的第一条语句并不是程序中被执行的第一条指令,还有很多其它语句。为了研究我们的程序编译后的语句,首先要找main函数的位置,可以通过下边的程序获得main函数的偏移地址
Main()
{
Printf(“%x\n”,main);
}
函数中printf语句表示以16进制打印main函数的指针
可以看到main函数的偏移地址为01Fah
2、尝试使用寄存器编程
Tc2.0编译环境中支持8086CPU中的寄存器名,可以编写下面的程序测试
Main()
{
_AX = 1;
_BX = 1;
_CX = 2;
_AX = _BX + _CX;
_AH = _BL + _CL;
_AL = _BH + _CH;
}
编译连接后用debug跟踪程序,反编译偏移地址为01FA的程序段,如图
分析:编译器对于赋值和加法的处理方式如下:
_AX = 1; => mov ax,0001
_AX = _BX + _CX => mov ax,bx
add ax,cx
进入函数后的push bp,mov bp,sp和后边的pop bp可以认为是c函数中可能用到bp寄存器而做的对bp寄存器保存现场操作
3、编译器对函数的处理
刚才的测试中,发现在pop bp后有一个ret指令,因为main函数是一个由操作系统调用的特殊的函数,可以猜想编译器对于函数的处理是写成子程序形式,编写程序验证
Void f(void);
Main()
{
_AX = 1;
_BX = 1;
_CX = 2;
f();
}
Void f()
{
_AX = _BX + _CX;
}
编译连接后用debug跟踪,反编译地址为01FA的程序段,如图
分析:
可以看到在赋值完成后有一条调用子程序的指令
Call 020B
之后是pop bp和ret,是main函数结束的标志
再看偏移地址为020B的程序段,可以分析出编译器对于将函数
void f()
{
_AX = _BX + _CX;
}
编译成了如下的子程序
Push bp
Mov bp,sp
Mov ax,bx
Add ax,cx
Pop bp
Ret
显然,刚才的猜想成立,而且容易发现,对于每个函数,编译器都会加入保存bp寄存器的指令
4、函数中对参数和返回值的处理
分析刚才打印main函数地址的程序
Main()
{
Printf(“%x\n”,main);
}
用debug反汇编到01FA处,如图
可以看到在对01FA(main函数的地址)和0194h入栈后执行了call 0AC0指令,可以猜想0AC0即是printf函数所在的位置。调用的方法是对所有参数入栈后调用。
可以编写一下程序验证是否是依次入栈。
int f(int,int);
Main()
{
_AX = 1;
_BX = 2;
_CX = F(_AX,_BX);
}
int f(int a,int b)
{
Return (a+b);
}
编译连接后反汇编,如图
可以看出,编译器对于参数的处理是从右往左依次入栈,函数的返回值保存于ax中