程序的机器级表示

来源:互联网 发布:淘宝雷锋侠怎么看 编辑:程序博客网 时间:2024/04/30 12:21
   编译程序的功能就是把用高级语言编写的程序翻译成与之等价的目标程序。现在汇编语言已经能够被机器所理解,而高级语言大多数必须要被翻译成汇编语言才能被程序理解,所以知道高级语言是怎么被翻译成汇编语言对程序员来说很有必要。本篇文章用C语言与汇编语言对比,简单的介绍下高级语言到汇编语言的过程。    先从C开始吧:
    int demo(){        int x = 10;        int y = 20;        int sum = add(&x,  &y);        printf(“the sum is %d\n”,sum);        return sum;    }    int add(int *xp, int *yp){        int x = *xp;        int y = *yp;        return x+y;    }
   这段简短的C程序很简单,在这里不做解释。现在来看看与这段程序的等价的汇编表示:
demo:1    pushl  %ebp2    movl   %esp %ebp3    subl   %24 esp4    movl   $10  -4(%ebp)5    movl   $20  -8(%ebp)6    leal   -8(%ebp) %eax7    movl   %eax 4(%esp)8    leal   -4(%ebp) %eax9    movl   %eax esp10   call addadd:1    pushl   %ebp2    movl    %esp %ebp3    pushl   %ebx4    movl    8(%ebp) %edx5    movl    12(%ebp) %ecx6    movl    (%edx) %ebx7    movl    (%ecx) %eax8    add     %ebx %eax9    popl    %ebx10   popl    %ebp11   ret
    这段程序实现的功能与上面那段C程序一样,但要看懂这段汇编,相信对于大多数初学者来说是有一定的难度的。为了读懂这段汇编程序,我们必须要有一定的知识储备:
MOVL $0x3051 ,%EAX;把0x3051这个值放到 EAX寄存器, 4个字节MOVL %EAX, -12(%EBP);把EAX的值,存放到EBP指的地址减去12个字节处                                           LEAL -12(%EBP)  %EAX;把 %EBP减去12得到的地址,放到EAX寄存器当中PUSHL %EBP;把寄存器EBP的值压栈POPL %EBP;把栈顶的值弹出, 存放到EBP寄存器中SUBL %4 %ESP;把ESP寄存器的值减去4
    好了,有了这些储备知识,再回过头来看这段汇编就容易懂得多了。这里必须要再提一下的是esp与ebp。esp是堆栈指针,ebp是基址指针,函数从硬盘读入内存,在进程的虚拟地址空间中会有一个个函数的栈帧,ebp指向函数的开始,esp指向函数的栈顶,在函数执行之前,进程管理会为函数的执行留够执行的空间。    好了,现在汇编函数开始执行了:
1    pushl  %ebp2    movl   %esp %ebp
     把寄存器ebp的值压栈,然后把esp的值存放到ebp指向的地址中去,假设现在esp与ebp的值都是800;  
3    subl   %24 esp
    把esp的值减去24,则现在esp的地址是776,这样做的目的是为这个函数划分执行时所要的地址空间。
4    movl   $10  -4(%ebp)5    movl   $20  -8(%ebp)
    在地址为796(800-4)的空间存入值为10的数据,在地址为792(800-8)的空间存入值为20的数据;
6    leal   -8(%ebp) %eax7    movl   %eax 4(%esp)8    leal   -4(%ebp) %eax9    movl   %eax esp
    把ebp减去8的地址存(792)放到eax寄存器中去,然后把eax的值存放到esp+4(780)的地方去。这样做了之后的结果就是:地址为780的空间中存入了792,注意,792是值20的地址;同理地址为776的地方存入了796;
10   call add
    调用add函数,这里会留下一个返回地址;
1    pushl   %ebp2    movl    %esp %ebp3    pushl   %ebx
    接着上面的函数来,把ebp压入栈,然后把esp的值存入ebp指向的地址,这时768的地址空间中存入了800;764的地址空间中存入了ebx的值。其余语句执行情况与demo类似,最后执行到:
8    add     %ebx %eax
    前面已经把ebp+8(也就是地址776)中的值存放到了edx寄存器中,把ebp+12(也就是地址780)的值存放到了ecx寄存器中,然后取地址,分别把10和20分别存放到了寄存器ebx和eax中,然后执行加法运算求得结果。
9    popl    %ebx10   popl    %ebp
    把返回地址弹出存入到了ebx中,把上一个函数的开始地址弹出存放到了ebp中,执行到这里,又到了demo的函数帧,然后会把运算的结果打印出来。至此,这个函数就执行完了。怎么样,对比着C程序,我觉得这段汇编程序更容易理解了。
0 0
原创粉丝点击