前言:
而今朋友们对“汇编语言sum db 4 dup是什么意思”大致比较讲究,同学们都需要了解一些“汇编语言sum db 4 dup是什么意思”的相关知识。那么小编同时在网上网罗了一些关于“汇编语言sum db 4 dup是什么意思””的相关资讯,希望你们能喜欢,兄弟们一起来学习一下吧!记录一下学习汇编过程中写的一些小程序,代码都是在DosBox上完成的,记录的目的也是为了在后面想要复习相关知识点的时候有一个很好的资料和练习素材,同时也希望能够为后来学习的朋友起一点指导作用。
一,Hello World!
DATA SEGMENTstr db 'Hello World$' ;要输出的字符串必须要以$结尾DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA ;将CS和CODE,DS和DATA段建立联系START: MOV BX,DATA ; 段寄存器不能被立即数直接赋值,需要先赋值给其他寄存器,然后再赋值 MOV DS,BX LEA DX,str MOV AH,9 ; 执行9号系统调用,从DX寄存器中取出值并打印 INT 21H ; 产生一个系统中断 MOV AH,4CH ;将控制权返回给终端 INT 21H CODE ENDSEND START
ps:
LEA和MOV其实作用差不多,LEA是load effective address 的缩写,其实就是把后一个参数的地址传递给第一个参数,而MOV则是传递后面的值,值是地址就是地址,是值就是值。lea其实和mov+offset功能一样,唯一不同lea是硬指令,在指令执行的时候才会计算,而offset在汇编阶段就已经完成计算了。传送门
INT 21H其实就是执行系统调用,那执行哪一个呢?玄机就在前面的mov中。
二,计算平均值
DATA SEGMENT sum DW 1,2,3,4,5,6,7,8,9DATA ENDSSTACK SEGMENTSTACK ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,SS:STACKSTART: MOV BX, DATA MOV DS, BX MOV CX, 9 ; loop使用CX作为判断条件 即设置循环次数 XOR AX, AX ;清零 XOR BX, BX MOV SI, OFFSET sum ; 得到sum的起始地址again: ADD AX, [SI] ADD SI, 2 ; 索引指向下一项 LOOP again ; 循环结构语句,其中隐含使用CX寄存器,每次加1 ;CDQ MOV CL, 9 DIV CL ; 商在AX, 余数在DX MOV DL, AL ADD DL, 30H MOV AH, 02H ;2号系统调用,从DL取出值输出 INT 21H MOV AH, 4CH ;控制权返回给终端,不写的话显示完就卡那了 INT 21HCODE ENDSEND START三,键盘输入1-7,显示相应为星期几
DATA SEGMENT msg1 db 'Monday$' msg2 db 'Tuesday$' msg3 db 'Wednesday$' msg4 db 'Thyrsday$' msg5 db 'Friday$' msg6 db 'Saturday$' msg7 db 'Sunday$' msg db 'input number(1-7):$' table dw disp1,disp2,disp3,disp4 dw disp5,disp6,disp7DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART: MOV BX, DATA MOV DS, BX again: LEA DX, msg MOV AH, 9 ; 9号系统调用,从DX取数据并输出 INT 21H XOR AX, AX ; 清空AX,不然后面乘4低位会出现错误 MOV AH, 01H ; 1号系统调用,将字符输入到AL中 INT 21H ;MOVZX AX, AL SUB AX, 100H ; 系统调用会在AX上加100h SUB AX, 30H ; ascll码,减30h变裸数字 ; 不在范围内重新输入 CMP AL, 1 ; 减法操作,但不保存结果,只改变状态寄存器 JB again ; 无符号小于则跳转 CF=1 CMP AL, 7 JA again ; 无符号大于则跳转 CF=0,ZF=0 DEC AL MOV AX, AL MOV AH, 0 ; 意义不大,主要是前面类型不合适,这里补救一下 SHL AX, 1 ; 乘2,匹配到对应项地址 MOV BX, AX ;jmp dword ptr table[AX] ; 16位dos环境中,AX不能用作偏移地址 JMP WORD PTR TABLE[BX] ; jmp实际需要的是一个地址 disp1: MOV AX, OFFSET msg1 jmp disp disp2: MOV AX, OFFSET msg2 jmp disp disp3: MOV AX, OFFSET msg3 jmp disp disp4: MOV AX, OFFSET msg4 jmp disp disp5: MOV AX, OFFSET msg5 jmp disp disp6: MOV AX, OFFSET msg6 jmp disp disp7: MOV AX, OFFSET msg7 jmp disp disp: MOV DX, AX MOV AH, 9 INT 21H MOV AH, 4CH INT 21H ;控制权返回给终端CODE ENDSEND START
ps:
切记,16位dos环境中,AX不能用作偏移地址,所以我们使用BX。从table中取label的时候因为没有类型,需要我们指定类型,从而确定长度。四,模拟函数调用过程
sum函数的逻辑如下::
int sum(int lhs, int rhs){ int T1 = 1; int T2 = 2; return lhs + rhs + T1 + T2;}
ASSUME CS:CODE,DS:DATA,SS:STACKSTACK SEGMENT db 20 dup(0)STACK ENDSDATA SEGMENT db 20 dup(0) str db "hello world!$"DATA ENDSCODE SEGMENTSTART: MOV AX, DATA MOV DS, AX MOV AX, STACK MOV SS, AX ;开始业务逻辑部分 MOV AX, 3h ;传递参数 立即数不能直接传递 para1 PUSH AX MOV AX, 4H ; para2 PUSH AX CALL sum ; 调用sum MOV DL, AX MOV AH, 02h; 从DX取值并输出 INT 21H MOV AH, 4CH ; 将控制权转移给终端 INT 21H ; 产生系统中断sum: PUSH bp MOV BP, SP ; 初始化函数堆栈 SUB SP, 20 ; 20字节留作局部变量 ; 保护寄存器 PUSH BX PUSH CX PUSH DX ; 定义两个局部变量 MOV word ptr SS:[BP - 2], 1h MOV word ptr SS:[BP - 4], 2h ; 修改寄存器 MOV BX, 2h MOV CX, 3h MOV DX, 4h ; 计算部分 两个参数加上常数1+2 MOV AX,SS:[BP + 6]; param1 ADD AX,SS:[BP + 4]; param2 ADD AX,SS:[BP - 2]; 1 ADD AX,SS:[BP - 4]; 2 ADD AX, 30H; 输出为ascll码,加上48 //|--------| //|param2 3| //|param1 4| //|ret_addr| 返回地址就是CALL指令下一条指令的地址 //|ebp | EBP其内存放一个指针,该指针指向系统栈最上面一个栈帧的底部 //|ebp-2 1h| //|ebp-4 2h| //|--------| ; 恢复寄存器 POP DX POP CX POP BX MOV SP,BP POP BP RET CODE ENDSEND START
ps:
函数的返回值一般存放在EAX中。
对于使用栈的函数调用过程一定要清楚,在参数和栈帧起点ebp之间还有一个ret_addr,存放着调用这个函数的原函数的EIP寄存器的位置,即程序计数器的位置,这样与ebp结合可以精确的在子函数执行完以后回到原函数。
五,汇编生成1-N共N位不重复的随机数
比如1-5,就会生成12345, 34152,54312等等。
;生成八位的随机字符串DATA SEGMENT result db " " ; 9位 DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART: MOV AX, DATA MOV DS, AX MOV SI, 0 ; 目前到第几个随机数 doRand: ; 这里设置一个label方便其他程序调用 CreateRandNumdo1: ; 每执行一次可以确定一个随机数 CALL getRand ; 这个随机数在AL中 XOR DI, DI XOR CX, CX LEA DI, result ; di中存着result的起始地址 ; 这里在前几次会有很多无意义的执行,但是因为初始值为0,所以正确性是可以保证的 MOV CX, 8 ; CX为loop默认使用的寄存器,SI为现在已有的随机字符数,也就是循环这么多次 CreateRandNumdo2: MOV BH, [DI]; 每次通过[DI]取一个值 CMP BH, AL ; 比较此次得到的随机数和已有的随机数 JZ CreateRandNumdo1 ; 出现重复的时候再次生成随机数 INC DI LOOP CreateRandNumdo2 ; CreateRandNumdo1结束以后,AL中存放着此次要插入的值,插入到result[SI]中 ;ADD AL, 30H ; 输出为ASCLL,所以加上30H MOV result[SI], AL INC SI ; 现在对第几个随机数赋值 CMP SI, 8 ; 已经生成了完成了我们需要的随机字符串 JB doRand; 开始生成下一个随机字符 JB 无符号大于则跳转 MOV CX, 8 MOV SI, 0 ToASCLL: ; 目前全部的值都是数字,需要转换成ASCLL码 ADD result[SI], 30H INC SI LOOP ToASCLL MOV result[SI], 24H ; $的ASCLL码为36, 给字符串末尾加上$ LEA DX, result MOV AH, 9 ; 从DX中读取字符串并输出 INT 21H ;注释掉的部分为测试getRand ;-------------------------------------- ;call getRand ;MOV DL, AL ;ADD DL, 30H ; 显示ascll码,加30H ;MOV AH, 02H ; 从DL取出数字显示 ;INT 21H ;-------------------------------------- MOV AH, 4CH ; 控制权交给终端 INT 21H getRand: ;获取一个随机数,放到AL中 XOR AL, AL MOV AX, 0H ; 汇编中使用in/out来访问系统的io空间 OUT 43H, AL ;将0送到43h端口 IN AL, 40H ;将40h端口的数据送到AL寄存器 MOV BL, 8 ;除以8,得到范围0-7的余数 DIV BL ;商在AL, 余数在AH MOV AL, AH ; MOV AH, 0 INC AL ; 加1,得到范围1-8 RETCODE ENDSEND START
ps:
汇编是直接面向硬件的,它可以访问系统的mem空间,也可以直接访问系统的io空间。汇编中使用in/out来访问系统的io空间。传送门
事实上这个代码还有优化空间,就是检测的时候没必要每次都检查8次,正确性可以保证,但是浪费一些指令。所以可以用一个寄存器保存现在已经完成的随机字符的数量,在CreateRandNumdo1给CX赋当前已经生成的字符数。
代码太难重用了,可以用一个寄存器保存需要生成的长度,类似于全局变量,替换这个代码满天飞的8。
标签: #汇编语言sum db 4 dup是什么意思 #dup0汇编