中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » 网络日志(Blog) » 【Redtek】 个人网志(学习笔记)
作者:
标题: 【Redtek】 个人网志(学习笔记) 上一主题 | 下一主题
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 61 楼』:  关于批处理嵌入超长汇编代码 使用 LLM 解释/回答一下

[原创][批处理单行显示多种颜色字符]
http://www.cn-dos.net/forum/viewthread.php?tid=25797&fpage=0&highlight=&page=2

上面贴子的第27楼:

  qzwqzw兄提到了:“从可读性上来讲,可以将汇编脚本分行下载批处理前段,这样的形式可以更好的注释”。

  感谢qzwqzw兄精彩的指点,原来水平无法实现这个功能,现在可以实现了:)

  而且根据qzwqzw兄指点,如果按这种方法做,可以在 .Bat 批处理中嵌入超长汇编代码,如嵌入数百行……

  也就是说可以执行非常复杂的汇编了,且还与批处理合二为一。

  而且,这种内嵌方式也解决了纯 MS-DOS 下命令行长度不能过长的一大障碍~:)


  如果哪天急了,还可以汇编、批处理、VBS三合一合写一个代码(晕晕……)

(刚才测试了一下,有一些障碍~:)

Last edited by redtek on 2006-12-23 at 06:14 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-24 06:46
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 62 楼』:   使用 LLM 解释/回答一下

简单做了一个批处理内嵌汇编代码的实验程序,其最主要的目地是为了完成特殊任务,同时不生成临时文件。




@echo off

:: 批处理嵌汇编代码实验
:: Redtek 2006 bbs.cn-dos.net

:start
::
::
:: 执行批处理代码段,绕开汇编代码段
Goto :BatStart

:masm
a
mov ah,09
mov dx,0109
int 21
int 20
db "My name is Redtek!$"

g
q


:BATStart

:: 装入当前批处理自身,并定cs代码段为 :masm 批处理标签段内。
:: echo exit|cmd /k prompt n %~s0$_l$_ …… (夭折喽~~)
:: 想到另一个办法~:)

echo exit|cmd /k more +10 %~s0|debug

:: Debug 执行后会显示所执行的过程,此功能可以用将来调用汇编代码来完成复杂计算或写盘,
:: 或调用Debug进行非显示方式的后台特殊工作。
::
::
::




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-24 07:27
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 63 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

连续的累加指定的内存单元,求和例程。
用 Debug 分析过程。


assume cs:code

code segment

mov ax,0ffffh
mov ds,ax
mov bx,0
mov dx,0

mov cx,12
s: mov al,
mov ah,0
add dx,ax
inc bx
loop s

mov ax,4c00h
int 21h

code ends
end




指令区别:

) Masm
  mov ax,
  将值0传送给ax寄存器

) Debug 汇编直译
  mov ax,
  相当于: (ax)= ((ds)*16+0)



) Debug 汇编直译
  mov ax,FFFF
  将 FFFFH 传送到 ax 寄存器

) Masm
  mov ax,0FFFFH
  功能同上。但在Masm汇编代码中,数据不能以字母开头,所以前必须加0


解决办法: Masm 中使用段前缀 mov ax,ds:
      相当于: (ax)=((ds)*16+0))

    

Last edited by redtek on 2006-12-24 at 09:42 AM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-24 10:13
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 64 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

安全内存空闲空间


在一般PC机中,DOS方式下,DOS和其他合法的程序一般都不会使用 0:200 ~~ 0:300(00200H~~00300H)的 256 个字节的空间。

所以,我们使用这段空间是安全的~:)



C:\WINDOWS>debug
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0100 NV UP EI PL NZ NA PO NC
0AF5:0100 3533D2 XOR AX,D233
-D 0:200 300
0000:0200 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0210 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0280 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0290 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02D0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:02F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0300 00 .
-Q




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-24 22:46
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 65 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

段前缀的使用


理解将内存 ffff:0 ~~ ffff:b 单元中的数据拷贝到 0:200~0:20b 单元中的过程。
0:200~~0:20b = 200:0 ~~ 200:b

通过循环拷贝地址中的内容,要初始化偏移地址变量bx,赋值循环次数变量cx,循环12次(0~~b)。

例程

;====================================================
;
;将内存 ffff:0 ~~ ffff:b 单元中数据拷贝到0:200~0:20b单元中
;
;====================================================

assume cs:code

code segment

mov bx,0 ; 偏移地址清零(也是从0开始)
mov cx,12 ; 循环12次
s: mov ax,0ffffh
mov ds,ax ; 改变ds段地址
mov dl,
mov ax,0020h
mov ds,ax ; 改变ds段地址,用于写内存
mov ,dl ; 将dl中的数据送入 0020:bx 内存
inc bx ; bx地址递增1
loop s

mov ax,4c00h
int 21h

code ends
end



执行后


C:\Masm50>debug p112.exe
-r
AX=0000 BX=0000 CX=001C DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 BB0000 MOV BX,0000
-d ffff:0 b
FFFF:0000 EA 5B E0 00 F0 30 34 2F-30 32 2F 30 .


(看一下执行前这段内存中的内容)

-
-d 0020:0 b
0020:0000 00 00 00 00 00 00 00 00-00 00 00 00 ............

(看一下上面要复制到的目标内存中的内容-没有内容)

-g

Program terminated normally

(上面 g 运行这段复制内存的代码)

(看一下执行完代码后, 0020:0 ~~ 0020:b 这段内容是否被复制过来内容了)

-d 0020:0 b
0020:0000 EA 5B E0 00 F0 30 34 2F-30 32 2F 30 .

(上面这段内存是从 ffff:0 ~~ ffff:b 这段内存所复制过来的)



关于上面代码循环的改进过程……


每循环都要设置改变两次ds段地址,但效率不高。
使用两个段寄存器分别存放单元 ffff:x 和目标单元 0020:x 的段地址,效率上会提高一些。

改进例程


assume cs:code

code segment

mov ax,0ffffh
mov ds,ax
mov ax,0020h
mov es,ax

mov bx,0

mov cx,12
s: mov dl,
mov es:,dl
inc bx
loop s

mov ax,4c00h
int 21h

code ends
end



上面蓝色标注是段前缀的使用,强制指定是哪一个段。


Debug 跟踪调试结果


C:\Masm50>debug p112-59.exe
-r
AX=0000 BX=0000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 B8FFFF MOV AX,FFFF
-d ffff:0 b
FFFF:0000 EA 5B E0 00 F0 30 34 2F-30 32 2F 30 .


0020:0000 00 00 00 00 00 00 00 00-00 00 00 00 ............-
-g

Program terminated normally
-
-d 20:0 b
0020:0000 EA 5B E0 00 F0 30 34 2F-30 32 2F 30 .-
-q




实验:


1) 编程,向内存 0:200~~0:23F 依次传送数据 0~63(3FH)。
   程序中只能使用 9 条指令。

第一次的代码写内存的顺序反了,哈哈……


-d 0:200 23f
0000:0200 3F 3E 3D 3C 3B 3A 39 38-37 36 35 34 33 32 31 30 ?>=<;:9876543210
0000:0210 2F 2E 2D 2C 2B 2A 29 28-27 26 25 24 23 22 21 20 /.-,+*)('&%$#"!
0000:0220 1F 1E 1D 1C 1B 1A 19 18-17 16 15 14 13 12 11 10 ................
0000:0230 0F 0E 0D 0C 0B 0A 09 08-07 06 05 04 03 02 01 00 ................


重来……


下面是重写的代码经过Debug调试后发现 0:200 地址处内容本该被写入 00H,结果并没有被写入。

经过Debug跟踪分析,原来我是用cx=3F经循环被Loop递减运算时,当Loop遇3F为0时,则退出了,所以这个00H没机会写入。

看来这种倒着写的方法有待改进:)

(下面是错误的内容)


-d 0:200 23f
0000:0200 3F 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F ?...............
0000:0210 10 11 12 13 14 15 16 17-18 19 1A 1B 1C 1D 1E 1F ................
0000:0220 20 21 22 23 24 25 26 27-28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0000:0230 30 31 32 33 34 35 36 37-38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?



调试正确的代码:


;--------------------------------------------------
; 向内存 0:200~~0:23F 依次传送数据 0~63(3FH)
;--------------------------------------------------

assume cs:code
code segment

mov ax,20h
mov ds,ax
mov bx,0h ; 设置偏移量

mov cx,64
s: mov ds:,bl
inc bx
loop s
mov ax,4c00h
int 21h

code ends
end




调试成功~:)


-d 0:200 23f
0000:0200 00 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F ................
0000:0210 10 11 12 13 14 15 16 17-18 19 1A 1B 1C 1D 1E 1F ................
0000:0220 20 21 22 23 24 25 26 27-28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0000:0230 30 31 32 33 34 35 36 37-38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?



