自加运算(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;
}

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,所以容易绕晕,重点在于理解运算时,左运算数、右运算数准备到寄存器中,计算结果返回到相关变量中这一原则!!!

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <cmath>
 
using namespace std;
 
int main(){
    int a = 1,b = 1,c = 1;
    int d = a++ + b++ + c++;
    return 0;
}
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
cplus`main:	
    0x100000f60 <+0>:  pushq  %rbp
    0x100000f61 <+1>:  movq   %rsp, %rbp
    0x100000f64 <+4>:  xorl   %eax, %eax
    0x100000f66 <+6>:  movl   $0x0, -0x4(%rbp)
    0x100000f6d <+13>: movl   $0x1, -0x8(%rbp)
    0x100000f74 <+20>: movl   $0x1, -0xc(%rbp)
    0x100000f7b <+27>: movl   $0x1, -0x10(%rbp)
 
    0x100000f82 <+34>: movl   -0x8(%rbp), %ecx;取出a【第1个+运算的左运算数】
    0x100000f85 <+37>: movl   %ecx, %edx
    0x100000f87 <+39>: addl   $0x1, %edx;a++
    0x100000f8a <+42>: movl   %edx, -0x8(%rbp);结果返回变量中
 
    0x100000f8d <+45>: movl   -0xc(%rbp), %edx;取出b【第1个+运算的右运算数】
    0x100000f90 <+48>: movl   %edx, %esi
    0x100000f92 <+50>: addl   $0x1, %esi;b++
    0x100000f95 <+53>: movl   %esi, -0xc(%rbp);结果返回变量中
 
    0x100000f98 <+56>: addl   %edx, %ecx;执行第1个+运算(1+1=2)【第2个+运算的左运算数】
 
    0x100000f9a <+58>: movl   -0x10(%rbp), %edx;取出c【第2个+运算的右运算数】
    0x100000f9d <+61>: movl   %edx, %esi
    0x100000f9f <+63>: addl   $0x1, %esi;c++
    0x100000fa2 <+66>: movl   %esi, -0x10(%rbp);结果返回变量中
 
    0x100000fa5 <+69>: addl   %edx, %ecx;执行第2个+运算(2+1=3)
 
    0x100000fa7 <+71>: movl   %ecx, -0x14(%rbp);结果返回变量中
    0x100000faa <+74>: popq   %rbp
    0x100000fab <+75>: retq

4、索性再来一个++a的吧
4.1、C++及AT&A汇编

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <cmath>
 
using namespace std;
 
int main(){
    int a = 1,b = 1,c = 1;
    int d = ++a + ++a + ++a;
    return 0;
}
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
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)
    0x100000f84 <+20>: movl   $0x1, -0xc(%rbp)
    0x100000f8b <+27>: movl   $0x1, -0x10(%rbp)
    ;第1个a++
    0x100000f92 <+34>: movl   -0x8(%rbp), %ecx
    0x100000f95 <+37>: addl   $0x1, %ecx
    0x100000f98 <+40>: movl   %ecx, -0x8(%rbp)
    ;第2个a++
    0x100000f9b <+43>: movl   -0x8(%rbp), %edx
    0x100000f9e <+46>: addl   $0x1, %edx
    0x100000fa1 <+49>: movl   %edx, -0x8(%rbp)
    ;(a++)+(a++)
    0x100000fa4 <+52>: addl   %edx, %ecx
    ;第3个a++
    0x100000fa6 <+54>: movl   -0x8(%rbp), %edx
    0x100000fa9 <+57>: addl   $0x1, %edx
    0x100000fac <+60>: movl   %edx, -0x8(%rbp)
    ;((a++)+(a++))+(a++)
    0x100000faf <+63>: addl   %edx, %ecx
    ;返回值
    0x100000fb1 <+65>: movl   %ecx, -0x14(%rbp)
    0x100000fb4 <+68>: popq   %rbp
    0x100000fb5 <+69>: retq

4.2、8086汇编

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
41
42
43
44
45
46
47
48
49
assume ss:stack, ds:data, cs:code
 
stack segment
     db 20h dup(0cch)
stack ends
 
data segment
     db 20h dup(0cch)
data ends
 
code segment
start:
     mov ax, stack
     mov ss, ax
     mov sp, 20h
     mov ax, data
     mov ds, ax
 
     push bp
     mov bp, sp
     sub sp, 10h  
     ;------业务代码----Begain
     ;int a = 1;   
     ;int b = ++a + ++a + ++a;
     mov word ptr [bp-2], 1h
     ;第1个++运算【第1个+左运算数】
     mov ax, [bp-2]
     add ax, 1h
     mov word ptr [bp-2], ax
     ;第2个++运算【第1个+右运算数】
     mov bx, [bp-2]
     add bx,1h
     mov word ptr [bp-2], bx
 
     add ax, bx;第1个+运算【第2个+左运算数】
     ;第3个++运算【第2个+右运算数】
     mov bx, [bp-2]
     add bx, 1h
     mov word ptr [bp-2], bx
 
     add ax, bx;第2个+运算【返回值,或下一个左运算数】
     mov word ptr [bp-4], ax;返回值赋给b                            
     ;------业务代码----End
 
     ;Exit
     mov ah, 4ch
     int 21h
code ends
end start

2 thoughts on “自加运算(a++)在汇编中的实现

  1. Sian Post author

    8086汇编版本二(完整版):
    1、一元运算与二元运算均统一步骤:取值–>运算–>回写
    1.1、取第1次+左运算数到ax【第1次+左运算数】(取值a=1)
    1.2、准备执行第1次++操作,在bx中完成,运算完成后回写到变量中【第1次+左运算数++】
    1.3、取第1次+右运算数到bx【第1次+右运算数】(取值a=2)
    1.4、准备执行第2次++操作,在cx中完成,运算完成后回写到变量中【第1次+右运算数++】(a=3)
    1.5、执行第1次+运算,运算结果返回在ax中【第2次+左运算数】(1+2=3)
    1.6、取第2次+右运算数到bx【第2次+右运算数】(a=3)
    1.7、准备执行第3次++操作,在cx中完成,运算完成后回写到变量中(a=4)
    1.8、执行第2次+运算,运算结果返回在ax中(3+3=6)
    1.9、返回结果存在变量中(b=6)

    assume ss:stack, ds:data, cs:code
     
    stack segment
        db 20h dup(0AAH)
    stack ends          
     
    data segment    
        db 20h dup(0BBH)
    data ends
     
    code segment
    start:
        ;初始化
        mov ax, stack
        mov ss, ax
        mov sp, 20h
        mov ax, data
        mov ds, ax
     
        call func
     
        mov ah, 4ch
        int 21h
     
    func:  ;实现int b = a++ + a++ + a++;
        push bp
        mov bp, sp
        sub sp, 10h
     
        ;int a = 1 
        mov word ptr [bp-2], 1h  
     
        mov ax, [bp-2];(a=1)[第1个+的左运算数] 
        mov bx, ax;(a=1)[a++运算寄存器]
        add bx, 1h;a++(第1个++)
        mov word ptr [bp-2], bx;(a=2)[值回写到变量中]
     
        mov bx, [bp-2];取第1个+的右运算数[第1个+的右运算数] 
        mov cx, bx;准备该运算数的++运算
        add cx, 1h;a++(第2个++)
        mov word ptr [bp-2], cx;(a=3)[值回写到变量中] 
     
        add ax, bx;第1次+运算[第2个+运算的左运算数]
     
        mov bx, [bp-2];[第2个+运算的右运算数] 
        mov cx, bx;准备该运算数的++运算
        add cx, 1h;a++(第3个a++)  
        mov word ptr [bp-2], cx;(a=4)[值回写到变量中] 
     
        add ax, bx;第2次+运算[返回值]
        ;int b = 6
        mov word prt [bp-4], ax;(b = 6)
     
        ;恢复、返回
        mov sp, bp
        pop bp
        ret
    code ends
    end start

  2. Sian Post author

    8086汇编版本一(简化版):
    1、ax、bx两个寄存器分别存储运算的左运算数与右运算数
    2、运算基本步骤(后置++的优先级小于+运算,因此左运算数在运算前不能自加)
    2.1、取a的值到ax寄存器(1)【第1个+的左运算数】
    2.2、取a的值到bx寄存器(1)
    2.3、执行第1次a++运算,直接bx寄存器+1(2)【第1个+的右运算数】
    2.4、执行第1个+运算,结果返回到ax寄存器(1+2=3)【返回值】【第2个+的左运算数】
    2.5、执行第2次a++运算,直接bx寄存器+1(3)【第2个+的右运算数】
    2.6、执行第2个+运算,结果返回到ax寄存器(3+3=6)【返回值】
    2.7、执行第3次a++运算,直接bx寄存器+1(4)

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    
    assume ss:stack, ds:data, cs:code
     
    stack segment
        db 20h dup(0AAH)
    stack ends          
     
    data segment    
        db 20h dup(0BBH)
    data ends
     
    code segment
    start:
        ;初始化
        mov ax, stack
        mov ss, ax
        mov sp, 20h
        mov ax, data
        mov ds, ax
     
        call func
     
        mov ah, 4ch
        int 21h
     
    func:  ;实现int b = a++ + a++ + a++;
        push bp
        mov bp, sp
        sub sp, 10h
     
        ;int a = 1 
        mov word ptr [bp-2], 0001h  
     
        mov ax, [bp-2];(a=1)[第1个+的左运算数]
        mov bx, ax;(a=1)[a++运算寄存器]
     
        add bx, 1;a++(第1个++)
        mov word ptr [bp-2], bx;(a=2)[第1个+的右运算数] 
     
        add ax, bx;第1次+运算[第2个+运算的左运算数]
     
        add bx, 1;a++(第2个++)
        mov word ptr [bp-2], bx;(a = 3)[第2个+运算的右运算数]
     
        add ax, bx;第2次+运算[返回值]
     
        add bx, 1;a++(第3个++)
        mov word ptr [bp-2], bx;(a = 4)
     
        ;int b = 6
        mov word prt [bp-4], ax;(b = 6)
     
        ;恢复、返回
        mov sp, bp
        pop bp
        ret
    code ends
    end start

Leave a Reply