4706 字
24 分钟
从零开始的汇编语言笔记(2)

这里应该是一些主要的代码模板记录。

一. 基础读写#

1. 单个非负整数输入#

控制台输入一个十进制整数字符串,转成数存储。

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg
main proc far
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
call read_num
mov ax, input_num
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
; 输入一个整数,存入input_num
read_num proc near
push ax
push bx
push cx
push dx
push si
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
read_loop:
mul bx
mov dl, [si]
and dl, 0Fh
add ax, dx
inc si
loop read_loop
mov input_num, ax
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

2. 单个非负整数输出#

; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
lea si, output_buffer
mov ax, output_num
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
call newline
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp

合并后的输入输出:

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
output_num dw ?
output_buffer db 10 dup (?)
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc far
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
call read_num
mov ax, input_num
mov output_num, ax
call write_num
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
; 输入一个整数,存入input_num
read_num proc near
push ax
push bx
push cx
push dx
push si
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
read_loop:
mul bx
mov dl, [si]
and dl, 0Fh
add ax, dx
inc si
loop read_loop
mov input_num, ax
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
lea si, output_buffer
mov ax, output_num
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
call newline
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

3. 多个非负数输入输出#

(1) 每行一个#

每行输入1个数。

输入结束后输出。

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
output_num dw ?
output_buffer db 10 dup (?)
nums_len dw 3
nums dw 3 dup (?)
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov cx, [nums_len]
lea si, nums
get_nums_loop:
call read_num
mov ax, [input_num]
mov word ptr [si], ax
add si, 2
loop get_nums_loop
; call sort_num
mov cx, [nums_len]
lea si, nums
put_nums_loop:
mov ax, [si]
mov [output_num], ax
call write_num
add si, 2
loop put_nums_loop
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
; 输入一个整数,存入input_num
read_num proc near
push ax
push bx
push cx
push dx
push si
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, [input_buffer_len]
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
read_loop:
mul bx
mov dl, [si]
and dl, 0Fh
add ax, dx
inc si
loop read_loop
mov [input_num], ax
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
push di
lea si, output_buffer
mov ax, [output_num]
xor cx, cx ; 位数计数器
mov bx, 10
write_loop:
xor dx, dx
div bx ; AX = AX / 10, 商在 AX, 余数在 DX
or dl, 030h ; 转换为ASCII码
mov [si], dl ; 存储字符
inc si ; 指向下一个位置
inc cx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
dec si ; 指向最后一个
lea di, output_buffer ; 指向第一个
shr cx, 1
jz write_num_print ; (防止cx=0时的循环)
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
call newline
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

(2) 每行多个#

读入一行数,存入input_nums中,并且数的个数存入input_cnt中。

dataseg segment
input_nums dw 20 dup(?)
input_cnt dw ?
input_invalid db 0
input_buffer db 100
input_buffer_len db ?
input_buffer_data db 100 dup(?)
output_num dw ?
output_buffer db 10 dup (?)
nums_len dw ?
nums dw 20 dup (?)
dataseg ends
stackseg segment
db 100 dup (?)
stackseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg, ss:stackseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov ax, stackseg
mov ss, ax
call readline_num
call writeline_num
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
; 输入一行多个整数,存入
readline_num proc near
push ax
push bx
push cx
push dx
push si
push di
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
lea si, input_buffer_data ; 扫描到的原始字符串位置
mov ax, 0 ; 存储当前结果
lea di, input_nums ; 当前正在写入的位置
mov dl, 0 ; 标志位,最低位表示是否有数尚未存入结果
; 第二位表示是否有负数标志
xor bh, bh
readline_loop:
mov bl, byte ptr [si]
cmp bl, ' '
je readline_isspace ; 是空格
cmp bl, 0Dh ; 回车
je readline_isspace
cmp bl, 0Ah ; 换行
je readline_isspace
cmp bl, '-'
je readline_isneg
cmp bl, '0' ; 检查是否是数字
jb readline_invalid
cmp bl, '9'
ja readline_invalid
jmp readline_isnumber
readline_isneg:
test dl, 02h ; 多个符号
jnz readline_invalid
xor dl, 02h ; 标志位
jmp readline_charover
readline_isspace:
test dl, 03h ; 完全没开始
jz readline_charover
and dl, 03h
cmp dl, 02h ; 检查禁止的情况,仅有一个符号
je readline_invalid
test dl, 02h ; 是负数
jz readline_storenum
neg ax
readline_storenum:
mov word ptr [di], ax ; 存储
xor ax, ax ; 清空
add di, 2 ; 进位
mov dl, 0 ; 标志位清空
jmp readline_charover
readline_isnumber:
or dl, 1 ; 标志位
and bl, 0Fh ; ASCII转成数
push dx
mov dx, 10
mul dx ; *10
pop dx
add ax, bx ; 加当前位
readline_charover:
inc si
loop readline_loop
; 检查是否有数没有存储
test dl, 01h
jz readline_ok
; 处理末尾
mov word ptr [di], ax
add di, 2
jmp readline_ok
readline_invalid: ; 非法输入
mov input_invalid, 1
readline_ok:
lea si, input_nums
sub di, si
sar di, 1
mov input_cnt, di ; 写入个数
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
readline_num endp
; 输出一行多个整数
writeline_num proc near
push ax
push bx
push cx
push dx
push si
push di
lea si, input_nums ; 位置
mov cx, input_cnt ; 长度
writeline_loop:
mov ax, word ptr [si]
mov output_num, ax
call write_num
mov ah, 02h
mov dl, ' '
int 21h
add si, 2
loop writeline_loop
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
writeline_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
push di
lea si, output_buffer
mov ax, output_num
; 负数处理
cmp ax, 0
jge direct_write_num
push ax
mov ah, 02h
mov dl, '-'
int 21h
pop ax
neg ax
direct_write_num:
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
; call newline 取决于要不要换行
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

