Pixiv:岸Yasuri
通用寄存器中也有一类特殊的,BX寄存器可以像数据段地址的变量一样来使用
/*比如*/ mov [0],1234h mov [2],5678h /*为数据段ds:0~ds:3赋值*/ mov bx,0 mov ax,[bx] add bx,2 mov ax,[bx]
其他大部分寄存器都无法做到这样,而bx寄存器却可以使用这样的语法
基于bx寄存器的特性,我们不能再简单地将bx寄存器理解为一个通用寄存器,它还常常作为数据段的一个地址变量
这个指令类似于C语言的++
inc bx
等效于add bx,1
这个指令允许我们使用循环结构
比如求解\(2^{15}\)(目前还没学乘除,汇编语言也没有pow这样一个函数)
assume cs:code code segment mov ax,1 mov cx,15 s: mov ax,2 add ax,ax loop s /*这是一个循环结构*/ mov ax,4c00h int 21h code ends end
你在某一代码处设置标号s,在下面再写上loop <标号>
即可设置一个循环段
从s的这一行代码开始到loop结束为要循环的代码
这里不断循环的代码是
mov ax,2 add ax,ax
在8086汇编语言中,次数完全由CX来定,我们已经知道CX寄存器可以用来计算一个汇编程序的代码行数,但同时CX寄存器还担当了作为循环次数的一个作用
你设置CX的值为多少就循环多少次
mov cx,15/*设置次数为15*/ ... loop s/*会隐含地让cx-1*/ /*当cx为0时则退出循环 因此你设置cx为多少就循环就执行多少次 */
mov cx,次数 循环体 loop 标号
debug是用来调试代码
masm是用来编译代码
在处理某一方面不太一样
assume cs:code code segment mov ax,2000 mov al,[0] code ends end
我们首先看一下从test.asm到test.obj再到test.exe经过masm编译器运行后的代码
再对比一下我在debug上写的
可以发现debug会处理成[0]
而masm会处理成0
[0]
的含义是偏移地址
而0
的含义是一个内存单元
就效率而言[0]
更高,我们可以将代码mov al,[0]
改成mov al,ds:[0]
这样可以达到与debug一样的处理方式,效率也更高
在汇编程序中你要详细地设置好各个段以及作用,一个段最多只能容纳64KB的内存
我们利用assume设置了代码段,同理我们也可以设置栈段和数据段
assume cs:code,ss:stack,ds:data stack segment ... stack ends data segment ... data ends code segment ... code ends end
这里我定义code与cs链接起来,ss与stack链接起来,ds与data链接起来
这些段寄存器的作用不用多说了
其内存空间是由系统自动分配好的
我们无需再关心它到底是在哪一段,只需要知道其偏移地址即可,我们可以用BX寄存器索引数据段,sp索引栈段,ip索引代码段。
不过一般情况下我们只会去索引数据段
当设置的段多起来后我们需要一个标号来确定程序从哪开始,结束的是哪一段
assume cs:code,ss:stack,ds:data stack segment ... stack ends data segment ... data ends code segment start: ... ... code ends end start
这里我设置标号start,同时在下面的end伪指令表明我结束的是从start开始的那一段代码
dw指令类似于C语言里面的定义变量,不过有些不一样
在汇编里是定义一个整数或者更准确点你是定义一个4位十六进制数据
dw是定义一个字型数据(也就是定义一个占2字节的数据)
dw 1234 /* 定义字型数据1234H 类似于C语言的int a = 0x1234; */ dw 12 /*定义字型数据1200H*/
习惯上会在栈段和代码段那一块专门定义数据
虽然现在学得有限,但还是能从内存角度实现一些功能
下面代码能将data段的数据copy至stack段
assume cs:code,ds:data,ss:sg data segment dw 3031h,3233h,3435h,3637h,3839h /*注意加上h,否则会默认为十进制的3031*/ data ends sg segment stack dt 1 dup (0) /*这块的语法再下一节会有讲 可以忽略这行代码 */ sg ends code segment start: mov ax,data mov ds,ax mov bx,0 mov cx,10 s: push ds:[bx] add bx,2 loop s mov ax,4c00h int 21h code ends end start
同理依据内存操作,你还能完成其他的操作,比如清空内存、数据交换等
我们发现通用寄存器并不普通,似乎每个寄存器都具有特殊功能一样,但总体上就分为段寄存器、偏移地址寄存器、通用寄存器和标志寄存器(后续会讲)。
这三类具有一个最基本的功能,通用寄存器就是用来存储数据,段寄存器就是用来指向段,偏移地址寄存器就是指向段的偏移地址的内存
其余的功能如果你不使用你就可以只用它的基本功能
如果你在某一个块不用循环结构,那么CX就可以用来存储数据而不是专门去存储循环次数
如果在某一个程序不需要使用栈段,你就可以把SS指向的内存当作一个普通的内存,可以当成一个代码段也可以当成一个数据段