源程序如下:
1 assume cs:code, ds:data 2 3 data segment 4 db ‘welcome to masm!‘ 5 data ends 6 7 code segment 8 start: mov ax,data 9 mov ds,ax;将数据段基址赋给DS寄存器 10 mov ax,0b800h;默认在显存第0列显示时,对应的显存空间为B8000H ~ B8F9FH。此处以B800H作为附加段地址 11 mov es,ax;存入附加段寄存器ES 12 13 mov bx,0h 14 mov cx,16;共计16个字符,循环16次 15 16 mov si,720h;一屏25行80列,每一行160个字节,屏幕中间位置对应的显存地址为11*160+40h=6E0+40h=720h 17 mov di,0 18 19 s: mov bl,ds:[di];获取字符 20 mov bh,02h;按位设置属性字节,绿色,00000010B,02H 21 mov es:[si],bx 22 mov bh,24h;绿底红色,00100100B,24H 23 mov es:[si+160],bx;进行换行 24 mov bh,71h;白底蓝色,01110001B,71H 25 mov es:[si+2*160],bx 26 27 inc di;下一字符 28 add si,2 29 loop s 30 31 mov ax,4c00h 32 int 21h 33 34 code ends 35 end start
运行结果截图如下:
编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
使用任意文本编辑器,录入汇编源程序task2.asm。
源程序如下:
1 assume cs:code, ds:data 2 data segment 3 str db ‘try‘, 0 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 11 mov si, offset str 12 mov al, 2 13 call printStr 14 15 mov ah, 4ch 16 int 21h 17 18 printStr: 19 push bx 20 push cx 21 push si 22 push di 23 24 mov bx, 0b800H 25 mov es, bx 26 mov di, 0 27 s: mov cl, [si] 28 mov ch, 0 29 jcxz over 30 mov ch, al 31 mov es:[di], cx 32 inc si 33 add di, 2 34 jmp s 35 36 over: pop di 37 pop si 38 pop cx 39 pop bx 40 ret 41 42 code ends 43 end start
把line3改为: str db ‘another try‘, 0
把line12改为: mov al, 4
在 line18-40中:
四个寄存器中的数据压入栈,执行出栈操作时恢复,能保证数据不受影响。
将寄存器cx中存储的字符,包含低位字节的ASCII码和高位字节的字符属性,送到指定的显存地址。
源程序如下:
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 4 str db 16 dup(0) 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov ax, x 12 mov di, offset str 13 call num2str 14 15 mov ah, 4ch 16 int 21h 17 18 num2str: 19 push ax 20 push bx 21 push cx 22 push dx 23 24 mov cx, 0 25 mov bl, 10 26 s1: 27 div bl 28 inc cx 29 mov dl, ah 30 push dx 31 mov ah, 0 32 cmp al, 0 33 jne s1 34 s2: 35 pop dx 36 or dl, 30h 37 mov [di], dl 38 inc di 39 loop s2 40 41 pop dx 42 pop cx 43 pop bx 44 pop ax 45 46 ret 47 code ends 48 end start
子任务1
对task3.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编;
使用g命令执行 到line15(程序退出之前),使用d命令查看数据段内容,观察是否把转换后的数字字符串‘1984‘存放在数据段中str标号后面的单元。
根据如下结果截图,‘1984‘已存放在相应单元中。
子任务2
对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,实现对转换后的字符串进行输出。
修改后的代码如下:
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 4 str db 16 dup(0) 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov ax, x 12 mov di, offset str 13 call num2str 14 mov si,offset str 15 mov al,2 16 call printStr 17 mov ah, 4ch 18 int 21h 19 20 num2str: 21 push ax 22 push bx 23 push cx 24 push dx 25 26 mov cx, 0 27 mov bl, 10 28 s1: 29 div bl 30 inc cx 31 mov dl, ah 32 push dx 33 mov ah, 0 34 cmp al, 0 35 jne s1 36 s2: 37 pop dx 38 or dl, 30h 39 mov [di], dl 40 inc di 41 loop s2 42 43 pop dx 44 pop cx 45 pop bx 46 pop ax 47 48 ret 49 50 printStr: 51 push bx 52 push cx 53 push si 54 push di 55 56 mov bx, 0b800H 57 mov es, bx 58 mov di, 0 59 s: mov cl, [si] 60 mov ch, 0 61 jcxz over 62 mov ch, al 63 mov es:[di], cx 64 inc si 65 add di, 2 66 jmp s 67 68 over: pop di 69 pop si 70 pop cx 71 pop bx 72 ret 73 74 code ends 75 end start
结果截图如下:
把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,观察结果。
此处修改为 x dw 2021 ,结果截图如下:
使用任意文本编辑器,录入汇编源程序task4.asm。
源程序如下:
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 12 s1: 13 mov ah, 1 14 int 21h 15 mov [si], al 16 cmp al, ‘#‘ 17 je next 18 inc si 19 jmp s1 20 next: 21 mov cx, si 22 mov si, 0 23 s2: mov ah, 2 24 mov dl, [si] 25 int 21h 26 inc si 27 loop s2 28 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
汇编、链接、运行程序,输入一个字符串并以#结束(比如,2020, bye#)观察运行结果。
结果截图如下:
使用int 21h中的1号子功能,从键盘输入的字符保存在al中。当读入的字符为#时,则跳转到next,否则继续读入下一个字符。
使用int 21h中的2号子功能,将之前输入的字符逐个输出到屏幕上。
在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
1 #include <stdio.h> 2 int sum(int, int); 3 4 int main() { 5 int a = 2, b = 7, c; 6 7 c = sum(a, b); 8 9 return 0; 10 } 11 12 int sum(int x, int y) { 13 return (x + y); 14 }
在line7, line13分别设置断点,在调试模式下,查看反汇编代码。
①汇编中参数通过寄存器传递,从line7断点反汇编结果可以观察到两个数据先后赋值给寄存器eax。
②调用函数之后,后续的返回值存储在寄存器exa中。
③关于多个参数的入栈顺序,仍然可以通过line7断点反汇编结果看出最右边的参数最先压栈,依次进行。
④关于函数调用栈,ESP扩展栈指针寄存器,指向栈顶,EBP是基址指针,在调用函数时保存ESP,使函数结束时可以正确返回。
⑤汇编是使用call和ret指令实现子程序的调用和返回的。
原文:https://www.cnblogs.com/jewnicorner/p/14148067.html