如果没有 Debug 调试这个编译的 .exe 文件,根本没有办法直接发现程序中的问题。

越来越感觉到 Debug 就象是用于看到代程序过程并方便调试代码用的(批处理中的) Echo on 这样的命令~:)

而且,没有象 Debug 类似或是一样的工具帮助调试已编译了的代码,将寸步难行~:)


上面代码原理: 从偏移量 0~3F 一共有 64 个字节(因为偏移量0也算一个,刚才给忘了)
        所以设置循环 64 次。
        将 0:200 (段:偏移量)地址设置为 200:0000 地址( (段*16+偏移量) / 16 :0000 ),方便计算。
        所以 bx 寄存器中的偏移量就从 0000 开始计数了~:)
        只要计数累加偏移量到 64 时,那个cx计数器中的循环64次也正好结束,所有指定内存全都写入了。

Last edited by redtek on 2006-12-24 at 12:33 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-24 23:06
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 66 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

关于 Debug 的一个调试技巧



C:\Masm50>debug p113.exe
-r
AX=0000 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 B82000 MOV AX,0020
-u
0B49:0000 B82000 MOV AX,0020
0B49:0003 8ED8 MOV DS,AX
0B49:0005 BB0000 MOV BX,0000
0B49:0008 B94000 MOV CX,0040
0B49:000B 881F MOV ,BL
0B49:000D 43 INC BX
0B49:000E E2FB LOOP 000B


0B49:0010 B8004C MOV AX,4C00
0B49:0013 CD21 INT 21
0B49:0015 05508D ADD AX,8D50
0B49:0018 46 INC SI
0B49:0019 8050E83E ADC BYTE PTR ,3E
0B49:001D 0D83C4 OR AX,C483
-
-
-g 0010

AX=0020 BX=0040 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0020 ES=0B39 SS=0B49 CS=0B49 IP=0010 NV UP EI PL NZ AC PO NC
0B49:0010 B8004C MOV AX,4C00
-q



假如不再想跟踪调试上面绿色部分的代码了,想一下子执行完绿色部分的代码,
但只让程序执行到红色标注的代码处停止。

则可以用 g 命令加参数执行:

  G 0010

含义:从当前 CS:IP 指针处执行代码,执行到标号 0010 处停止。

Last edited by redtek on 2006-12-24 at 12:40 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-25 01:35
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 67 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

代码复制自身到另一块内存



) 下面的程序的功能是将 "mov ax,4c00h" 之前的指令复制到内存 0:200 处,补全程序。
  上机调试,跟踪运行结果。


;----------------------------------------
;
; 未完全的代码,待填补完
;
;----------------------------------------

assume cs:code

code segment

mov ax,
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,
s: mov al,
mov es:,al
inc bx
loop s

mov ax,4c00h
int 21h

code ends
end




根据以上代码思考问题:

1) 复制的是什么?从哪里到哪里?
2) 复制的是什么?有多少个?如何知道要复制的字节的数量?

根据上面代码,分析如下:

  (ds)*16+256B= cs 所以 cs =(ds)+10H
  
  复制的代码不能包括 “mov ax,4c00h” 与 “int 21h” 这两句,如何知道其长度?
  反汇编这两句代码信息如下:
  

  B8004C MOV AX,4C00
  CD21 INT 21
  

  其中:B8004C与CD21是上面 mov ……命令的机器码,数一下。机器码是:5个字节。

  所以,(代码总长度 - 5B )=要复制的代码长度。
  即: CX-5=要复制的但又不含上面两句指令的代码总长度。

  所以,循环次数是 cs-5 。cs中具体是多少要Debug调入才知道(或是根据经验数),不过咱们把循环次数瞎添一个就知道了。


下面是补全代码以后,唯一不知道总长度,也不知道要循环多少次。
所以,用汇编代码中的cx循环次数21是瞎写的,先占个长度,这样先能编译过去再说。

然后到了Debug中所看到的红色标注部分就是代码的总长度,我们再用总长度减那两条语句的机器码长度5字节,就是cx循环次数。


C:\Masm50>debug p113-1.exe
-r
AX=0000 BX=0000 CX=001C DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 8BC1 MOV AX,CS
-u
0B49:0000 8BC1 MOV AX,CS
0B49:0002 8ED8 MOV DS,AX
0B49:0004 B82000 MOV AX,0020
0B49:0007 8EC0 MOV ES,AX
0B49:0009 BB0000 MOV BX,0000
0B49:000C B91500 MOV CX,0015
0B49:000F 8A07 MOV AL,
0B49:0011 26 ES:
0B49:0012 8807 MOV ,AL
0B49:0014 43 INC BX
0B49:0015 E2F8 LOOP 000F
0B49:0017 B8004C MOV AX,4C00
0B49:001A CD21 INT 21
0B49:001C 3E DS:
0B49:001D 0D83C4 OR AX,C483
-q



长度为 0x001c ,再减那两条不包括的指令的5个字节,为 23 。即直要复制的代码长度为 23 个字节~:)


C:\Masm50>set /a 0x001c-5
23


我是用计算器算的,如果觉得用计算器算太麻烦,还可以向上面一样秀一下DOS命令~:)同样支持16进制与10进制混合运算~:)


补全后的代码


;----------------------------------------
;
; 补全后的代码,复制代码自身到内存0:200处
;
;----------------------------------------

assume cs:code

code segment

mov ax,cs
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,23
s: mov al,
mov es:,al
inc bx
loop s

mov ax,4c00h
int 21h

code ends
end




Debug跟踪过程,验证是否将自身代码复制到 0:200 处

下面是反汇编代码,方便参考。


C:\Masm50>debug p113-1.exe
-r
AX=0000 BX=0000 CX=001C DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 8CC8 MOV AX,CS
-u
0B49:0000 8CC8 MOV AX,CS
0B49:0002 8ED8 MOV DS,AX
0B49:0004 B82000 MOV AX,0020
0B49:0007 8EC0 MOV ES,AX
0B49:0009 BB0000 MOV BX,0000
0B49:000C B91700 MOV CX,0017
0B49:000F 8A07 MOV AL,
0B49:0011 26 ES:
0B49:0012 8807 MOV ,AL
0B49:0014 43 INC BX
0B49:0015 E2F8 LOOP 000F
0B49:0017 B8004C MOV AX,4C00
0B49:001A CD21 INT 21


下面是运行代码前的目标内存状态与运行代码后的目标内存状态


C:\Masm50>debug p113-1.exe
-r
AX=0000 BX=0000 CX=001C DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 8CC8 MOV AX,CS
-d 0:200
0000:0200 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0210 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-
-g

Program terminated normally
-d 0:200
0000:0200 8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A ..... ..........
0000:0210 07 26 88 07 43 E2 F8 00-00 00 00 00 00 00 00 00 .&..C...........
0000:0220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-q


  
下面是执行后的目标内存情况(被拷了过去)


-d 0:200
0000:0200 8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A ..... ..........
0000:0210 07 26 88 07 43 E2 F8 00-00 00 00 00 00 00 00 00 .&..C...........
0000:0220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................


反汇编被拷贝过去的目标内存


-u 0:200
0000:0200 8CC8 MOV AX,CS
0000:0202 8ED8 MOV DS,AX
0000:0204 B82000 MOV AX,0020
0000:0207 8EC0 MOV ES,AX
0000:0209 BB0000 MOV BX,0000
0000:020C B91700 MOV CX,0017
0000:020F 8A07 MOV AL,
0000:0211 26 ES:
0000:0212 8807 MOV ,AL
0000:0214 43 INC BX
0000:0215 E2F8 LOOP 020F


看一下主代码(进行复制的主代码)


C:\Masm50>debug p113-1.exe
-r
AX=0000 BX=0000 CX=001C DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 8CC8 MOV AX,CS
-u
0B49:0000 8CC8 MOV AX,CS
0B49:0002 8ED8 MOV DS,AX
0B49:0004 B82000 MOV AX,0020
0B49:0007 8EC0 MOV ES,AX
0B49:0009 BB0000 MOV BX,0000
0B49:000C B91700 MOV CX,0017
0B49:000F 8A07 MOV AL,
0B49:0011 26 ES:
0B49:0012 8807 MOV ,AL
0B49:0014 43 INC BX
0B49:0015 E2F8 LOOP 000F


Last edited by redtek on 2006-12-24 at 02:56 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-25 02:27
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 68 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

包含多个段的程序

程序取得所需空间的方法:

1) 加载程序的时候为程序分配
2) 程序在执行的过程中向系统申请


dw,字型数据。


在代码中使用数据例程


