感谢曹老师的PPT、《汇编语言程序设计教程》(卜艳萍,清华出版社),仔细阅读后,自己提取并总结了这些技巧或方法。文中若有纰漏之处,恳请读者通过邮件向我指正。
位运算技巧在汇编程序中的应用 其他汇编技巧 16进制数转换为ASCII码 DOS功能调用的2号功能的输出,需要传入一个ASCII码的字符。然而我们现在只有一个16进制数,如何得到对应的ASCII码呢?
方法一:查表法 (1)要点:
(2)代码:
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 assume cs:codesg, ds:datasgdatasg segment ASCII db 30 h,31 h,32 h,33 h,34 h,35 h db 36 h,37 h,38 h,39 h db 41 h,42 h,43 h,44 h,45 h,46 h hex db 09 h datasg endscodesg segmentstart: mov ax, datasg mov ds, ax mov bx, offset ASCII mov al, hex and al, 0 fh xlat mov dl, al mov ah, 2 int 21 h mov ah, 4 ch int 21 hcodesg endsend start
(3)内存中存储的数据:
(4)运行结果:
hex赋值 0fh09h运行结果
方法二:直接转换法 下面演示的是两位 16进制数(即8位二进制,1个字节大小,可以存放到 8位寄存器 如 AL等)
(1)分析:
我们观察一下 ASCII 码表,发现0 − 9 0-9 0 − 9 的ASCII码(二进制8位)下,前8位具有共同前缀 0011 ,而末8位恰好就是0 − 9 0-9 0 − 9 的二进制表示!那 16 进制下的A − F A-F A − F 呢?我们只需要特判即可,如果该数字的ASCII码不超过 39H (即数字9),那么直接输出即可;若超过(说明数字是A-F),那么直接对其加上7 即可
由于两位16进制数即是8位二进制数,故我们需要先对高4位二进制数进行转换,再对低4位二进制数进行转换。
(2)代码:
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 datasg segmentdatasg ends stacks segment db 256 dup(?)stacks endscodesg segment assume cs:codesg, ds:datasg, ss:stacksstart: mov ax, datasg mov ds, ax mov al, 0 fah push ax mov dl, al mov cl, 4 shr dl, cl call transASCII pop dx and dx, 000 fh call transASCII mov ah, 4 ch int 21 htransASCII proc far or dl, 30 h cmp dl, 39 h jbe output add dl, 7 output: mov ah, 2 int 21 h rettransASCII endp codesg ends end start
(3)运行结果:
AL赋值fah9ch运行结果
多分支结构——地址表法 (1)要点:
当程序分支较多时,可使用地址表(跳转表)来实现程序分支。我们在数据段事先安排一个地址表,里面连续存放的是一系列跳转地址,即各分支程序的入口地址 。
由于使用 DOS 功能调用的1号功能,输入只能是一个字节大小的字符,同时是以二进制的ASCII码存入 AL 中。故需将 AL 存下 ASCII 码转换为对应的数字。(在下面的第30行代码)
⭐ 因为一个段最大存储空间是64 64 64 KB,偏移地址故使用 16 位表示 。因此需要用 2 个字节存储单元 (1个字)去储存偏移地址。对于这个地址表而言,要两个字节、两个字节…如此去寻找表中的每个元素。(在下面的第32行代码)
(2)代码:
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 datasg segment str0 db 0 dh,0 ah,'input number (1-3):' ,0 dH,0 ah,'$' str1 db 0 dh,0 ah,'chapter1: introduction' ,0 dH,0 ah,'$' str2 db 0 dh,0 ah,'chapter2: designing method' ,0 dH,0 ah,'$' str3 db 0 dh,0 ah,'chapter3: experiment' ,0 dH,0 ah,'$' table dw disp1, disp2, disp3 datasg endsstacks segment stacks endscodesg segment assume cs:codesg, ds:datasg, ss:stacksstart: mov ax, datasg mov ds, axinput: mov ah, 09 h mov dx, offset str0 int 21 h mov ah, 01 h int 21 h cmp al, '1' jb input cmp al, '3' ja input and ax, 000 fh dec ax shl ax, 1 mov bx, ax jmp table[bx]disp1: mov dx, offset str1 jmp outputdisp2: mov dx, offset str2 jmp outputdisp3: mov dx, offset str3 jmp output output: mov ah, 09 h int 21 h mov ah, 4 ch int 21 hcodesg ends end start
逻辑尺 逻辑尺,其实就是将有限个算式中的加减 运算符用 0 或 1 进行区分,由此得到有限长度的 01 串。
(1)题目
给定数组x ( x 1 , x 2 , . . . , x 10 ) x\ (x_1,x_2,...,x_{10}) x ( x 1 , x 2 , ... , x 10 ) 和y ( y 1 , y 2 , . . . , y 10 ) y\ (y_1,y_2,...,y_{10}) y ( y 1 , y 2 , ... , y 10 ) ,要求计算下面的z ( z 1 , z 2 , . . . , z 10 ) z\ (z_1,z_2,...,z_{10}) z ( z 1 , z 2 , ... , z 10 ) ,具体算式如下:
{ z 1 = x 1 + y 1 z 2 = x 2 + y 2 z 3 = x 3 − y 3 z 4 = x 4 − y 4 z 5 = x 5 − y 5 z 6 = x 6 + y 6 z 7 = x 7 − y 7 z 8 = x 8 − y 8 z 9 = x 9 + y 9 z 10 = x 10 + y 10 \begin{cases} z_1 &= x_1 + y_1 \\ z_2 &= x_2 + y_2 \\ z_3 &= x_3 - y_3 \\ z_4 &= x_4 - y_4 \\ z_5 &= x_5 - y_5 \\ z_6 &= x_6 + y_6 \\ z_7 &= x_7 - y_7 \\ z_8 &= x_8 - y_8 \\ z_9 &= x_9 + y_9 \\ z_{10}&= x_{10} + y_{10} \\ \end{cases} ⎩ ⎨ ⎧ z 1 z 2 z 3 z 4 z 5 z 6 z 7 z 8 z 9 z 10 = x 1 + y 1 = x 2 + y 2 = x 3 − y 3 = x 4 − y 4 = x 5 − y 5 = x 6 + y 6 = x 7 − y 7 = x 8 − y 8 = x 9 + y 9 = x 10 + y 10
(2)分析
注意只有10 10 10 项,每一项的z i ( 1 ≤ i ≤ 10 ) z_i(1\leq i\leq 10) z i ( 1 ≤ i ≤ 10 ) 都是由x i x_i x i 与y i y_i y i 进行加或减的运算,我们用 1 表示减法、0 表示加法,因此,从第一条式(在低位)到第10条式(在高位)的加减符号便能够得到一条 01 串:0000,0000,1101,1100b(16进制为 00dch),接着我们只需要循环依次遍历z i z_i z i 便能够得出结果了。
(3)代码
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 datasg segment x dw x1,x2,x3,x4,x5,x6,x7,x8,x9,x10 y dw y1,y2,y3,y4,y5,y6,y7,y8,y9,y10 z dw z1,z2,z3,z4,z5,z6,z7,z8,z9,z10 logic_rule dw 00 dch datasg endsstacks segment stacks endscodesg segment assume cs:codesg, ds:datasg, ss:stacksstart: mov ax, datasg mov ds, ax mov bx, 0 mov cx, 10 mov dx, logic_rulenext: mov ax, x[bx] shr dx, 1 jc subtract add ax, y[bx] jmp restore subtract: sub ax, y[bx]restore: mov z[bx], ax add bx, 2 loop next mov ah, 4 ch int 21 hcodesg ends end start
其他算法 阶乘运算(递归实现)
《汇编语言程序设计教程》(卜艳萍,清华出版社)P175
辗转相除法
《汇编语言程序设计教程》(卜艳萍,清华出版社)P165
冒泡排序
《汇编语言程序设计教程》(卜艳萍,清华出版社)P157