• x86汇编语言实践(3)


    0 写在前面

      为了更深入的了解程序的实现原理,近期我学习了IBM-PC相关原理,并手工编写了一些x86汇编程序

      在2017年的计算机组成原理中,曾对MIPS体系结构及其汇编语言有过一定的了解,考虑到x86体系结构在目前的广泛应用,我通过两个月左右的时间对x86的相关内容进行了学习。

      在《x86汇编语言实践》系列中(包括本篇、x86汇编语言实践(1)x86汇编语言实践(2)x86汇编语言实践(4)以及x86汇编语言复习笔记),我通过几个具体案例对x86汇编语言进行实践操作,并记录了自己再编写汇编代码中遇到的困难和心得体会,与各位学习x86汇编的朋友共同分享。

      我将我编写的一些汇编代码放到了github上,感兴趣的朋友可以点击屏幕左上角的小猫咪进入我的github,或请点击这里下载源代码。

    1 递归调用计算N!

    1-1 练习要点

    • 递归调用

    • 栈指针的维护

    • 子程序编写与调用

    1-2 实现思路

    • 在数据段存储好待计算的N,和用以存储计算结果的RESULT

    • 主程序中首先将N和RESULT压栈

    • 调用CALCULATE进行阶乘的递归计算

    • 结果返回至RESULT

    • 调用DISP_VALUE打印输出阶乘计算结果

    1-3 重点难点

    • 参数传递:使用堆栈进行参数传递,需要将参数压栈,注意子程序返回时,必须增加一个常数偏移量RET X。这里的X为压入参数所占的字节数,通常为2的倍数,以保证堆栈平衡

    • 子程序保存现场:在子程序中,往往要用到很多寄存器,但我们希望在子程序返回时,调用子程序位置处周围的变量仍能恢复,这就需要在调用的子程序中保存现场,即子程序中所用到或修改的所有寄存器,都必须压栈处理

    • 子程序中的堆栈寻址:使用BP寄存器寻址,这是为了不修改SP指针,避免弄乱堆栈栈顶指针SP

    • 中间一直困扰我的就是在子程序中获取参数N的方式MOV BX,[BP+6]为什么是BP+6呢?我们来看,BP保存的是子程序中的SP指针,但是距离我们将N压栈之间,我们经历了:将RESULT压栈、调用时将调用处的IP+2压栈以及将BP压栈,三个过程。因此当前的BP和N之间相差了6个字节的距离,故采用[BP+6]的方式进行参数N的寻址

    • 输出上的改进:仍是除10显示,但这次保存余数。为了得到正序输出,将每次的余数压栈,这样在显示的时候就是从高位向低位显示了。此外,在输出时对前导0进行了过滤处理,需要注意的是当遇到第一个非0数字后,需要将标志位置1,这样以后的数字0就可以正常显示。

    1-4 代码实现

     1 STACK     SEGMENT    PARA    STACK
     2         DW        100H DUP(?)
     3 STACK    ENDS
     4 
     5 DATA    SEGMENT    PARA
     6     N     DW    7
     7     RESULT     DW     ?         
     8 DATA     ENDS
     9 
    10 CODE     SEGMENT PARA
    11         ASSUME    CS:CODE,DS:DATA,SS:STACK
    12 CALCULATE PROC NEAR
    13     CAL_PART:
    14         PUSH    BP
    15         MOV     BP,SP
    16         PUSH     DX
    17         PUSH     BX
    18 
    19         MOV     BX,[BP+6]
    20         CMP     BX,0
    21         JNZ     CAL1
    22         MOV     AX,1
    23         JMP     SHORT CAL2
    24     CAL1:
    25         PUSH     BX
    26         DEC     BX
    27         PUSH     BX
    28         PUSH     RESULT
    29         CALL     CALCULATE
    30         POP     BX
    31         MUL        BX        
    32     CAL2:
    33         MOV     RESULT,AX
    34         POP         BX
    35         POP     DX
    36         POP        BP
    37         RET     4
    38 CALCULATE ENDP
    39 
    40 DISP_VALUE PROC
    41     DISPLAY:
    42         PUSH     DX
    43         PUSH     CX
    44         PUSH    BX
    45         PUSH     AX
    46 
    47         MOV     CX,5
    48         MOV     BX,10
    49 
    50     DLP1:
    51         XOR     DX,DX
    52         DIV     BX
    53         PUSH     DX
    54         LOOP     DLP1
    55 
    56         MOV     BX,0
    57         MOV     CX,5
    58     DLP2:
    59         POP     DX
    60         CMP     DL,0
    61         JNZ     DLP2_1
    62         CMP     BX,0
    63         JZ         DLP2_2
    64     DLP2_1:
    65         MOV     BX,1
    66         OR         DL,30H
    67         MOV     AH,2
    68         INT      21H
    69     DLP2_2:
    70         LOOP     DLP2
    71 
    72         POP     AX
    73         POP     BX
    74         POP     CX
    75         POP     DX
    76         RET
    77 DISP_VALUE ENDP
    78 
    79 
    80 MAIN    PROC     FAR
    81     MAINPROC:
    82         MOV     AX,DATA
    83         MOV     DS,AX
    84 
    85         MOV     AX,N
    86         PUSH     AX
    87         PUSH     RESULT
    88         CALL     CALCULATE
    89         MOV     AX,RESULT
    90         CALL     DISP_VALUE    
    91 
    92     EXIT:    
    93         MOV     AX,4C00H
    94         INT     21H
    95 MAIN     ENDP
    96 CODE     ENDS
    97         END     MAIN

    1-5 实现效果截图

    1-5-1 计算N=7时的阶乘计算结果

       

      经验证,发现输出结果符合预期。

    1-5-2 查看递归调用到N=4时的堆栈信息

       

      从上面单步执行的寄存器结果中可以看出,BX=4即此时已经执行到N=4,此时堆栈指针SP位于01d2。我们来分析一下,当前堆栈中的内容

    • ss:1d2 压入RESULT作为参数向递归函数中传递,值为0

    • ss:1d4 压入BX(这里也就是N=4)作为参数向递归函数中传递,值为4

    • ss:1d6 保存的减一之前的N,这是为了在子程序返回时能计算N*AX返回结果

    • ss:1d8 子程序开始是压入的BX保存的值,值为5

    • ss:1da 子程序开始是压入的DX保存的值,值为0

    • ss:1dc 子程序开始是压入的BP保存的值,值为1ea

    • ss:1de CALL子程序会保存调用处下一条指令的IP并压栈,值为1c,即该子程序返回后会跳转至1c(+偏移值)

    2 练习子程序参数传递的两种方法

    2-1 练习要点

    • 子程序的编写

    • 使用寄存器向子程序传递参数

    • 使用堆栈向子程序传递参数

    • 复习乘法计算子程序,字符串拷贝子程序,字符串比较子程序,查找子程序

    • 选做部分我练习的是将字符串中全部的大写字母替换成小写字母

    2-2 重点难点

    • 寄存器传参比较简单,将用到参数的寄存器保存为相应的参数值即可完成参数传递

    • 堆栈传参需要注意以下几点

      • 压栈顺序一定要注意,在压入多个参数时,需要记住其相对于SP的相对位置,从而避免取出参数时的混乱

      • 子程序中对参数的索引采用BP指针代替SP指针进行寻址,从而避免改变栈顶SP指针引发的紊乱现象发生

      • 返回时需要加上一个常数偏移量,将压入栈中的参数位置地址恢复,从而维持堆栈平衡

    2-3 实现思路

    • 首先为输入和输出单独编写子程序,程序主体采用跳转表实现

    • 为每一个条件单独编写一个子程序,有10中条件(A-E为堆栈传参子程序,a-e为寄存器传参子程序),因此共需编写10个子程序分别对应着实现响应功能

    • 在最外层设置循环结构,使得程序能够处理多组输入

    • 字符串、数据、参数等初始化设置在数据段完成即可

    2-4 代码实现

      1 STACK     SEGMENT    PARA    STACK
      2         DW        100H DUP(?)
      3 STACK    ENDS
      4 
      5 DATA    SEGMENT    PARA
      6     LEN     EQU 7
      7     N        EQU 10    ;TIMES OF LOOP
      8     X        DW     7
      9     Y        DW  8
     10     Z        DW     ?
     11     STRING1 DB    'QIQI',20H,0,'$'
     12     STRING2 DB    'CHEN',20H,0,'$'    
     13     CHAR     DB    'C'
     14     OP         DB     ?
     15     NL        DB     13,10,'$'
     16     MSGEQ     DB     'STRING1=STRING2',13,10,'$'
     17     MSGGT     DB     'STRING1>STRING2',13,10,'$'
     18     MSGLT   DB     'STRING1<STRING2',13,10,'$'
     19     DOFOUND DB    'CHAR FOUND IN STRING2',13,10,'$'
     20     NOTFOUND DB 'CHAR NOT FOUND IN STRING2',13,10,'$'
     21 DATA     ENDS
     22 
     23 CODE     SEGMENT PARA
     24         ASSUME    CS:CODE,DS:DATA,SS:STACK
     25 ;PRINT A NEWLINE
     26 NEWLINE MACRO
     27     PUSH      DX
     28     PUSH     AX
     29     MOV        DX,OFFSET NL
     30     MOV     AH,9
     31     INT     21H
     32     POP     AX
     33     POP         DX
     34     ENDM
     35 ;GET OPERATION TO OP
     36 GETOP     MACRO
     37     GETOPM:
     38         MOV     AH,1
     39         INT     21H
     40         MOV     OP,AL
     41         ENDM
     42 ;OUTPUT MSG
     43 OUTPUT     MACRO MSG
     44     PUSH     DX
     45     PUSH     AX
     46     MOV     DX,OFFSET MSG
     47     MOV     AH,9
     48     INT     21H
     49     POP     AX
     50     POP     DX
     51     ENDM
     52 ;DISPLAY VALUE IN AX
     53 DISP_VALUE PROC
     54     DISPLAY:
     55         PUSH     DX
     56         PUSH     CX
     57         PUSH    BX
     58         PUSH     AX
     59 
     60         MOV     CX,5
     61         MOV     BX,10
     62 
     63     DLP1:
     64         XOR     DX,DX
     65         DIV     BX
     66         PUSH     DX
     67         LOOP     DLP1
     68 
     69         MOV     BX,0
     70         MOV     CX,5
     71     DLP2:
     72         POP     DX
     73         CMP     DL,0
     74         JNZ     DLP2_1
     75         CMP     BX,0
     76         JZ         DLP2_2
     77     DLP2_1:
     78         MOV     BX,1
     79         OR         DL,30H
     80         MOV     AH,2
     81         INT      21H
     82     DLP2_2:
     83         LOOP     DLP2
     84 
     85         NEWLINE
     86         POP     AX
     87         POP     BX
     88         POP     CX
     89         POP     DX
     90         RET
     91 DISP_VALUE ENDP
     92 
     93 DISP_STR2 PROC
     94     PRINTSTR2:
     95         PUSH     DX
     96         MOV     DX,OFFSET STRING2
     97         MOV     AH,9
     98         INT     21H
     99         NEWLINE
    100         POP     DX
    101         RET
    102 DISP_STR2 ENDP
    103 
    104 MULTIPLE PROC
    105     MULTI:
    106         PUSH     BP
    107         MOV     BP,SP
    108         PUSH     AX
    109         PUSH     BX
    110 
    111         MOV     AX,[BP+4]
    112         MOV     BX,[BP+6]
    113         MUL     BX
    114         MOV     Z,AX
    115 
    116         POP     BX
    117         POP     AX
    118         POP     BP
    119 
    120         RET     4
    121 MULTIPLE ENDP
    122 
    123 MULTIPLE2 PROC
    124     MULTI2:
    125         MUL     BX
    126         MOV     Z,AX
    127         RET
    128 MULTIPLE2 ENDP
    129 
    130 STRCPY PROC
    131     STRCPYPROC:
    132         PUSH     BP
    133         MOV     BP,SP
    134 
    135         PUSH     DI 
    136         PUSH     SI
    137         MOV     SI,[BP+4]
    138         MOV        DI,[BP+6]
    139 
    140         CLD
    141     CPYLP:
    142         LODSB
    143         STOSB
    144         CMP     AL,0
    145         JNZ     CPYLP
    146         POP     SI
    147         POP     DI
    148         POP     BP
    149         RET     4
    150 STRCPY ENDP
    151 
    152 STRCPY2 PROC
    153     STRCPY2PROC:
    154         CLD
    155     CPYLP2:
    156         LODSB
    157         STOSB
    158         CMP     AL,0
    159         JNZ     CPYLP2
    160         RET
    161 STRCPY2 ENDP
    162 
    163 STRCMP     PROC
    164     STRCMPROC:
    165         PUSH     BP
    166         MOV     BP,SP
    167 
    168         PUSH     DI
    169         PUSH     SI
    170 
    171         MOV     SI,[BP+4]
    172         MOV     DI,[BP+6]
    173         CALL     STRCMP2
    174 
    175         POP     SI
    176         POP     DI
    177         POP     BP
    178         RET     4
    179 STRCMP     ENDP
    180 
    181 STRCMP2 PROC
    182     STRCMP2PROC:
    183         PUSH     CX
    184         PUSH     SI
    185         CLD
    186         PUSH     SI
    187         MOV     CX,1
    188     CMPLP2:
    189         LODSB
    190         CMP     AL,0
    191         JZ         CMPLPBEG2
    192         INC     CX
    193         JMP     SHORT CMPLP2
    194     CMPLPBEG2:
    195         POP     SI
    196         REPE     CMPSB
    197         JA         L2_1
    198         JB         L2_2
    199         OUTPUT     MSGEQ
    200         JMP     SHORT CMPRET2
    201     L2_1:
    202         OUTPUT     MSGGT
    203         JMP     SHORT CMPRET2
    204     L2_2:
    205         OUTPUT     MSGLT
    206     CMPRET2:
    207         POP      SI
    208         POP     CX
    209         RET
    210 STRCMP2 ENDP
    211 
    212 FIND PROC
    213     FINDCHAR:
    214         PUSH     BP
    215         MOV         BP,SP
    216         PUSH     CX
    217 
    218         MOV     DI,[BP+6]
    219         MOV     CX,LEN
    220         DEC     CX
    221         MOV     AX,[BP+4]
    222         CLD
    223         REPNZ     SCASB
    224         JZ     FOUND
    225         OUTPUT     NOTFOUND
    226         JMP     SHORT FIND_RETURN
    227     FOUND:
    228         OUTPUT     DOFOUND
    229     FIND_RETURN:
    230         POP     CX
    231         POP     BP
    232         RET        4
    233 FIND ENDP
    234 
    235 FIND2 PROC
    236     FIND2PROC:
    237         PUSH     CX
    238         PUSH     DI
    239         MOV     CX,LEN
    240         DEC     CX
    241         CLD
    242         REPNZ     SCASB
    243         JZ         FOUND2
    244         OUTPUT     NOTFOUND
    245         JMP     SHORT FIND2RETURN
    246     FOUND2:
    247         OUTPUT     DOFOUND
    248     FIND2RETURN:
    249         POP     DI
    250         POP     CX
    251         RET
    252 FIND2 ENDP
    253 
    254 TOLOWER PROC
    255     TOLOW:
    256         PUSH     BP
    257         MOV     BP,SP
    258         PUSH     SI
    259         PUSH     DI
    260         PUSH     CX
    261         PUSH     AX
    262 
    263         MOV     SI,[BP + 4]
    264         MOV     DI,SI
    265         MOV     CX,LEN
    266         CLD
    267     TOLOW_LP:
    268         LODSB
    269         CMP     AL,'A'
    270         JB         TOLOW_CONTINUE
    271         CMP     AL,'Z'
    272         JA         TOLOW_CONTINUE
    273         ADD     AL,20H
    274     TOLOW_CONTINUE:
    275         STOSB
    276         LOOP     TOLOW_LP
    277         
    278         POP     AX
    279         POP     CX
    280         POP     DI
    281         POP     SI
    282         POP     BP
    283         RET     2
    284 TOLOWER ENDP
    285 
    286 TOLOWER2 PROC
    287     TOLOW2:
    288         PUSH     SI
    289         PUSH     DI
    290         PUSH     CX
    291         PUSH     AX
    292         MOV     DI,SI
    293         MOV     CX,LEN
    294         DEC     CX
    295         CLD
    296     TOLOW_LP2:
    297         LODSB
    298         CMP     AL,'A'
    299         JB         TOLOW_CONTINUE2
    300         CMP     AL,'Z'
    301         JA         TOLOW_CONTINUE2
    302         ADD     AL,20H
    303     TOLOW_CONTINUE2:
    304         STOSB
    305         LOOP     TOLOW_LP2
    306         POP     AX
    307         POP     CX
    308         POP     DI
    309         POP     SI
    310         RET
    311 TOLOWER2 ENDP
    312 
    313 SWITCH     PROC
    314     SWITCHPROC:
    315         PUSH     CX
    316     S0:
    317         CMP     OP,'A'
    318         JNE        S1
    319         PUSH     X
    320         PUSH     Y
    321         CALL     MULTIPLE
    322         MOV     AX,Z
    323         CALL     DISP_VALUE
    324         JMP     CONTINUE
    325     S1:
    326         CMP     OP,'B'
    327         JNE        S2
    328         MOV     DX,OFFSET STRING2
    329         PUSH     DX
    330         MOV     DX,OFFSET STRING1
    331         PUSH     DX
    332         CALL     STRCPY
    333         OUTPUT     STRING2
    334         NEWLINE
    335         JMP     CONTINUE
    336     S2:
    337         CMP     OP,'C'
    338         JNE        S3
    339         MOV     DX,OFFSET STRING2
    340         PUSH     DX
    341         MOV     DX,OFFSET STRING1
    342         PUSH     DX
    343         CALL     STRCMP
    344         JMP     CONTINUE
    345     S3:
    346         CMP     OP,'D'
    347         JNE        S4
    348         MOV     DX,OFFSET STRING2
    349         PUSH     DX
    350         MOV     DL,CHAR
    351         XOR     DH,DH
    352         PUSH     DX
    353         CALL     FIND
    354         JMP     CONTINUE
    355     S4:
    356         CMP     OP,'E'
    357         JNE        S5
    358         MOV     DX,OFFSET STRING1
    359         PUSH     DX
    360         CALL     TOLOWER
    361         OUTPUT     STRING1
    362         NEWLINE
    363         JMP     CONTINUE
    364     S5:
    365         CMP     OP,'a'
    366         JNE        S6
    367         MOV     AX,X
    368         MOV     BX,Y
    369         CALL     MULTIPLE2
    370         MOV        AX,Z
    371         CALL     DISP_VALUE
    372         JMP     CONTINUE
    373     S6:
    374         CMP     OP,'b'
    375         JNE        S7
    376         MOV         SI,OFFSET STRING1
    377         MOV     DI,OFFSET STRING2
    378         CALL     STRCPY2
    379         OUTPUT     STRING2
    380         NEWLINE
    381         JMP     CONTINUE
    382     S7:
    383         CMP     OP,'c'
    384         JNE        S8
    385         MOV     SI,OFFSET STRING1
    386         MOV     DI,OFFSET STRING2
    387         CALL     STRCMP2
    388         JMP     CONTINUE
    389     S8:
    390         CMP     OP,'d'
    391         JNE        S9
    392         MOV         DI,OFFSET STRING2
    393         MOV     AL,CHAR
    394         CALL    FIND2
    395         JMP     CONTINUE
    396     S9:
    397         CMP     OP,'e'
    398         JNE        CONTINUE
    399         MOV     SI,OFFSET STRING2
    400         CALL     TOLOWER2
    401         OUTPUT     STRING2
    402         NEWLINE
    403     CONTINUE:
    404         POP     CX    
    405         RET
    406 SWITCH     ENDP
    407 
    408 MAIN    PROC     FAR
    409     MAINPROC:
    410         MOV     AX,DATA
    411         MOV     DS,AX
    412         MOV     ES,AX
    413 
    414         MOV     CX,N
    415     MAINLOOP:
    416         GETOP
    417         NEWLINE
    418         CALL     SWITCH
    419         LOOP     MAINLOOP
    420 
    421     EXIT:    
    422         MOV     AX,4C00H
    423         INT     21H
    424 MAIN     ENDP
    425 
    426 CODE     ENDS
    427         END     MAIN

    2-5 运行结果

        为了验证程序符合预期,需要设计以下样例进行测试。设置循环次数为10次

        设置数据区如下:

       

     数据分别表示

    • LEN 字符串长

    • N 外循环次数

    • X,Y,Z  执行A/a操作时的乘数和结果

    • STRING1,STRING2 待操作的两个字符串

    • CHAR 待寻找的字符串

    • OP 读入的操作指令符

    • NL 回车换行标志

    • MSGEQ,MSGGT,MSGLT,DOFOUND,NOTFOUND 输出提示信息

      运行程序,得到如下结果

       

      显然,运行结果符合预期。

  • 相关阅读:
    FTP 协议和 HTTP 协议的比较
    HttpURLConnection的post请求,什么时候发出,writeData存在什么地方
    装饰器
    函数参数以及名称空间作用域
    函数的调用
    函数的返回值
    定义函数的三种方式
    函数
    day05
    day04
  • 原文地址:https://www.cnblogs.com/chrischen98/p/10770665.html
Copyright © 2020-2023  润新知