现在的位置: 首页 > 综合 > 正文

汇编语言综合研究——使用寄存器

2018年01月22日 ⁄ 综合 ⁄ 共 1651字 ⁄ 字号 评论关闭

王爽汇编语言综合研究 使用寄存器

 

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 bpret,是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处,如图

      

可以看到在对01FAmain函数的地址)和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

抱歉!评论已关闭.