二. 常见任务#

1. 排序#

一个简单的选择排序:

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
output_num dw ?
output_buffer db 10 dup (?)
nums_len dw ?
nums dw 20 dup (?)
prompt_input_num db 'Input the number of numbers: ', '$'
prompt_input_num_d db 'Input the number: ', '$'
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov ah, 09h
lea dx, prompt_input_num
int 21h
call read_num
mov ah, 09h
lea dx, prompt_input_num_d
int 21h
mov cx, input_num
mov nums_len, cx
lea si, nums
get_nums_loop:
call read_num
mov ax, input_num
mov word ptr [si], ax
add si, 2
loop get_nums_loop
call sort_num
mov cx, nums_len
lea si, nums
put_nums_loop:
mov ax, word ptr [si]
mov output_num, ax
call write_num
add si, 2
loop put_nums_loop
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
sort_num proc near
push ax
push bx
push cx
push dx
push si
push di
mov si, [nums_len]
sal si, 1
lea bx, [nums + si] ; 截止位
lea si, nums
sort_loop:
lea di, [si + 2]
cmp di, bx
je scan_over
scan_loop:
mov ax, word ptr [di]
cmp word ptr [si], ax
jna scan_loop_over
; 开始交换
mov ax, word ptr [si]
xchg ax, word ptr [di]
xchg ax, word ptr [si]
scan_loop_over:
add di, 2
cmp di, bx
jne scan_loop
scan_over:
add si, 2
cmp si, bx
jne sort_loop
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
sort_num endp
; 输入一个整数,存入input_num
read_num proc near
push ax
push bx
push cx
push dx
push si
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
read_loop:
mul bx
mov dl, [si]
and dl, 0Fh
add ax, dx
inc si
loop read_loop
mov input_num, ax
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
lea si, output_buffer
mov ax, output_num
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
call newline
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main
image-20241126221839252

2. 进制转换#

输入一个十进制数,转成十六进制输出。

*报错#

operand must have size#

mov [si], '$'

应该修改为

mov byte ptr [si], '$'

Expected: comma#

shr cx

没有指定位移的位数。

shr cx, 1

往年上机题#

2021级:输入一组数,输出中位数#

也就是前面排序的类似的,取出中间的数即可。

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
output_num dw ?
output_buffer db 10 dup (?)
nums_len dw ?
nums dw 20 dup (?)
prompt_input_num db 'Input the number of numbers: ', '$'
prompt_input_num_d db 'Input the number: ', '$'
prompt_mid db 'The middle is : ', '$'
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov ah, 09h
lea dx, prompt_input_num
int 21h
call read_num
mov ah, 09h
lea dx, prompt_input_num_d
int 21h
mov cx, input_num
mov nums_len, cx
lea si, nums
get_nums_loop:
call read_num
mov ax, input_num
mov word ptr [si], ax
add si, 2
loop get_nums_loop
call sort_num
mov ah, 09h
lea dx, prompt_mid
int 21h
mov cx, nums_len
inc cx
shr cx, 1 ; (n+1)/2
dec cx ; 调整为零基
shl cx, 1 ; 2字节一个字
lea si, nums
add si, cx
mov ax, word ptr [si]
mov output_num, ax
call write_num
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
sort_num proc near
push ax
push bx
push cx
push dx
push si
push di
mov si, [nums_len]
sal si, 1
lea bx, [nums + si] ; 截止位
lea si, nums
sort_loop:
lea di, [si + 2]
cmp di, bx
je scan_over
scan_loop:
mov ax, word ptr [di]
cmp word ptr [si], ax
jna scan_loop_over
; 开始交换
mov ax, word ptr [si]
xchg ax, word ptr [di]
xchg ax, word ptr [si]
scan_loop_over:
add di, 2
cmp di, bx
jne scan_loop
scan_over:
add si, 2
cmp si, bx
jne sort_loop
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
sort_num endp
; 输入一个整数,存入input_num
read_num proc near
push ax
push bx
push cx
push dx
push si
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
read_loop:
mul bx
mov dl, [si]
and dl, 0Fh
add ax, dx
inc si
loop read_loop
mov input_num, ax
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
lea si, output_buffer
mov ax, output_num
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
call newline
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

