ASM16

函数

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG1 db "Hello World1!",0dh,0ah,'$'
MY_MSG2 db "Hello World2!",0dh,0ah,'$'
MyData ends

MyCode2 segment
call far ptr MY_SUB
MY_SUB:
push bp
mov bp,sp ;保存栈底

mov ax,[bp+6]
sub ax,[bp+8]

pop bp ;恢复栈底
retf 4
MyCode2 ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax

;段间子程序调用
mov ax,1
push ax
mov ax,2
push ax
call far ptr MY_SUB ;进行远调用,跳转到 MY_SUB 子程序。

mov ax,09h ;参数2
push ax
mov ax,offset MY_MSG1 ;参数1 从右往左边入栈
push ax
call SHOW_HELLO
; add sp 4 ;stdcall调用约定

mov ax,09h
push ax
mov ax,offset MY_MSG2
push ax
call SHOW_HELLO
; add sp 4

mov ax,2
push ax
mov ax,1
push ax
call MY_ADD

mov ax,4c00h
int 21h

SHOW_HELLO:
push bp
mov bp,sp
push ax ;保存环境
push cx
push dx

mov cx,0
mov dx,word ptr [bp+4] ;访问参数1
mov ah,byte ptr [bp+6] ;访问参数2
int 21h

pop dx
pop cx
pop ax ;恢复环境
; pop ax
; jmp ax ==> pop ip

; pop ax
; add sp,4
; push ax
; ret
pop bp
retn 4 ;mov ip,[sp] add sp,4 c调用约定

MY_ADD:
push bp
mov bp,sp ;保存栈底
sub sp,4 ;申请局部变量空间
push bx ;保存环境

mov ax,[bp+4]
mov [bp-2],ax ;第1个局部变量
add ax,[bp+6]
mov [bp-4],ax ;第2个局部变量

;返回值放在寄存器 ax
pop bx
mov sp,bp ;释放局部变量空间
pop bp ;恢复栈底
retn 4 ;int 3 iret

MyCode ends

end MAIN

call far ptr MY_SUB 进行远调用,跳转到 MY_SUB 子程序。(因为其他段也要调用MY_SUB,所以MY_SUB中对参数的调用按照远调用的格式来写,所以此处也采用远调用,保证格式的一致)

子程序(补充)

子程序指令

  • 子程序是完成特定功能的一段程序
  • 当主程序(调用程序)需要执行这个功能时,采用call调用指令转移到该子程序的起始处执行
  • 当运行完子程序功能后,采用RET返回指令回到主程序继续执行

子程序调用指令

  • CALL指令分为4种类型(类似JMP)

    1
    2
    3
    4
    5
    plaintext
    call label ;段内调用、直接寻址
    call r16/m16 ;段内调用、间接寻址
    call far ptr label ;段间调用、直接寻址
    call far ptr mem ;段间调用、间接寻址
  • CALL指令需要保存返回地址:

    image-20240807230427937

子程序返回指令

  • 根据段内和段间、有无参数,分为4种类型

    1
    2
    3
    4
    5
    plaintext
    RET ;无参数段内返回
    RET i16 ;有参数段内返回
    RETF ;无参数段间返回
    RETF i16 ;有参数段间返回
  • 需要弹出CALL指令压入堆栈的返回地址

    image-20240807230816891

中断指令

  • 中断(Interrupt)是又一种改变程序执行顺序的方法
  • 中断具有多种中断类型
  • 中断的指令有3条:INT i8 IRET INTO
1
2
3
4
5
6
7
8
9
10
INT i8
;中断调用指令:产生i8号中断

IRET
; 中断返回指令:实现中断返回

INTO
; 溢出中断指令
; 若溢出标志OF=1,产生4号中断
; 否则顺序执行

字符串输出的功能调用

  • DOS功能调用INT 21H

    image-20240807233434301

  • 可以输出回车(0DH)和换行(0AH)字符产生回车和换行的作用

image-20240807233659737

  • DOS功能调用INT 21H

    image-20240807234351246

  • 执行该功能调用时,用户按键,最后用回车确认

  • 本调用可执行全部标准键盘编辑命令;用户按回车键结束输入,如按Ctrl+Break或Ctrl+C则中止

字符输出的功能调用

  • 显示器功能调用INT 10H

image-20240807233843817

按键判断的功能调用

  • DOS功能调用INT 21H

image-20240807234809571

  • 键盘功能调用INT 16H

    image-20240807234922451

  • 这两个功能调用都不循环等待按键,即使有键按下,键盘缓冲区仍然保留键值并且没有被清空,必要时必须用字符输入功能取走键值清空缓冲区