assume cs:code
code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
mov bx,0 ; 偏移量
mov ax,0
mov cx,8 ; 循环8次

s: add ax,cs: ; (ax)= ((ax)+(cs)*16+(bx))
add bx,2
loop s

mov ax,4c00h
int 21h

code ends
end




Debug 跟踪上面编译了的代码



反汇编看到其 dw 所定义的数据被定义到了代码段首(因为dw是第一条指令),其内容如下:


-d cs:0000 f
0B49:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............



但是,上面的代码会出现问题,因为前16个字节不是代码,而是我们定义的数据。


Debug 分析上面被编译之后的代码


C:\Masm50>debug p115.exe
-r
AX=0000 BX=0000 CX=0026 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 2301 AND AX, DS:0000=20CD
-u
0B49:0000 2301 AND AX,
0B49:0002 56 PUSH SI
0B49:0003 0489 ADD AL,89
0B49:0005 07 POP ES
0B49:0006 BC0AEF MOV SP,EF0A
0B49:0009 0DED0F OR AX,0FED
0B49:000C BA0C87 MOV DX,870C
0B49:000F 09BB0000 OR ,DI
0B49:0013 B80000 MOV AX,0000
0B49:0016 B90800 MOV CX,0008
0B49:0019 2E CS:
0B49:001A 0307 ADD AX,
0B49:001C 83C302 ADD BX,+02
0B49:001F E2F8 LOOP 0019

(上面列出的前16个字节是我们定义的数据,不是指令)


(下面才是我们定义的指令,但这批令应该在程序的入口: cs:ip )
(所以,有可能会出错)

-u cs:0010
0B49:0010 BB0000 MOV BX,0000
0B49:0013 B80000 MOV AX,0000
0B49:0016 B90800 MOV CX,0008
0B49:0019 2E CS:
0B49:001A 0307 ADD AX,
0B49:001C 83C302 ADD BX,+02
0B49:001F E2F8 LOOP 0019
0B49:0021 B8004C MOV AX,4C00
0B49:0024 CD21 INT 21
0B49:0026 00EB ADD BL,CH
0B49:0028 0590FF ADD AX,FF90
0B49:002B 86FE XCHG BH,DH
0B49:002D FEA15607 JMP
-q



在源程序中指明程序入口所在


assume cs:code
code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

start: mov bx,0
mov ax,0
s: add ax,cs:
add bx,2
loop s

mov ax,4c00h
int 21h

code ends
end start





Debug 跟踪上面编译了的代码


C:\Masm50>debug p116.exe
-r
AX=0000 BX=0000 CX=0023 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0010 NV UP EI PL NZ NA PO NC
0B49:0010 BB0000 MOV BX,0000
-u
0B49:0010 BB0000 MOV BX,0000
0B49:0013 B80000 MOV AX,0000
0B49:0016 2E CS:
0B49:0017 0307 ADD AX,
0B49:0019 83C302 ADD BX,+02
0B49:001C E2F8 LOOP 0016
0B49:001E B8004C MOV AX,4C00
0B49:0021 CD21 INT 21
0B49:0023 FEFE ??? DH
0B49:0025 0000 ADD ,AL
0B49:0027 EB05 JMP 002E
0B49:0029 90 NOP
0B49:002A FF86FEFE INC WORD PTR
0B49:002E A15607 MOV AX,
-q


发现 ip 已指向 10 ,cpu执行时跳过了数据区。

嘿嘿……开始奇怪了,越奇怪思考起来越有味道~:)
病毒?修改程序入口?还能干什么?原由?

比较结果:一个带 end start ,一个是 end ,比较入口不一样的地方


C:\Masm50\p>fc /b /a pok.exe pno.exe
正正在在比比较较文文件件 pok.exe 和和 PNO.EXE
00000012: AA BA
00000014: 10 00


改名比较



C:\Masm50\p>DEBUG POK.TXT
-D DS:100
0AF5:0100 4D 5A 23 00 02 00 00 00-20 00 00 00 FF FF 00 00 MZ#..... .......
0AF5:0110 00 00 AA 50 10 00 00 00-1E 00 00 00 01 00 00 00 ...P............
0AF5:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-Q

C:\Masm50\p>DEBUG PNO.TXT
-R
AX=0000 BX=0000 CX=0223 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0100 NV UP EI PL NZ NA PO NC
0AF5:0100 4D DEC BP
-D DS:100
0AF5:0100 4D 5A 23 00 02 00 00 00-20 00 00 00 FF FF 00 00 MZ#..... .......
0AF5:0110 00 00 BA 50 00 00 00 00-1E 00 00 00 01 00 00 00 ...P............
0AF5:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0AF5:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-Q

C:\Masm50\p>FC /B POK.TXT PNO.TXT
正正在在比比较较文文件件 pok.txt 和和 PNO.TXT
00000012: AA BA
00000014: 10 00



FC 执行比较的以后,将它的输出信息copy到这里居然显示“双影儿”字了,哈哈……

fc /b pok.txt pno.txt >test.txt之后,再用Debug重写一个新文件,再次16进制写这几个字,看看是不是重影儿?

打开记事这回是,copy 粘到这里。


正在比较文件 pok.txt 和


记事本内copy这内容看来没事儿,刚才重影是在 cmd 里直接copy 的……

type test.txt 一下,cmd 里copy ^

正正在在比比较较文文件件 pok.txt


好玩……

copy con a.txt 新建一个,直接打字看看 type 出来是什么……

正在比较文件 pok.tx


16进制一样,唯一区别就是 cmd 直接copy,刚一放到 里一粘就是双影,比较剪辑板?晕………………………………

会不会和 fc 在 cmd 中的输出方式有关?它用了另一种方式显示字符?
而这种方式显示的字符当 copy 到剪辑板时就变成了双字?
看来 echo 是达不到这种效果……
我看到的 fc 的输出和我copy出来的不同……
用这种方法进行防批处理运算结果输出中的防拷贝?

测试 fc 比较文件后,输出了一串中文字信息……
然后直接在cmd里鼠标右键选择copy……一粘结果还是双字……
奇怪………………

Last edited by redtek on 2006-12-24 at 10:49 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-25 05:28
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
electronixtar
铂金会员





积分 7493
发帖 2672
注册 2005-9-2
状态 离线
『第 69 楼』:   使用 LLM 解释/回答一下

牛人,顶

2006-12-25 07:24
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
ccwan
金牌会员




积分 2725
发帖 1160
注册 2006-9-23
来自 河北廊坊
状态 离线
『第 70 楼』:   使用 LLM 解释/回答一下

顶,人牛!



三人行,必有吾师焉。 学然后知不足,教然后知困,然后能自强也。
2006-12-25 07:44
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 71 楼』:   使用 LLM 解释/回答一下