2021级:输入字符串,改成小写后按字母表输出#

终端输入一个字符串

程序要求:

  • 将大写字母改为小写。

  • 按a-z的顺序输出出现过的字母

    如果字母没有出现就用空格代替,不能重复输出相同字母

(大概从0开始写了20min)

dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup (?)
answer_buffer db 26 dup (' '), '$'
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov ah, 0ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
lea si, input_buffer_data
mov bl, byte ptr 'a'
sub bl, byte ptr 'A'
; 改成小写
search_loop:
mov al, byte ptr [si]
cmp al, byte ptr 'A'
jb no_match
cmp al, byte ptr 'Z'
ja no_match
add al, bl
mov byte ptr [si], al
no_match:
inc si
loop search_loop
mov byte ptr [si], '$'
; mov ah, 09h
; lea dx, input_buffer_data
; int 21h
; call newline
xor ch, ch
mov cl, input_buffer_len
lea si, input_buffer_data
solve_loop:
mov al, byte ptr [si]
cmp al, byte ptr 'a'
jb solve_loop_over
cmp al, byte ptr 'z'
ja solve_loop_over
mov bl, al
sub bl, byte ptr 'a'
xor bh, bh
lea di, answer_buffer
add di, bx
mov [di], byte ptr 'a'
add [di], bl
solve_loop_over:
inc si
loop solve_loop
mov ah, 09h
lea dx, answer_buffer
int 21h
call newline
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
newline proc near
push ax
push ds
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

2020级:接受十进制数输入朝代,将朝代转成对应年份输出#

  • 自行设计数据存储朝代
  • 接收一个十进制年份输入
  • 将年份转为相应的朝代字符串输出
  • 查询可重复,如不是合法输入则退出程序
dataseg segment
input_buffer db 20
input_buffer_len db ?
input_buffer_data db 20 dup(?)
input_num dw ?
input_prompt db 'Input Year: ', '$'
year_cnt dw 7
year_ans dw -10000, -500, 800, 1000, 1300, 1500, 1700, 10000
dyna_ans db 'Qin $Han $Tang$Song$Yuan$Ming$Qing$'
invalid_tag db 0
dataseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
main_loop:
mov ah, 09h
lea dx, input_prompt
int 21h
call read_num
mov al, invalid_tag
cmp al, 1
je main_over
call answer
jmp main_loop
main_over:
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
answer proc near
mov cx, year_cnt
lea si, year_ans
lea di, dyna_ans
mov dx, input_num
answer_loop:
mov ax, [si]
mov bx, [si+2]
cmp dx, ax
jl no_answer
cmp dx, bx
jge no_answer
jmp answer_find
no_answer:
add si, 2
add di, 5
loop answer_loop
answer_find:
mov ah, 09h
mov dx, di
int 21h
call newline
ret
answer endp
read_num proc near
push ax
push bx
push cx
push dx
push si
push di
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, [input_buffer_len]
mov ax, 0
lea si, input_buffer_data
mov bx, 10
xor dx, dx
mov dl, [si]
cmp dl, '-'
jne read_loop
inc si
dec cx
read_loop:
mul bx
mov dl, [si]
cmp dl, '0'
jb read_invalid
cmp dl, '9'
ja read_invalid
and dl, 0Fh
add ax, dx
inc si
loop read_loop
lea si, input_buffer_data
mov dl, [si]
cmp dl, '-'
jne read_store
neg ax
read_store:
mov [input_num], ax
jmp read_num_over
read_invalid:
mov ax, 1
mov invalid_tag, al
read_num_over:
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
read_num endp
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main

2020级:加减法表达式#

