汇编笔记——函数

    科技2022-08-15  105

    START后面的 MOV AX,DATAS MOV DS,相当于左括号,MOV AH,4CH INT 21H相当于右括号,一组括号算一个函数,还可以自定义别的函数

    声明函数

    name PROC ;函数名字为name ;函数内容 RET ;返回值 name ENDP ;函数结束标志

    调用函数

    CALL name

    简单调用的例子:输出字符A 在代码段输入

    CALL ABC

    代码段后面输入

    ABC PROC ;声明ABC 函数 MOV DL,'A' MOV AH,2 INT 21H RET ABC ENDP

    完整代码,可以复制去运行一下

    DATAS SEGMENT ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 CALL ABC ;调用ABC函数 MOV AH,4CH INT 21H ABC PROC ;声明ABC 函数 MOV DL,'A' MOV AH,2 INT 21H RET ABC ENDP CODES ENDS END START

    现在来看传参与返回值,emmmm,简单来说就是传参传的不明显,返回也返回的不明显, 先看传参,给AX一个数,以无符号十进制形式输出 函数如下:

    ;定义ABC函数 ABC PROC MOV BH,0;记录压栈次数 MOV CL,10 L1: ADD BH,1 DIV CL;AX/CL,AL,余数AH PUSH AX MOV AH,0 CMP AL,0 JA L1 ;全部压栈,开始输出 L2: SUB BH,1 POP DX MOV DL,DH ADD DL,48 MOV AH,2 INT 21H CMP BH,0 JA L2 RET ABC ENDP

    在 MOV AX,DATAS MOV DS,AX后给AX赋值,调用ABC函数,会正确显示AX中的值,因为AX 是函数要的参数,为什么这么说呢?请注意:DIV CL;AX/CL,商AL,余数AH

    如果多个几个寄存器赋值,像下面这样,依旧是值输出AX的值,所以传参传的啥需要自己记住,而且是牢记 隐约感觉到大作业的恐怖

    DATAS SEGMENT ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 MOV BX,123 MOV CX,456 MOV AX,126 CALL ABC MOV AH,4CH INT 21H ABC PROC MOV BH,0;记录压栈次数 MOV CL,10 L1: ADD BH,1 DIV CL;AX/CL,AL,余数AH PUSH AX MOV AH,0 CMP AL,0 JA L1 ;全部压栈,开始输出 L2: SUB BH,1 POP DX MOV DL,DH ADD DL,48 MOV AH,2 INT 21H CMP BH,0 JA L2 RET ABC ENDP CODES ENDS END START

    如果想多输出几个数,如下代码也是错的,因为函数里用到了BX,调函数的时候改变了BX的值;因为汇编直接改了对应地址的数据

    MOV BX,123 MOV CX,456 MOV AX,126 CALL ABC MOV AX,BX CALL ABC

    返回值基本和没有一样,需要自己牢记该函数的功能以及寄存器变成的样子,变了就是返回了

    最后来个复杂一点的样例,结合汇编的“数组”,循环输入5个数字并输出 提示一下:输入可以写成一个函数,需要留意最后存到了哪里;输出可以写成另一个函数,需要记得第一步的结果存到了哪里

    ;函数 DATAS SEGMENT ;此处输入数据段代码 A1 WORD 1 A2 WORD 5 DUP(?) DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 MOV DI,5 MOV SI,OFFSET A2 L5: CALL INPUT ;调用INPUT函数,输入数字并转成无符号十进制数 MOV [SI],AX ;存入内存 ADD SI,2 ;内存地址+1 SUB DI,1 ;还需循环次数-1 CMP DI,0 ;循环次数到5,停止循环 JA L5 L6: SUB SI,2 MOV AX,[SI] CALL OUTPUT ;调用OUTPUT函数,以无符号十进制数形式输出输入的数字 MOV DL,' ' MOV AH,2 INT 21H ADD DI,1 CMP DI,5 JB L6 MOV AH,4CH INT 21H ;--------------------------分隔线------------------------------; ;定义INPUT函数 INPUT PROC MOV BX, 0 MOV CL, 10 MOV AH, 1 INT 21H CMP AL, '0' JB L3 CMP AL, '9' JA L3 MOV BL, AL SUB BL, 48 L4: MOV AH, 1 INT 21H CMP AL, '0' JB L3 CMP AL, '9' JA L3 MOV DL, AL SUB DL, 48 MOV AL, BL MOV CL, 10 MUL CL MOV BX, AX MOV DH, 0 ADD BX, DX JMP L4 L3: MOV AX, BX RET INPUT ENDP ;--------------------------分隔线------------------------------; ;定义OUTPUT函数 OUTPUT PROC MOV BH,0;记录压栈次数 MOV CL,10 L1: ADD BH,1 DIV CL;AX/CL,AL,余数AH PUSH AX MOV AH,0 CMP AL,0 JA L1 ;全部压栈,开始输出 L2: SUB BH,1 POP DX MOV DL,DH ADD DL,48 MOV AH,2 INT 21H CMP BH,0 JA L2 RET OUTPUT ENDP CODES ENDS END START

    这样两个函数调用起来,都感觉到记住寄存器中数据有点难了,如果再多几个函数更乱,所以这里就需要想办法让寄存器调函数前后数据不变(除有出口参数的情况)。我们可以用堆栈解决,在函数开始时,将用到的寄存器数据压栈,函数结束时,寄存器数据出栈回到各个寄存器。上面的代码加工一下,就是这个样子:

    ;函数 DATAS SEGMENT ;此处输入数据段代码 A1 WORD 1 A2 WORD 5 DUP(?) DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 MOV DI,5 MOV SI,OFFSET A2 L5: CALL INPUT ;调用INPUT函数,输入数字并转成无符号十进制数 MOV [SI],AX ;存入内存 ADD SI,2 ;内存地址+1 SUB DI,1 ;还需循环次数-1 CMP DI,0 ;循环次数到5,停止循环 JA L5 L6: SUB SI,2 MOV AX,[SI] CALL OUTPUT ;调用OUTPUT函数,以无符号十进制数形式输出输入的数字 MOV DL,' ' MOV AH,2 INT 21H ADD DI,1 CMP DI,5 JB L6 MOV AH,4CH INT 21H ;--------------------------分隔线------------------------------; ;定义INPUT函数 INPUT PROC PUSH BX PUSH CX PUSH DX MOV BX, 0 MOV CL, 10 MOV AH, 1 INT 21H CMP AL, '0' JB L3 CMP AL, '9' JA L3 MOV BL, AL SUB BL, 48 L4: MOV AH, 1 INT 21H CMP AL, '0' JB L3 CMP AL, '9' JA L3 MOV DL, AL SUB DL, 48 MOV AL, BL MOV CL, 10 MUL CL MOV BX, AX MOV DH, 0 ADD BX, DX JMP L4 L3: MOV AX, BX POP DX POP CX POP BX RET INPUT ENDP ;--------------------------分隔线------------------------------; ;定义OUTPUT函数 OUTPUT PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV BH,0;记录压栈次数 MOV CL,10 L1: ADD BH,1 DIV CL;AX/CL,AL,余数AH PUSH AX MOV AH,0 CMP AL,0 JA L1 ;全部压栈,开始输出 L2: SUB BH,1 POP DX MOV DL,DH ADD DL,48 MOV AH,2 INT 21H CMP BH,0 JA L2 POP DX POP CX POP BX POP AX RET OUTPUT ENDP CODES ENDS END START

    注意:INPUT函数有出口参数AX,恢复数据的时候别给AX也恢复了

    Processed: 0.017, SQL: 8