多谢两位仁兄鼓励:)
人牛?饶了我吧,嘿嘿……应该一边看着汇编一边咬着牛肉干儿~:)`````



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-25 10:58
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 72 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

数据、代码、栈在不同的段中使用


是圣诞节?时间流逝,冲刺……


1) 代码、数据、栈放到同一个段中会使程序混乱,难以维护。
2) 如果数据、栈、代码需要的空间超过64KB,就不能放在一个段中。
   不同的安排放到不同意义标识的段中,更使代码清晰容易扩展。

将数据、代码、栈放到不同的段中,例程分析:



) 在定义 stack 栈段的代码中,编译器编译给出 "no stack segment" 警告,在 Google.com 查询到的解决办法:

  问: 已在程序中设有如下定义:STACK SEGMENT ……为什么LINK 仍然警告:no stack segment ?

  答:将段定义修改为:STACK SEGMENT STACK ;后面的STACK项是组合类型,即不再出现警告信息。


多段方式的代码


assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,,0defh,0fedh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack ; start入口
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
mov bx,0
mov cx,8
s: push
add bx,2
loop s
mov bx,0
mov cx,8
s0: pop
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start



编译可执行文件后用Debug调试,发现一个错误~:)
发现多了个 00H 00H ,源代码中定义的数据什么时候定义了这个东东?
后来一数,是多了一个数据 00H 00H ,原来是写源代码的时候多加一个逗号,编译器认为这是合法的一个数据 00 00 。


-d ds:0000
0B49:0000 23 01 56 04 89 07 BC 0A-00 00 EF 0D ED 0F BA 0C #.V.............
0B49:0010 87 09 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B49:0020 00 00 13 00 4C 0B 59 05-BC 0A 89 07 56 04 23 01 ....L.Y.....V.#.
0B49:0030 B8 4B 0B 8E D0 BC 10 00-B8 49 0B 8E D8 BB 00 00 .K.......I......
0B49:0040 B9 08 00 FF 37 83 C3 02-E2 F9 BB 00 00 B9 08 00 ....7...........
0B49:0050 8F 07 83 C3 02 E2 F9 B8-00 4C CD 21 FE 89 96 FC .........L.!....
0B49:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B49:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P


绿色标注相当于源代码中的:


data segment
dw 0123h,0456h,0789h,0abch,,0defh,0fedh,0cbah,0987h
data ends


红色标记是源代码中多打了个逗号所占位的。

蓝色标记为栈空间预留,相于源代中的


stack segment
dw 0,0,0,0,0,0,0,0
stack ends


然后再 Debug 调试,紧接着就是这个有意思的错误。
但如果在 MS-DOS 下调试则没有问题,因为栈并没有越界,它就算是“指针”越界,但数据不会越界(数据长度刚刚好)。
可见(个人目前认为) CMD 太严格了!

Last edited by redtek on 2006-12-25 at 11:19 AM ]

附件 1: 1.GIF (2006-12-26 00:19, 14.91 KiB, 下载附件所需积分 1 点 ,下载次数: 2)




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-25 22:03
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 73 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

编写调试跟踪多段程序

一个小窍门

刚才希望截取 Debug 操作的过程文字,结果内容过长,无法 copy 文件。
试着Debug输出内容重向到一个文本文件内,好是好,只是生成了临时文件。

想了想发现一个好玩的办法,不生成临时文件,直接将操作过程管道输出到剪辑板内,然后我往论坛一粘就行了~:)

不过,所输出的内容是不会显示到屏幕上的。但是用熟了也用着显示什么,知道自己键入的是什么应该出现些什么就行了。


debug p123.exe|clip




下面源代码编译后调试跟踪过程

assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov ax,data
mov ds,ax
push ds:
push ds:
pop ds:
pop ds:
mov ax,4c00h
int 21h
code ends
end start




试调上面编译过的源代码


-r

AX=0000 BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B4B IP=0000 NV UP EI PL NZ NA PO NC
0B4B:0000 B84A0B MOV AX,0B4A
-u

0B4B:0000 B84A0B MOV AX,0B4A
0B4B:0003 8ED0 MOV SS,AX
0B4B:0005 B8490B MOV AX,0B49
0B4B:0008 8ED8 MOV DS,AX
0B4B:000A FF360000 PUSH
0B4B:000E FF360200 PUSH
0B4B:0012 8F060200 POP
0B4B:0016 8F060000 POP
0B4B:001A B8004C MOV AX,4C00
0B4B:001D CD21 INT 21
0B4B:001F 8B87BE22 MOV AX,
-d cs:0

0B4B:0000 B8 4A 0B 8E D0 B8 49 0B-8E D8 FF 36 00 00 FF 36 .J....I....6...6
0B4B:0010 02 00 8F 06 02 00 8F 06-00 00 B8 00 4C CD 21 8B ............L.!.
0B4B:0020 87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1 .."..."t........
0B4B:0030 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC ...."...".......
0B4B:0040 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B4B:0050 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
0B4B:0060 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8 .op......P....P.
0B4B:0070 CA 0C 83 C4 04 B8 FF FF-50 8D 86 00 FF 50 8D 46 ........P....P.F
-d ss:0

0B49:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............
0B49:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B49:0020 B8 4A 0B 8E D0 B8 49 0B-8E D8 FF 36 00 00 FF 36 .J....I....6...6
0B49:0030 02 00 8F 06 02 00 8F 06-00 00 B8 00 4C CD 21 8B ............L.!.
0B49:0040 87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1 .."..."t........
0B49:0050 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC ...."...".......
0B49:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B49:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
-d ds:0

0B39:0000 CD 20 FF 9F 00 9A F0 FE-1D F0 4F 03 59 05 8A 03 . ........O.Y...
0B39:0010 59 05 17 03 59 05 48 05-01 03 01 00 02 FF FF FF Y...Y.H.........
0B39:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 06 0B 4C 01 ..............L.
0B39:0030 19 0A 14 00 18 00 39 0B-FF FF FF FF 00 00 00 00 ......9.........
0B39:0040 05 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B39:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!...........
0B39:0060 20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20 .....
0B39:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........
-q




代码装入执行前与执行改变栈地址之后的数据对比


-R
AX=0000 BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B4B IP=0000 NV UP EI PL NZ NA PO NC
0B4B:0000 B84A0B MOV AX,0B4A
-T

AX=0B4A BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B4B IP=0003 NV UP EI PL NZ NA PO NC
0B4B:0003 8ED0 MOV SS,AX
-T

AX=0B49 BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B4A CS=0B4B IP=0008 NV UP EI PL NZ NA PO NC
0B4B:0008 8ED8 MOV DS,AX
-D SS:0
0B4A:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B4A:0010 B8 4A 0B 8E D0 B8 49 0B-8E D8 FF 36 00 00 FF 36 .J....I....6...6
0B4A:0020 02 00 8F 06 02 00 8F 06-00 00 B8 00 4C CD 21 8B ............L.!.
0B4A:0030 87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1 .."..."t........
0B4A:0040 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC ...."...".......
0B4A:0050 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B4A:0060 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
0B4A:0070 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8 .op......P....P.
-D 0B49:0
0B49:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............
0B49:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B49:0020 B8 4A 0B 8E D0 B8 49 0B-8E D8 FF 36 00 00 FF 36 .J....I....6...6
0B49:0030 02 00 8F 06 02 00 8F 06-00 00 B8 00 4C CD 21 8B ............L.!.
0B49:0040 87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1 .."..."t........
0B49:0050 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC ...."...".......
0B49:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B49:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P


上面是代码装入执行前和改变栈ds的对比,根据上面对比再对比整个代码使用内存的变化。


C:\Masm50>debug p123.exe
-r
AX=0000 BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B4B IP=0000 NV UP EI PL NZ NA PO NC
0B4B:0000 B84A0B MOV AX,0B4A
-d ss:0
0B49:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............
0B49:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B49:0020 B8 4A 0B 8E D0 B8 49 0B-8E D8 FF 36 00 00 FF 36 .J....I....6...6
0B49:0030 02 00 8F 06 02 00 8F 06-00 00 B8 00 4C CD 21 C7 ............L.!.
0B49:0040 02 75 48 89 3E E6 99 FF-06 E6 99 C6 06 E8 99 FF .uH.>...........
0B49:0050 C6 06 E9 99 00 E8 99 00-AC E8 29 E2 74 38 3C 0D ..........).t8<.
0B49:0060 74 34 3A 06 B6 96 74 2E-3A C3 74 2A 3C 3A 74 03 t4:...t.:.t*<:t.
0B49:0070 E9 5F FF 80 3E A4 98 02-75 05 E8 74 00 EB D9 46 ._..>...u..t...F



红色标注为 ss 栈段在代码执行前未重新分配时的状态,ss 基地址批向数据在源代码中的定义:



data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends


而紧跟着它后面的数据 00 00 ……则是为栈安排存储区,它在代码中是这样定义的


stack segment
dw 0,0,0,0,0,0,0,0
stack ends


上面的定义这才是应该为栈分配的空间。

而在这一片 “内存区域” 的后面才是代码入口 ( end start ),cs段地址为:0B4BH

执行前:


|______PSP____|____ss=0b49=8个dw定义的字数据___后8个字00为栈分配___共32字节__|__代码段: cs=0b4b__|


执行后(只执行 为ss栈赋值后),则变化如下:

其 ss=B4A0 ,被定义到了原来的栈与代码段之间了(即向下移了16个字节),
由原来装入时的 SS=0B49 向下移了 16字节。
变为: SS=B4A0。

那么 SS=B4A0 它将指向哪里?见上面反汇编分析,其指向了 dw 0,0,0……在源代码中所定义的栈区。

这是为了方便压栈用。

分析:

) CPU执行程序,程序返回前,data 段中的数据为多少?

  

  -d ds:0
  0B49:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09
  



) CPU执行程序,程序返回前,CS=? SS=? DS=?

  CS=0B4B  SS=0B4A  DS=0B49


) 设程序加载后,code段的段地址为X,则data段的段地址为?
  stack段的段地址为?


  stack段的段地址为: stack=(cs)*16+0B-32B
  data段的段地址为:  data=(cs)*16+0B-32B - 100H



编译下面代码,用Debug加载、跟踪、调试……


assume cs:code,ds:data,ss:stack

data segment
dw 0123h,0456h
data ends

stack segment
dw 0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:
push ds:
pop ds:
pop ds:
mov ax,4c00h
int 21h

code ends
end start




) CPU执行程序,程序返回前,data段中的数据为多少?
  
  DS = 0B49
  DS = 23 01 56 04


) CPU执行程序,程序返回前, CS、SS、DS都是多少?

  DS=0B49 SS=0B4A CS=0B4B


) 设程序加载后,code段的段地址为X,则data段的段地址为?
  stack段的段地址为?

  stack段的段地址为: ( (X)*16 - 32B) / 16
  data 段的段地址为: ( (X)*16 - 32B - 256B) ) / 16
  


) 对于如下定义的段:

  name segment
   ...
  name ends

  如果段中的数据占N个字节,则程序加载后,该段实际占有空间为?

  答:如果 N < FH ,则实际占用 FH 字节。



简单总结:

(到这里,发现一个例子反复的跟踪和对比源代码被编译并反汇编后的“样子”是绝对值得的,直到脑子里已经形成视图为止。)

(每一个基础如果不打好,就向下走,会学得非常快,但越向后学难度越大、难以逾越的障碍就会越多,能力难以再提高。)

(汇编离不开Debug等调试工具,没了这些工具寸步难行。汇编学机器原理,Debug了解真象。)



将下面的程序编译连接,则Debug加载、跟踪……



assume cs:code,ds:data,ss:stack
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:
push ds:
pop ds:
pop ds:
mov ax,4c00h
int 21h
code ends
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
end start




分析:


  {PSP}{代码}{数据}{栈}




) CPU执行程序,程序返回前,data段中的数据为多少?
  
  DS=0B4C
  0B4C:0000 23 01 56 04


) CPU执行程序,程序返回前,CS=? SS=? DS=?

  SS=0B4D CS=0B49 DS=0B4C


) 设程序加载后,code段的段地址为X,则data段的段地址为?
  stack段的段地址为?


  因为 code 段之前没  stack、data 等数据,只有 psp所占用的256B。
  所以 data 段地址为: ((CS)*16 - 256B )/ 16
  公式写得不太标准。因为文件一被装入,data段自然指向PSP,而stack与data段都在code段后面,
  所以code段地址(CS)向回移255B就是PSP。

  CX=44H 即:寄存器代码长度为:68 B
  实际手工数代码长度为:34 B
  则 68B - 34B = 34 B  则视图如下:{有效代码占34B+补满F}{data+补满到F + stack实际占用}
  (上面只是视图,不是真正计算方法)
  (因为代码结束后的空余空间在F以前是不再用了,为了整除方便)
  (所以,再有数据,如栈和数据段的超始地址都是可以将来被16整除的地址,这是最重要的一点)


  即: CX代段总长度 - (DATA: dw 0123h,0456h 独占的16倍数的起始行 = 16字节) == DATA段基地址
     (CX=68B)-(DATA: 16B)-(最后的stack所真实占用的4B)= 48B(CS段的偏移量)
     (CS=0B49H)+48B =0B4CH (这是求出的段地址)

  *  现在我们求出了已知CS地址,所以DATA段的地址为: 0B4CH
     那么假如 CS=X ,则DATA段地址为: ((x)*16+48B)/16
  
  *  既然已知DATA段地址了,那么STACK只不过是它向下的一个F篇移量,则STACK= (((x)*16+48B)/16)+16B


下面是一些求得如下公式的推理验证。

-d ss:0
0B49:0000 B8 4D 0B 8E D0 BC 10 00-B8 4C 0B 8E D8 FF 36 00
0B49:0010 00 FF 36 02 00 8F 06 02-00 8F 06 00 00 B8 00 4C
0B49:0020 CD 21 00 00 00 00 00 00-00 00 00 00 00 00 00 00

(上面 CD 21 就是代码结束了)


(下面 23 01 56 04 是 dw 0123H,0456H 所定义的数据。)


0B49:0030 23 01 56 04 00 00 00 00-00 00 00 00 00 00 00 00



(下面 00 00 00 是 stack 段在源代码中 dw 0,0 定义的栈空间)
(它们的特点:都是新起一行:)


0B49:0040 00 00 00 00 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1
0B49:0050 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC
0B49:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05
0B49:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50



(它们为什么都要新起一行来存有被定义的新数据?)
(个人理解:)

(这是带有偏移量的数据,如果计算为无偏移量物理地址为:0B4E:1)
(当 MOV AX,0B4E:1 显然无法赋值)
(但 MOV AX,B4E1  表面上看上去是物理地址,但它不是相对段地址,所以更是出错)
(所以,偏移量只要的后面有0,方便段的物理地址(段)*16+偏移量,它的物理地址低位是0,方便再转为无偏移量

的段地址)


-d 0b4d:11
0B4D:0010 00 15 00 49 0B 59 05-56 04 23 01 FE 89 96 FC
0B4D:0020 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05
0B4D:0030 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50
0B4D:0040 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8
0B4D:0050 CA 0C 83 C4 04 B8 FF FF-50 8D 86 00 FF 50 8D 46
0B4D:0060 80 50 E8 4D FA 83 C4 06-0A C0 75 03 E9 7B FF 5E
0B4D:0070 8B E5 5D C3 83 3E 56 07-20 72 0A B8 1C 04 50 E8
0B4D:0080 62 44 83 C4 02 B8 FF FF-50 B8 05 00 50 8D 86 7A
0B4D:0090 FE

-d 0b4e:1
0B4E:0000 00 15 00 49 0B 59 05-56 04 23 01 FE 89 96 FC
0B4E:0010 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05
0B4E:0020 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50
0B4E:0030 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8
0B4E:0040 CA 0C 83 C4 04 B8 FF FF-50 8D 86 00 FF 50 8D 46
0B4E:0050 80 50 E8 4D FA 83 C4 06-0A C0 75 03 E9 7B FF 5E
0B4E:0060 8B E5 5D C3 83 3E 56 07-20 72 0A B8 1C 04 50 E8
0B4E:0070 62 44 83 C4 02 B8 FF FF-50 B8 05 00 50 8D 86 7A
0B4E:0080 FE



经过分析,反汇编代码 CD 21 (代码结束了)之后是 00 00 ……
因为刚才分析出必须是(段)*16+偏移量以后,其低位必须有0……
这样形容:就是当段地址*16+偏移量的物地址必须能被16整除才可以。




简单总结:

  上面的计算方法并不难,写了这么多笔记是为了推出它们的规律和都是为什么。背一个公式有记记力就行了,那么没有公式的时候怎么办?只能推出解决办法。要想找到解决办法就必须从源代码与反汇编的真实代码之间找到它们的规律,
  要找出规律就得用基础知识反复的验算。验算过程中就会发现很多不解的内容,如:为什么要空出一部分空间不用?为什么要新起一行才可以?这些书上没有,怎么办?一遍一遍推,一遍遍算,就会发现很多内容全是基础知识的扩充。



程序的入口地址分析

code segment
start: mov ax,stack ………………
………………
code ends
end start

如果没有在源代码中标出程序入口标置会怎么样?什么样的源代码未标置程序入口就不会运行?

分析如下:


assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov ax,data
mov ds,ax
push ds:
push ds:
pop ds:
pop ds:
mov ax,4c00h
int 21h
code ends
end



编译后的可执行文件,代码入口就是源代码中按顺序放的数据,哈哈……无法运行~:)
从这里就可以看到 Start 与 end Start 的重要性了,它指出了代码结束与代码入口地址。不过start可以随便启名:)


C:\Masm50>debug aaa.exe
-r
AX=0000 BX=0000 CX=003F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B3B ES=0B3B SS=0B4B CS=0B4B IP=0000 NV UP EI PL NZ NA PO NC
0B4B:0000 2301 AND AX, DS:0000=20CD
-u
0B4B:0000 2301 AND AX,
0B4B:0002 56 PUSH SI
0B4B:0003 0489 ADD AL,89
0B4B:0005 07 POP ES
0B4B:0006 BC0AEF MOV SP,EF0A
0B4B:0009 0DED0F OR AX,0FED
0B4B:000C BA0C87 MOV DX,870C
0B4B:000F 0900 OR ,AX
0B4B:0011 0000 ADD ,AL
0B4B:0013 0000 ADD ,AL
0B4B:0015 0000 ADD ,AL
0B4B:0017 0000 ADD ,AL
0B4B:0019 0000 ADD ,AL
0B4B:001B 0000 ADD ,AL
0B4B:001D 0000 ADD ,AL
0B4B:001F 00B84C0B ADD ,BH




) 将 A 段和 B 段中的数据依次相加,将结果 C 段中。 



assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c segment
db 0,0,0,0,0,0,0,0
c ends

code segment
start: mov ax,a ; A 段
mov ds,ax
mov dx,b ; B 段
mov es,dx
mov bx,c ; C 段
mov ss,bx

mov bx,0 ; 清零
mov cx,8

s: mov al,ds: ; 把 A 段数据送入 AL
add al,es: ; 将 A 段数据与 B 段偏移量为BX的数据相加,结果送入AL
mov ss:,al ; 把最相加结果送入目标 S 段偏移量为bx处
add bx,1 ; “指针”递增 1
loop s

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



调试结果

-d ds:0
0B4B:0000 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
0B4B:0010 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
0B4B:0020 02 04 06 08 0A 0C 0E 10-00 00 00 00 00 00 00 00 ................
0B4B:0030 B8 4B 0B 8E D8 BA 4C 0B-8E C2 BB 4D 0B 8E D3 BB .K....L....M....
0B4B:0040 00 00 B9 08 00 8A 07 26-02 07 36 88 07 83 C3 01 .......&..6.....
0B4B:0050 E2 F3 B8 00 4C CD 21 C0-22 89 86 FA FE 89 96 FC ....L.!.".......
0B4B:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B4B:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
-d es:0
0B4C:0000 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
0B4C:0010 02 04 06 08 0A 0C 0E 10-00 00 00 00 00 00 00 00 ................
0B4C:0020 B8 4B 0B 8E D8 BA 4C 0B-8E C2 BB 4D 0B 8E D3 BB .K....L....M....
0B4C:0030 00 00 B9 08 00 8A 07 26-02 07 36 88 07 83 C3 01 .......&..6.....
0B4C:0040 E2 F3 B8 00 4C CD 21 C0-22 89 86 FA FE 89 96 FC ....L.!.".......
0B4C:0050 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B4C:0060 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
0B4C:0070 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8 .op......P....P.
-d ss:0
0B4D:0000 02 04 06 08 0A 0C 0E 10-00 00 00 00 00 00 00 00 ................
0B4D:0010 B8 4B 0B 8E D8 BA 4C 0B-8E C2 BB 4D 0B 8E D3 BB .K....L....M....
0B4D:0020 00 00 B9 08 00 8A 07 26-02 07 36 88 07 83 C3 01 .......&..6.....
0B4D:0030 E2 F3 B8 00 4C CD 21 C0-22 89 86 FA FE 89 96 FC ....L.!.".......
0B4D:0040 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B4D:0050 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P
0B4D:0060 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8 .op......P....P.
0B4D:0070 CA 0C 83 C4 04 B8 FF FF-50 8D 86 00 FF 50 8D 46 ........P....P.F



) 用 push 指令将 a 段中 word 数据逆序存储到 b 段中。




assume cs:code
a segment
dw 1,2,3,4,5,6,7,8
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start:
mov ax,a
mov ds,ax ; 定义数据段 A
mov ax,b
mov es,ax ; 定义目标数据段 B
mov ax,0020h ; 定义栈使用安全空间
mov ss,ax ; 定义栈
mov sp,100
mov bx,0 ; 清零
mov cx,8
s0: push ds: ; 数据段偏移量为的数据压栈
add bx,2
loop s0
mov bx,0
mov cx,8
s1: pop es: ; 逆序弹出存到 B 段
add bx,2
loop s1
mov ax,4c00h
int 21h
code ends
end start



跟踪结果如下


-d es:0
0B4C:0000 08 00 07 00 06 00 05 00-04 00 03 00 02 00 01 00
0B4C:0010 B8 4B 0B 8E D8 B8 4C 0B-8E C0 B8 20 00 8E D0 BC
0B4C:0020 64 00 BB 00 00 B9 08 00-FF 37 83 C3 02 E2 F9 BB
0B4C:0030 00 00 B9 08 00 26 8F 07-83 C3 02 E2 F8 B8 00 4C
0B4C:0040 CD 21 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC
0B4C:0050 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05
0B4C:0060 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50
0B4C:0070 E8 6F 70 83 C4 06 B8 CD-05 50 8D 86 00 FF 50 E8


Last edited by redtek on 2006-12-26 at 11:21 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-26 01:12
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 74 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

灵活定位内存地址


and和or指令


) and 指令
  都为1时为1,否则为0
  通过该指令可将操作对象的相应位设为0,其它位不变。

    设: al,01100011B

    将 al 的第6位设为0: and al,10111111B
    将 al 的第7位设为0: and al,01111111B
    将 al 的第0位设为0: and al,11111110B


) or 指令
  都为1时为1,或有一个为1时也为1,否则为0
  通过该指令可将操作对象的相应位设为1,其它位不变。

    设: mov al,01100011B

    将 al 的第6位设为1: or al,01000000B
    将 al 的第7位设为1: or al,10000000B
    将 al 的第0位设为1: or al,00000001B




对比源代码定义数据与编译后的可执行文件


assume ds:data,cs:code
data segment
db 'unIX'
dw 1,2,3
db 'foRK'
data ends
code segment
start:
code ends
end start



见到可执行文件其上所定义的数据存放形式


-d ss:0
0B49:0000 75 6E 49 58 01 00 02 00-03 00 66 6F 52 4B E2 70 unIX......foRK.p
0B49:0010 83 C4 06 B8 C8 05 50 8D-46 80 50 E8 3E 0D 83 C4 ......P.F.P.>...
0B49:0020 04 C7 86 FE FE 00 00 EB-05 90 FF 86 FE FE A1 56 ...............V
0B49:0030 07 39 86 FE FE 73 7D 8B-9E FE FE D1 E3 D1 E3 8B .9...s}.........
0B49:0040 87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1 .."..."t........
0B49:0050 E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC ...."...".......
0B49:0060 FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05 .....&.G.*.@P...
0B49:0070 0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50 ..RP..F...P....P



它们是连续存放的~:)
经过分析发现原来源代码中将这些数据定义在一个标号所段内,它们就是连续存放的。如果分开定义,它们就是单独占FH。


下面对比单独定义数据,看它们是如何分布的~:)


assume cs:code,ds:data_1
data_1 segment
db 'Redtek'
data_1 ends
data_2 segment
db '2006.12.27'
data_2 ends
code segment
start: mov ax,4c00h
int 21h
code ends
end start


Debug 分析它的分布……


-d ss:0
0B49:0000 52 65 64 74 65 6B 00 00-00 00 00 00 00 00 00 00 Redtek..........
0B49:0010 32 30 30 36 2E 31 32 2E-32 37 00 00 00 00 00 00 2006.12.27......


上面这两段数据的“间隔”起始偏移地址都相差FH,为了取首地址和定位方便~:)


将字符串中的第一行 “BaSiC” 字母全转成大写


assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'iNfOrmaTiOn'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax ; 取数据段首地址
mov bx,0
mov cx,5
s: mov al,ds:
and al,11011111b ; 转所有字母为大写
mov ds:,al
inc bx
loop s
mov ax,4c00h
int 21h
codesg ends
end start



跟踪结果


-d ds:0
0B49:0000 42 41 53 49 43 69 4E 66-4F 72 6D 61 54 69 4F 6E BASICiNfOrmaTiOn



把第一行字符串全转成大写,第二行字符串全转成小写字母


assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'iNfOrmaTiOn'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax ; 取数据段首地址
mov bx,0
mov cx,5
s: mov al,ds:
and al,11011111b ; 转所有字母为大写
mov ds:,al
inc bx
loop s

mov bx,5
mov cx,11 ; 设置循环11次,因为字母长度为11
s1: mov al,
or al,00100000b
mov ,al
inc bx
loop s1

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



用 Debug 跟踪结果


-d ds:0
0B49:0000 42 41 53 49 43 69 6E 66-6F 72 6D 61 74 69 6F 6E BASICinformation



如果要是用到批处理里呢?


C:\WINDOWS>set /a 0X61 "&" 0xDF
65


C:\WINDOWS>set /a 97 "&" 0XDF
65
C:\WINDOWS>


0X61是小写字母 a 的 ASCII 码的16进制表现形式。a 的10进制 ASCII 码是 97

“&” 符号在批处理的 SET /? 命令帮助中是:“与” 操作。

我们最后结果所得到的 65 ,就是大写字母 A 的 10 进制的 ASCII 码表现形式。

怎么验证 65 就是大写字母 A ? ALT+65 的按键操作就出来了~:)



[bx+idta]


一种更灵活的寻址方式,它的偏移地址为(bx)+idata决定~:)

将一个内存单元的内容送入AX,这个内存单元长度为2字节(字单元),存放一个字,偏移地址为bx中数值+200,段地址在ds中。

数学化描述为: (ax)=((ds)*16+(bx)+200)

该指令也可以写成如下格式:

  mov ax,
  mov ax,200
  mov ax,.200


下面是随便一个例子,对比上面三种命令格式机器码中的表示。


assume cs:code
code segment
start: mov ax,'aa'
mov bx,10h
mov ax,
mov ax,200
mov ax,.200

mov ax,4c00h
int 21h

code ends
end start




Debug 反汇编看到机器码与反汇编指令如下:


0B49:0000 B86161 MOV AX,6161
0B49:0003 BB1000 MOV BX,0010
0B49:0006 8B87C800 MOV AX,
0B49:000A 8B87C800 MOV AX,
0B49:000E 8B87C800 MOV AX,
0B49:0012 B8004C MOV AX,4C00
0B49:0015 CD21 INT 21


经过对比发现,机器码是一样的,看来这些格式全是MASM干的~:)


用方式进行数组处理
使用数组原理实现将“两行”不同地址的字符串(第一行转大写,第二行转小写)


assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'MinIX'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,5
s: mov al,
and al,11011111b ; 转大写
mov ,al ; 转换完以后送回原处
mov al,5
or al,00100000b ; 转小写
mov 5,al ; 转完小写后再送回去
inc bx
loop s
mov ax,4c00h
int 21h
codesg ends
end start




Debug 验证转换结果


-d ds:0
0B49:0000 42 41 53 49 43 6D 69 6E-69 78 00 00 00 00 00 00 BASICminix......



SI 和 DI

SI 和 DI 是 8086CPU中和bx功能相近的寄存器,SI和DI不能够分成两个8位寄存器来使用。

示例三组指令实现了相同的功能:


1) mov bx,0
   mov ax,

2) mov si,0
   mov ax,

3) mov di,0
   mov ax,

下面三组指令也实现了相同的功能:


1) mov bx,0
   mov ax,

2) mov si,0
   mov ax,

3) mov di,0
   mov ax,



SI 和 DI 复制字符串到另一地址


assume cs:code,ds:data
data segment
db 'welcome to masm!'
db '................'
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0 ; 源变址
mov di,16 ; 目地变址
mov cx,8
s: mov ax,
mov ,ax
add si,2
add di,2
loop s
mov ax,4c00h
int 21h
code ends
end start




更少代码的示例,Debug 分析过程……


assume cs:code,ds:data
data segment
db 'welcome to masm!'
db '................'
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,8
s: mov ax,0
mov 16,ax
add si,2
loop s
mov ax,4c00h
int 21h
code ends
end start







例: mov ax, 的含义
   将一个内存单元的内容(字单元)送入ax寄存器,偏移地址为bx+si,段地址在ds中。

描述: (ax)=((ds)*16+(bx)+(si))

Debug 查看……


assume cs:code

code segment
start: mov ax,2000h
mov ds,ax
mov bx,1000h
mov si,0
mov ax,
inc si
mov cx,
inc si
mov di,si
add cx,

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





数学描述: (ax)=((ds)*16+(si)+(idata))


assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,1000h
mov si,0
mov ax,
inc si
mov cx,
inc si
mov di,si
mov bx,
mov ax,4c00h
int 21h
code ends
end start


代码对比


0B49:0000 B80020 MOV AX,2000
0B49:0003 8ED8 MOV DS,AX
0B49:0005 BB0010 MOV BX,1000
0B49:0008 BE0000 MOV SI,0000
0B49:000B 8B4002 MOV AX,
0B49:000E 46 INC SI
0B49:000F 8B4802 MOV CX,
0B49:0012 46 INC SI
0B49:0013 8BFE MOV DI,SI
0B49:0015 8B5902 MOV BX,
0B49:0018 B8004C MOV AX,4C00
0B49:001B CD21 INT 21



使用上面原理操作多维数组


将每个单词的第一个字母改为大写字母~:)


assume cs:code,ds:data
data segment
db '1. file '
db '2. edit '
db '3. search '
db '4. view '
db '5. options '
db '6. help '
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,3 ; 定位在第3列
mov bx,0 ; 定位在第n行
mov cx,6
s: mov al, ; 取数组 bx行.si列
and al,11011111b ; 第5位为0就是大写
mov ,al ; 送回去~:)
add bx,10h
loop s
mov ax,4c00h
int 21h
code ends
end start



Debug 验证结果


-d ds:0
0B49:0000 31 2E 20 46 69 6C 65 20-20 20 20 20 20 20 20 20 1. File
0B49:0010 32 2E 20 45 64 69 74 20-20 20 20 20 20 20 20 20 2. Edit
0B49:0020 33 2E 20 53 65 61 72 63-68 20 20 20 20 20 20 20 3. Search
0B49:0030 34 2E 20 56 69 65 77 20-20 20 20 20 20 20 20 20 4. View
0B49:0040 35 2E 20 4F 70 74 69 6F-6E 73 20 20 20 20 20 20 5. Options
0B49:0050 36 2E 20 48 65 6C 70 20-20 20 20 20 20 20 20 20 6. Help



多重循环转换数组中所有字母为大写


assume cs:code,ds:data
data segment
db 'dos '
db 'del '
db 'set '
db 'for '
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov cx,4
s0: mov di,0 ; 数组列指针
mov dx,cx ; 保存外层循环cx计数器的值
mov cx,3 ; 转换列计数(共3列)
s1: mov al, ; 取数组第0列
and al,11011111b
mov ,al ; 转完大写送回去
inc di ; 数组列指针右移一列
loop s1
mov cx,dx ; 恢复外层循环cx计数器的值
add bx,10h ; 将数组指针下移一行
loop s0 ; 返回外层循环
mov ax,4c00h
int 21h
code ends
end start



Debug 调试结果~:)))


-d ds:0
0B49:0000 44 4F 53 20 20 20 20 20-20 20 20 20 20 20 20 20 DOS
0B49:0010 44 45 4C 20 20 20 20 20-20 20 20 20 20 20 20 20 DEL
0B49:0020 53 45 54 20 20 20 20 20-20 20 20 20 20 20 20 20 SET
0B49:0030 46 4F 52 20 20 20 20 20-20 20 20 20 20 20 20 20 FOR


不管有多少个内、外循环,都只有一个cx计数器。
上面代码是用寄存器暂存数据。

用内存暂存数据


assume cs:code,ds:data
data segment
db 'dos '
db 'del '
db 'set '
db 'for '
data ends

code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov cx,4 ; 外循环计数器
s0: mov ds:,cx
mov si,0
mov cx,3 ; 内循环计数器
s: mov al, ; 内循环
and al,11011111b
mov ,al ; 转完大写再送回去
inc si
loop s
add bx,10h ; 外循环数组指针下移一行
mov cx,ds: ; 从内存单元中取出数据恢复cx计数器
loop s0
mov ax,4c00h
int 21h
code ends
end start




-d ds:0
0B49:0000 44 4F 53 20 20 20 20 20-20 20 20 20 20 20 20 20 DOS
0B49:0010 44 45 4C 20 20 20 20 20-20 20 20 20 20 20 20 20 DEL
0B49:0020 53 45 54 20 20 20 20 20-20 20 20 20 20 20 20 20 SET
0B49:0030 46 4F 52 20 20 20 20 20-20 20 20 20 20 20 20 20 FOR



将菜单中前4个字母大写,使用栈来存储数据


assume cs:code,ds:data,ss:stack

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

data segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
data ends

code segment
start: mov ax,data
mov ds,ax
mov ax,ss
mov ss,ax
mov sp,0fh
mov bx,0
mov cx,4
s0: push cx
mov si,0
mov cx,4
s1: mov al,
and al,11011111b
mov ,al
inc si
loop s1
add bx,10h
pop cx
loop s0
mov ax,4c00h
int 21h
code ends
end start



Debug 分析结果


-d ss:0
0B49:0000 00 00 00 00 00 00 00 00-00 2A 00 4E 0B 59 05 00 .........*.N.Y..
0B49:0010 31 2E 20 44 49 53 50 6C-61 79 20 20 20 20 20 20 1. DISPlay
0B49:0020 32 2E 20 42 52 4F 57 73-20 20 20 20 20 20 20 20 2. BROWs
0B49:0030 33 2E 20 52 45 50 4C 61-63 65 20 20 20 20 20 20 3. REPLace
0B49:0040 34 2E 20 4D 4F 44 49 66-79 20 20 20 20 20 20 20 4. MODIfy


Last edited by redtek on 2006-12-27 at 10:44 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-27 22:48
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 75 楼』:  【80x86汇编语言学习笔记】 使用 LLM 解释/回答一下

数据处理

寄存器(reg)集合包括:  ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di;

段寄存器(sreg)集合包括:ds,ss,cs,es;


要处理的数据有多长?

1) 通过寄存器名指明要处理的数据尺寸。

2) 在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度。
   X 在汇编指令中可以为 word 或 bye。

   mov word ptr ds:,1
   inc word ptr


在没有寄存器参与的内存单元访问指令中,用 word ptr 或 byte ptr 显性地指明所要访问的内存单地长度是必要的。
否则CPU无法得知所要访问的单元是字单元还是字节单元。


-a
0AF5:0100 mov ax,2000
0AF5:0103 mov ds,ax
0AF5:0105 mov byte ptr ,1
0AF5:010A
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0100 NV UP EI PL NZ NA PO NC
0AF5:0100 B80020 MOV AX,2000
-t

AX=2000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0103 NV UP EI PL NZ NA PO NC
0AF5:0103 8ED8 MOV DS,AX
-t

AX=2000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2000 ES=0AF5 SS=0AF5 CS=0AF5 IP=0105 NV UP EI PL NZ NA PO NC
0AF5:0105 C606001001 MOV BYTE PTR ,01 DS:1000=00
-t

AX=2000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2000 ES=0AF5 SS=0AF5 CS=0AF5 IP=010A NV UP EI PL NZ NA PO NC
0AF5:010A CD21 INT 21
-d ds:1000
2000:1000 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2000:1070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................




寻址方式的缩合应用

更改内存中的数据


公司名称: DEC
总载姓名: Ken Olsen
排  名: 137
收  入: 40(40亿美元)
著名产品: PDP(小型机)




db 'DEC' ; 公司名称
db 'Ken Oslen' ; 总载姓名
dw 137 ; 排  名
dw 40 ; 收  入
db 'PDP' ; 著名产品



数据在内存中存放形式


0B49:0000 44 45 43 4B 65 6E 20 4F-73 6C 65 6E 89 00 28 00 DECKen Oslen..(.
0B49:0010 50 44 50 00 00 00 00 00-00 00 00 00 00 00 00 00 PDP.............



代码如下



assume cs:code,ds:data
data segment
db 'DEC' ; 公司名称
db 'Ken Oslen' ; 总载姓名
dw 137 ; 排  名
dw 40 ; 收  入
db 'PDP' ; 著名产品
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0 ; 没用,就是表示寻址原理,超始位置
mov word ptr ,38 ; 修改排名为38
add word ptr ,70 ; 收入字段增加70
mov si,0 ; 用si定位产品字符串中的字符
mov byte ptr ,'V'
inc si ; 下移一个
mov byte ptr ,'A'
inc si
mov byte ptr ,'X'
mov ax,4c00h
int 21h
code ends
end start



修改完成


0B49:0000 44 45 43 4B 65 6E 20 4F-73 6C 65 6E 26 00 6E 00 DECKen Oslen&.n.
0B49:0010 56 41 58 00 00 00 00 00-00 00 00 00 00 00 00 00 VAX.............


很象结构体

按C风格描述


/* 定义一个公司记录的结构体 */

struct company {
char cn ; /* 公司名称 */
char hn ; /* 总载姓名 */
int pm ; /* 排 名 */
int sr ; /* 收 入 */
char cp ; /* 著名产品 */
}


按C风格,用汇编语言重写上面操作数据的代码


assume cs:code,ds:data
data segment
db 'DEC' ; 公司名称
db 'Ken Oslen' ; 总载姓名
dw 137 ; 排  名
dw 40 ; 收  入
db 'PDP' ; 著名产品
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov word ptr .0ch,38 ; 排名 - C: dec.pm=38
add word ptr .0eh,70 ; 收入 - C: dec.sr=dec.sr+70
mov si,0
mov byte ptr .10h,'V' ; C: dec.cp='V'
inc si ; C: i++
mov byte ptr .10h,'A' ; C: dec.cp='A'
inc si ; C: i++
mov byte ptr .10h,'X' ; C: dec.cp='X'
mov ax,4c00h
int 21h
code ends
end start


在机器码中,上面不同书写的代码在机器码中只有一种表示


0B4B:0000 B8490B MOV AX,0B49
0B4B:0003 8ED8 MOV DS,AX
0B4B:0005 BB0000 MOV BX,0000
0B4B:0008 C7470C2600 MOV WORD PTR ,0026
0B4B:000D 83470E46 ADD WORD PTR ,+46
0B4B:0011 BE0000 MOV SI,0000
0B4B:0014 C6401056 MOV BYTE PTR ,56
0B4B:0018 46 INC SI
0B4B:0019 C6401041 MOV BYTE PTR ,41
0B4B:001D 46 INC SI
0B4B:001E C6401058 MOV BYTE PTR ,58



DIV 除法操作

1) 除数:有8位和16位两种
2) 被除数:默认放在AX或DX和AX中。
   如果除数为8位,被除数则为16位。默认在AX中存放。
   如果除数为16位,被除数则为32位,在DX和AX中存放。DX存高16位,AX存低16位。
3) 结果
   如果除数为8位,则AL存放商,AH存放余数。
   如果除数为16位数,则AX存放商,DX存放余数

格式:

   div reg
   div 内存单元

   例: div byte ptr ds:
  含义: (al)=(ax)/((ds)*16+0))商
      (ah)=(ax)/(ds)*16+0))余数

   div word ptr es:
   (ax)=/((es)*16+0) 商
   (dx)=/((es)*16+0) 余数

   div byte ptr
   (al)=(ax)/((ds)*16+(bx)+(si)+8) 商
   (ah)=(ax)/(ds)*16+(bx)+(si)+8) 余数

   div word ptr
   (ax)=/((ds)*16+(bx)+(si)+8) 商
   (dx)=/((ds)*16+(bx)+(si)+8) 余数


计算 100001 / 100

100001(16)=186A1H
100(16)=64H

如果用 Debug 直接写汇编代码,一切都是16进制。
如果用 Masm 汇编代码写再编译,随便。

被除数是32位,那么计算除得的商与余数就必须(商16位、余数占16位),除数也占16位。

186A1H(被除数)的位低是:86A1H 、高位是:0001H


Debug 直接汇编代码如下:

C:\Masm50>debug
-A
0AF5:0100 mov dx,1
0AF5:0103 mov ax,86a1
0AF5:0106 mov bx,64
0AF5:0109 div bx
0AF5:010B
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0100 NV UP EI PL NZ NA PO NC
0AF5:0100 BA0100 MOV DX,0001
-t

AX=0000 BX=0000 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0103 NV UP EI PL NZ NA PO NC
0AF5:0103 B8A186 MOV AX,86A1
-t

AX=86A1 BX=0000 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0106 NV UP EI PL NZ NA PO NC
0AF5:0106 BB6400 MOV BX,0064
-t

AX=86A1 BX=0064 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0109 NV UP EI PL NZ NA PO NC
0AF5:0109 F7F3 DIV BX
-t

AX=03E8 BX=0064 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=010B NV UP EI PL NZ NA PO NC


用 windows 计算器算 100001 / 100 = 1000.01 (十进制)
上面值做为验证之用~:)

商:1000
余数:01

它们的16进制表示: 商:03E8H  余数:0001H
商与余数各占16位,商在低位表示的寄存器中,余数在高位表示的寄存器中。

再看 Debug 结果数据:


AX=03E8 BX=0064 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=010B NV UP EI PL NZ NA PO NC


红色标注表示:商
绿色标注表示:余数 ~:)



Masm 汇编代码,求 1001 / 100


assume cs:code
code segment
start: mov ax,1001
mov bl,100
div bl
code ends
end start



验证计算结果


AX=010A BX=0064 CX=0007 DX=0000 SP=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0007


AX=010A,结果正确~:)
商:0AH , 余数: 01H



伪指令 dd


定义dword(double word)-双字型数据。
双字型数据占 32 位。

如果汇编代码: dd 1
则16进制表示其所占用的空间: 00000001H


用 div 计算 data 段中第一个数据除以第二个数据后的结果,商存放在第3个数据的存储单元中。


assume cs:code,ds:data
data segment
dd 100001 ; 32位被除数
dw 100 ; 16位除数
dw 0
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,ds: ; 将被除数低位送入低位被除数应该在的寄存器
mov dx,ds: ; 将被除数的高位送dx寄存器
div word ptr ds: ; 用dx:ax 中的32位数据除以 ds:4 字单元中的数据
mov ds:,ax ; 将商存储在 ds:6 字单元中
mov ax,4c00h
int 21h
code ends
end start





-d ds:0006
0B49:0000 E8 03-00 00 00 00 00 00 00 00



DUP 操作符

它与 db,dw,dd等数据定义伪指令配合使用,用来进行数据的重复。

db  重重的次数 dup (重复的字节型数据)
dw  重重的次数 dup (重复的字型数据)
dd  重重的次数 dup (重复的双字型数据)



assume cs:code,ss:stack

stack segment
db 200 dup(0) ; 定义容量为200字节
stack ends

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



数据分布


-d ss:0
0B49:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
-d
0B49:0080 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:0090 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:00A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:00B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0B49:00C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00




寻址方式在结构化数据访问中的应用

Last edited by redtek on 2006-12-28 at 06:19 PM
]




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-28 12:12
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: