Monthly Archives: October 2018

C++中if…else…与for(…)在汇编中的实现

1、编写两个简单的条件语句来反汇编一下看最终机器是如何工作的,以下示例是在XCode中反汇编的,即AT&T汇编,8086或win32也是相同的原理
1.1、if…else…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cmath>
 
using namespace std;
 
int main(){
    int a = 0;
    int b = 0;
    if (a > 0){
        b = 1;
    }else{
        b = 2;
    }
    return 0;
}</cmath></iostream>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cplus`main:
    0x100000f70 <+0>:  pushq  %rbp
    0x100000f71 <+1>:  movq   %rsp, %rbp
    0x100000f74 <+4>:  movl   $0x0, -0x4(%rbp)
    0x100000f7b <+11>: movl   $0x0, -0x8(%rbp);int a
    0x100000f82 <+18>: movl   $0x0, -0xc(%rbp);int b
 
    ;if...else...开始
    ;1、小于或等于则跳转到3【0x100000f9f】
    0x100000f89 <+25>: cmpl   $0x0, -0x8(%rbp)
    0x100000f8d <+29>: jle    0x100000f9f
 
    ;2.1、符合条件则执行if条件下的代码
    0x100000f93 <+35>: movl   $0x1, -0xc(%rbp);b=1
    ;2.2、执行结束后直接跳转到结尾
    0x100000f9a <+42>: jmp    0x100000fa6
 
    ;3、else条件下的代码
    0x100000f9f <+47>: movl   $0x2, -0xc(%rbp);b=2
    ;if...else...结束
 
    0x100000fa6 <+54>: xorl   %eax, %eax
    0x100000fa8 <+56>: popq   %rbp
    0x100000fa9 <+57>: retq

1.2、for(…;…;…)[……]

继续阅读

自加运算(a++)在汇编中的实现

1、C++源代码

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <cmath>
 
using namespace std;
 
int main(){
    int a = 1;
    int b = a++ + a++ + a++;
    return 0;
}</cmath></iostream>

2、xCode中汇编结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
cplus`main:
 0x100000f70 <+0>:  pushq  %rbp
 0x100000f71 <+1>:  movq   %rsp, %rbp
 0x100000f74 <+4>:  xorl   %eax, %eax
 0x100000f76 <+6>:  movl   $0x0, -0x4(%rbp)
 0x100000f7d <+13>: movl   $0x1, -0x8(%rbp);设置局部变量(a=1)
 
 ;第一步(左运算值)%ecx
 0x100000f84 <+20>: movl   -0x8(%rbp), %ecx;取出变量值(1)[准备第一个+号左运算]
 
 0x100000f87 <+23>: movl   %ecx, %edx;准备第一次a++
 0x100000f89 <+25>: addl   $0x1, %edx;a++
 0x100000f8c <+28>: movl   %edx, -0x8(%rbp);第一次a++结果返回变量中(2)
 
 ;第二步(右运算值)%edx
 0x100000f8f <+31>: movl   -0x8(%rbp), %edx;取出第一次++的结果(2)[第一个+号右运算]
 
 0x100000f92 <+34>: movl   %edx, %esi;准备第二次a++
 0x100000f94 <+36>: addl   $0x1, %esi;a++
 0x100000f97 <+39>: movl   %esi, -0x8(%rbp);第二次a++结果返回变量中(3)
 
 ;第三步(第一个+运算)(返回值)%ecx
 0x100000f9a <+42>: addl   %edx, %ecx;运算第一个+号(1+2=3)[运算返回值,第二个+号的左运算值]
 
 ;第四步(右运算值)%edx
 0x100000f9c <+44>: movl   -0x8(%rbp), %edx;取出第二次a++后的结果(3)[第二个+号的右运算值]
 
 0x100000f9f <+47>: movl   %edx, %esi;准备第三次a++
 0x100000fa1 <+49>: addl   $0x1, %esi;a++
 0x100000fa4 <+52>: movl   %esi, -0x8(%rbp);第三次a++结果返回变量中(4)
 
 ;第五步(第二个+运算)(返回值)%ecx
 0x100000fa7 <+55>: addl   %edx, %ecx;运算第二个+号(3+3=6)[运算返回值]
 
 ;第六步(运算结束,赋值)
 0x100000fa9 <+57>: movl   %ecx, -0xc(%rbp);结果传给局部变量(c=6)
 
 
 0x100000fac <+60>: popq   %rbp
 0x100000fad <+61>: retq

3、如果对上述理解有一点难度,可以简化一下过程,因为都是a,所以容易绕晕,重点在于理解运算时,左运算数、右运算数准备到寄存器中,计算结果返回到相关变量中这一原则!!![……]

继续阅读

AT&T汇编中函数的基本实现

1、8086汇编参考链接:
1.1、函数调用原理–参数篇
1.2、函数调用原理–局部变量篇
1.3、函数调用原理–完善篇(栈帧)

2、简单C++代码

1
2
3
4
5
6
#include 
#include 
 
using namespace std;
 
int sum(int a, int b[......]<p class="read-more"><a href="https://www.yusian.com/blog/assembler/2018/10/25/2113381314.html">继续阅读</a></p>

函数调用原理–完善篇(栈帧)

1、参考链接:
1.1 函数调用原理–参数篇
1.2 函数调用原理–局部变量

2、局部变量空间分配后没有初始化,可能会出现异常访问而出现不可预知的错误,因为分配的临时空间必须初始化;
2.1、将每个字节都初始化为CC其中一种安全策略,因为CC在汇编指令中为int 3,即中断指令。
2.2、stosb/stosw指定能将es:di指向的空间写入ax寄存器中的值,并在执行结束后将di自加1字节/2字节
2.3、rep会循环指定后一条指令,循环次数从cx寄存器中取,如果为0则退出循环

3、汇编代码实现[……]

继续阅读

函数调用原理–局部变量篇

1、参考链接
1.1、函数调用原理–参数篇

2、函数需要解决的三大问题:参数、返回值、局部变量
2.1、参数在函数执行前压栈,执行结束后恢复内平栈或外平栈的方式恢复栈顶位置释放空间;
2.2、返回值一般直接存储在寄存器ax中,函数运行结束后在ax中读取
2.3、函数内部的局部变量也是通过栈来存储

3、函数局部变量面临的几个问题
3.1、专用空间,不被其他数据覆盖;
3.2、对栈进行操作,结束后需要对栈进行恢复操作;
3.3、临时空间使用结束后及时释放

4、基本实现思路
4.1、保存栈顶位置(sp);
4.2、将栈顶位置往前移动一段位置做为局部变量专有空间;
4.3、通过原栈顶+偏移位置(bp寄存器)来访问专用的临时空间;
4.4、结束后恢复原来栈顶位置;
4.5、考虑到函数的嵌套调用,保护和恢复bp同样重要!

5.0、汇编代码实现[……]

继续阅读