title:x86汇编语言之8086语法和指令集
tags:汇编
小白进阶之路之汇编5(持续更新中)
x86汇编语法
-
注释
;注释
-
变量取值和赋值(传送指令)
;赋值
mov ax,2000H ;将十六进制2000赋值给十六位寄存器ax 相当于ax=2000H
mov bx,FFFFh
;取值
mov bx,ax ;将ax中的值取出赋值给bx 相当于bx=ax
存放的数据大小根据使用的寄存器而定,比如ax是16位寄存器,最大只能存放16位数,也就是4位十六进制数据
十六进制数据不能以字母开头,前面需加上0 否则编译错误
- 函数声明
结构如下:
函数名:
函数体
ret ;结尾标记
示例:
print ;函数名
mov dx,offset str
mov ah,9ch
int 21h
ret ;函数结尾标记
- 函数调用
x86架构中使用关键指令call
x86架构汇编示例:
call print ;调用print函数
;退出程序
mov ah,4ch
int 21h
print: ;函数名
mov dx,offset str;获取别名对应数据的偏移地址
mov ah,9ch;9h表示调用显存 从dx总读取偏移地址对应的数据
int 21h
ret
- 字符串的定义
起因:如果直接将字符串赋值给通用寄存器,会出现以下两个问题:
- 字符顺序是反着的
- 最多只能存放两个字符
- 无法获取到数据地址,不能堆字符串进行修改
为了解决这个问题,需要使用另外一种方式,定义字符串
-
首先需要先在内存中申请一块空间,可以使用伪指令db和dw
db–>define byte 定义字节
dw–>define word 定义字 -
示例
db ‘hello’ ;占用五个字节的内存空间
dw ‘hello’ ;占用六个字节的内存空间
如果定义数字,使用dw每个数字占用两个字节的空间,字符串比较特殊,并不是每个字符占用两个字节,而是总长度必须是2的倍数
- 字符串的获取
获取字符串的数据,首先要获取到数据所对应的内存地址
那怎么获取已经定义好的地址呢?
第一步尝试:给数据添加别名
str db 'hello'
start:
mov bx,str;别名中存放的是偏移地址
end start
别名中存放的是偏移地址,但是光有偏移地址还不行,还需要段地址,段地址+偏移地址=实际物理地址,别名默认从ds寄存器中读取段地址,但是我们并没有给ds寄存器赋过值,这就导致我们无法获取正确的数据,因为我们不知道正确的段地址是多少?
那字符串段地址从哪里获取呢?
- 方法一:直接从内存中找(仅限于调试,实际开发肯定不行)
- 方法二:使用段进行包裹,段能给我们提供一个段地址(正解)
data segment
str db 'hello'
data segment
;使用段进行包裹,可以借助段名称获取段地址
- 对内存中的数据进行读写
从内存中一次读取数据的多少,取决于寄存器的容器大小
data segment
str dw 'hello','pangshu';如果定义多个数据,使用逗号进行分隔
data ends
start:
mov ax,data
mov ds,ax
mov ax,str;如果从内存中读取数据,是根据寄存器大小来读取,16位寄存器则一次性读取16位数据,8位寄存器则一次性读取八位数据
end start
错误写法:
;报错1
data segment
str db 'hello';改成dw则不报错
data ends
start:
mov ax,data
mov ds,ax
mov ax,str;
end start
;报错2
data segment
str dw 'hello'
data ends
start:
mov ax,data
mov ds,ax
mov al,str;改成mov,ax,str或者mov,al,b,str则不报错
end start
内存数据的读写从低到高
上面使用db或者dw定义数据的方式吧,定义数据的同时就已经定义好了数据所在的物理地址,如果我们想要从指定的内存地址中写入或者读取数据的话,需要借助段寄存器来实现,在8086中给我们提供了DS SS CS ES四个寄存器,理论上使用哪一个都行,但是由于系统默认读取DS寄存器中的数据当做段地址,所以我们一般使用DS进行数据的段地址管理
- 如何从指定内存中读取数据
假设我们需要从0710:0000这个物理地址中读取数据,然后存放到寄存器中
错误写法1:
start:
mov ax,0710:0000;没有这种语法
end start
错误写法2:
start:
mov ds,0710H;段寄存器不能直接赋值,必须借助通用寄存器
mov ax,ds:[0]