在代码段中使用数据
dw:在程序中定义字型数据,
暂且把书上的例子当作dw的用法和在代码段中使用数据例子吧
1 assume cs:code 2 code segment 3 dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 4 mov ax,0 5 mov cx,8 6 mov bx,0 7 s:add ax,cs:[bx] 8 add bx,2 9 loop s 10 11 mov ax,4c00h 12 int 21h 13 code ends 14 end
在这个例子中,CS:0到CS:10是dw定义的8个数据,而在11到25为程序执行的代码。
可以在debug中用u和d查看,考虑到这里不是实验,就不截图了。
cx的初值为26h,说明程序代码的到25h结束。
(老师上课多次强调:精确的反汇编是u ip的值 到cx-1)(也可写作 ip cx-1)
故用u命令可写为,-u 0010 0025
在该程序中由于IP初始值为0,需在debug中用r改动IP的初值为10h。所以较为不便。
注:db,dw,dd
除了dw 也可以用db和dd来定义数据
db定义字节类型变量,一个字节数据占1个字节单元,每次读取数据,读完一个偏移量加1 。
dw定义字类型变量,一个字数据占2个字节单元,每次读取数据,读完一个偏移量加2。
dd定义双字类型变量,一个双字数据占4个字节单元,每次读取数据时,读完一个偏移量加4。
assume cs:code code segment dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h start: mov ax,0 mov cx,8 mov bx,0 s:add ax,cs:[bx] add bx,2 loop s mov ax,4c00h int 21h code ends end start;end的用法二,指明执行start段的代码,可以通知编译器程序的入口所在
end的用法:
end 后什么也没有:程序运行到此结束
end 后加标号:标号为程序的入口点(标号相当于一个地址,而程序从标号处开始运行)
在代码段中使用栈
1 assume cs:codesg 2 codesg segment 3 dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 4 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;dw 16 dup(0) 重复定义16个内存单元 5
6 start: 7 mov ax,cs 8 mov ss,ax 9 mov sp,30h ;设置ss,sp 10 11 mov bx,0 12 mov cx,8 13 s: push cs:[bx] 14 add bx,2 15 loop s;将0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h入栈 16 17 mov bx,0 18 mov cx,8 19 s0: pop cs:[bx] 20 add bx,2 21 loop s0;将栈中的8个数据弹出到0----15单元中 22 23 mov ax,4c00h 24 int 21h 25 codesg ends 26 end start
1在debug中运行的时候,我们可以发现,cs:0-cs:0f是16给字节数据,cs:10-cs:2f是16个值为0的字节数据,在运行的过程中作为栈段
cx的值为58,精确的反汇编为 u 30 57(具体的截图可参见第六章的实验)
代码、数据、栈使用不同的段
在masm for windows 中默认的代码如下
1 DATAS SEGMENT 2 ;此处输入数据段代码 3 DATAS ENDS 4 5 STACKS SEGMENT 6 ;此处输入堆栈段代码 7 STACKS ENDS 8 9 CODES SEGMENT 10 ASSUME CS:CODES,DS:DATAS,SS:STACKS ;用asssume 将逻辑段和段寄存器关联起来; 11 START: 12 MOV AX,DATAS 13 MOV DS,AX 14 ;此处输入代码段代码 15 MOV AH,4CH 16 INT 21H 17 CODES ENDS 18 END START
在8086cpu中可以通过使用多个段,解决长度不能超过64KB的问题(一个段最长64KB)
注意点:
用伪指令segment和ends定义逻辑段。
用asssume 将逻辑段和段寄存器(ds ss sp )关联起来;
段名称代表段地址,是常数,不能直接送入段寄存器。(先送入ax)
ES附加段寄存器,可以将其作为,其他任意的段寄存器。