汇编入门笔记(六)

0x16:包含多个段的程序

1.在代码段中使用数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;计算 8 个数据的和存到 ax 寄存器
assume cs:code

code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;define word 定义8个字形数据

start: mov bx, 0 ;标号start
mov ax, 0

mov cx, 8
s: add ax, cs:[bx]
add bx, 2
loop s

mov ax, 4c00h
int 21h
code ends
end start ;end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方
;用end指令指明了程序的入口在标号start处,也就是说,“mov bx,0”是程序的第一条指令。

image-20210927160031097

如果把上面程序的start和end后面的start去掉,然后debug会发现 cs:ip 的前 16 个字节并不是我们想看到的“第一条”指令:mov bx, 0

是因为前16个字节被dw定义的8个字占用了,这样需要修改 ip 的内容使其从 0010 开始执行。(这样直接运行会出问题,找不到入口地址,需要用debug修改 ip 内容)

如果加上start就会发现 cs:ip 会直接从 cs:0010 开始。(不需要手动修改)

2.在代码段中使用栈

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
;利用栈,将程序中定义的数据逆序存放。
assume cs:codesg

codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ; 0-15单元
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 16-47单元作为栈使用

start: mov ax, cs
mov ss, ax
mov sp, 30h ;将设置栈顶ss:sp指向栈底cs:30。 30h = 48d
mov bx, 0

mov cx, 8 ;循环8次
s: push cs:[bx]
add bx, 2
loop s ;以上将代码段0~15单元中的8个字型数据依次入栈

mov bx, 0

mov cx, 8 ;循环8次
s0: pop cs:[bx]
add bx,2
loop s0 ;以上依次出栈8个字型数据到代码段0~15单元中

mov ax,4c00h
int 21h
codesg ends
end start ;指明程序的入口在start处

VScode MASM插件的一个问题:asm文件不能命名为 1.asm。

3.将数据、代码、栈放入不同的段

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
assume cs:code,ds:data,ss:stack 

data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;0-15单元
data ends

stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;0-31单元
stack ends

code segment
start: mov ax, stack;将名称为“stack”的段的段地址送入ax
mov ss, ax
mov sp, 20h ;设置栈顶ss:sp指向stack:20。 20h = 32d

mov ax, data ;将名称为“data”的段的段地址送入ax
mov ds, ax ;ds指向data段

mov bx, 0 ;ds:bx指向data段中的第一个单元

mov cx, 8
s: push [bx]
add bx, 2
loop s ;以上将data段中的0~15单元中的8个字型数据依次入栈

mov bx, 0

mov cx, 8
s0: pop [bx]
add bx, 2
loop s0 ;以上依次出栈8个字型数据到data段的0~15单元中

mov ax, 4c00h
int 21h
code ends
end start
;“end start”说明了程序的入口,这个入口将被写入可执行文件的描述信息,
;可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令

定义数据段和栈段就与代码段一样使用assume关键字。

定义中的段号就代表了段地址,如stack表示栈段的段地址。

0x17:and 和 or 指令

image-20210927203721976

0x18:关于 ASCII 码

以字符形式给出的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
assume cs:code,ds:data 

data segment
db 'unIx' ;相当于“db 75H,6EH,49H,58H”
db 'foRK'
data ends

code segment
start: mov al, 'a' ;相当于“mov al, 61H”,“a”的ASCI码为61H;
mov b1, 'b'

mov ax, 4c00h
int 21h
code ends
end start

image-20210927205409500

大小写转换:

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
assume cs:codesg,ds:datasg 

datasg segment
db 'BaSiC'
db 'iNfOrMaTion'
datasg end

codesg segment
start: mov ax, datasg
mov ds, ax ;设置ds 指向 datasg段

mov bx, 0 ;设置(bx)=0,ds:bx指向’BaSic’的第一个字母

mov cx, 5 ;设置循环次数5,因为’Basic'有5个字母
s: mov al, [bx] ;将ASCII码从ds:bx所指向的单元中取出
and al, 11011111B;将al中的ASCII码的第5位置为0,变为大写字母
mov [bx], al ;将转变后的ASCII码写回原单元
inc bx ;(bx)加1,ds:bx指向下一个字母
loop s

mov bx, 5 ;设置(bx)=5,ds:bx指向,iNfOrMaTion'的第一个字母

mov cx, 11 ;设置循环次数11,因为‘iNfOrMaTion'有11个字母
s0: mov al, [bx]
or al, 00100000B;将a1中的ASCII码的第5位置为1,变为小写字母
mov [bx], al
inc bx
loop s0

mov ax, 4c00h
int 21h
codesg ends
坚持原创技术分享,您的支持将鼓励我继续创作!