dataseg segment
input_nums dw 20 dup(?)
input_cnt dw ?
input_invalid db 0
input_buffer db 100
input_buffer_len db ?
input_buffer_data db 100 dup(?)
fuhao db ?
output_num dw ?
output_buffer db 10 dup (?)
nums_len dw ?
nums dw 20 dup (?)
dataseg ends
stackseg segment
db 100 dup (?)
stackseg ends
codeseg segment
assume cs:codeseg, ds:dataseg, es:dataseg, ss:stackseg
main proc near
push ds
xor ax, ax
push ax
mov ax, dataseg
mov ds, ax
mov es, ax
mov ax, stackseg
mov ss, ax
call readline_num
mov ax, [input_nums]
mov bx, [input_nums+2]
mov cl, fuhao
cmp cl, '+'
je adddd
jne deccc
adddd:
add ax, bx
jmp main_over
deccc:
sub ax, bx
main_over:
mov input_nums, ax
mov ax, 1
mov input_cnt, ax
call writeline_num
pop ax
pop ds
mov ax, 4C00h
int 21h
main endp
; 输入一行多个整数,存入
readline_num proc near
push ax
push bx
push cx
push dx
push si
push di
mov ah, 0Ah
lea dx, input_buffer
int 21h
call newline
xor ch, ch
mov cl, input_buffer_len
lea si, input_buffer_data ; 扫描到的原始字符串位置
mov ax, 0 ; 存储当前结果
lea di, input_nums ; 当前正在写入的位置
mov dl, 0 ; 标志位,最低位表示是否有数尚未存入结果
; 第二位表示是否有负数标志
xor bh, bh
readline_loop:
mov bl, byte ptr [si]
cmp bl, '-'
je readline_isspace
cmp bl, '+'
je readline_isspace
cmp bl, '0' ; 检查是否是数字
jb readline_invalid
cmp bl, '9'
ja readline_invalid
jmp readline_isnumber
readline_isspace:
test dl, 03h ; 完全没开始
jz readline_charover
and dl, 03h
cmp dl, 02h ; 检查禁止的情况,仅有一个符号
je readline_invalid
test dl, 02h ; 是负数
jz readline_storenum
neg ax
readline_storenum:
mov word ptr [di], ax ; 存储
xor ax, ax ; 清空
add di, 2 ; 进位
mov fuhao, bl
mov dl, 0 ; 标志位清空
jmp readline_charover
readline_isnumber:
or dl, 1 ; 标志位
and bl, 0Fh ; ASCII转成数
push dx
mov dx, 10
mul dx ; *10
pop dx
add ax, bx ; 加当前位
readline_charover:
inc si
loop readline_loop
; 检查是否有数没有存储
test dl, 01h
jz readline_ok
; 处理末尾
mov word ptr [di], ax
add di, 2
jmp readline_ok
readline_invalid: ; 非法输入
mov input_invalid, 1
readline_ok:
lea si, input_nums
sub di, si
sar di, 1
mov input_cnt, di ; 写入个数
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
readline_num endp
; 输出一行多个整数
writeline_num proc near
push ax
push bx
push cx
push dx
push si
push di
lea si, input_nums ; 位置
mov cx, input_cnt ; 长度
writeline_loop:
mov ax, word ptr [si]
mov output_num, ax
call write_num
mov ah, 02h
mov dl, ' '
int 21h
add si, 2
loop writeline_loop
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
writeline_num endp
; 输出一个整数,存在output_num
write_num proc near
push ax
push bx
push cx
push dx
push si
push di
lea si, output_buffer
mov ax, output_num
; 负数处理
cmp ax, 0
jge direct_write_num
push ax
mov ah, 02h
mov dl, '-'
int 21h
pop ax
neg ax
direct_write_num:
xor dx, dx
mov cx, 10
write_loop:
div cx ; AX = AX / 10, 商在 AX, 余数在 DX
mov bx, dx ; BL = 余数
or bl, 030h ; 转换为 ASCII 字符
mov [si], bl ; 存储字符
inc si ; 指向下一个位置
xor dx, dx
cmp ax, 0
jne write_loop
mov byte ptr [si], '$'
lea di, output_buffer
mov cx, si
sub cx, di
dec si
shr cx, 1
jz write_num_print
reverse_loop:
mov al, [si]
xchg al, [di]
xchg al, [si]
inc di
dec si
loop reverse_loop
write_num_print:
mov ah, 09h
lea dx, output_buffer
int 21h
; call newline 取决于要不要换行
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
write_num endp
; 换行
newline proc near
push ax
push dx
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
ret
newline endp
codeseg ends
end main
从零开始的汇编语言笔记(2)
https://fuwari.vercel.app/posts/course/assembly/assembly-note-2/
作者
wegret
发布于
2025-01-02
许可协议
CC BY-NC-SA 4.0