20CN安全小组 汇编教程(80386)

前言 在学习 32位汇编之前 推荐 看看 可以起到一个承上启下的 作用


-?
assemble     A [address]
compare      C range address
dump         D [range]
enter        E address [list]
fill         F range list
go           G [=address] [addresses]
hex          H value1 value2
input        I port
load         L [address] [drive] [firstsector] [number]
move         M range address
name         N [pathname] [arglist]
output       O port byte
proceed      P [=address] [number]
quit         Q
register     R [register]
search       S range list
trace        T [=address] [value]
unassemble   U [range]
write        W [address] [drive] [firstsector] [number]
allocate expanded memory        XA [#pages]
deallocate expanded memory      XD [handle]
map expanded memory pages       XM [Lpage] [Ppage] [handle]
display expanded memory status  XS



DEBUG命令详解

 

Debug:A(汇编)

直接将 8086/8087/8088 记忆码合并到内存。

该命令从汇编语言语句创建可执行的机器码。所有数值都是十六进制格式,必须按一到四个字符输入这些数值。在引用的操作代码(操作码)前指定前缀记忆码。

a [address]

参数

address

指定键入汇编语言指令的位置。对 address 使用十六进制值,并键入不以“h”字符结尾的每个值。如果不指定地址,a 将在它上次停止处开始汇编。

有关将数据输入到指定字节中的信息,请参看Debug E(键入)。

有关反汇编字节的信息,请参看Debug U(反汇编)


说明

使用记忆码

段的替代记忆码为 cs:、ds:、es: 和 ss:。远程返回的记忆码是 retf。字符串处理的记忆码必须明确声明字符串大小。例如,使用 movsw 可以移动 16 位的字串,使用 movsb 可以移动 8 位字节串。


汇编跳转和调用

汇编程序根据字节替换自动将短、近和远的跳转及调用汇编到目标地址。通过使用 near 或 far 前缀可以替代这样的跳转或调用,如下例所示:

-a0100:0500
0100:0500 jmp 502 ; a 2-byte short jump
0100:0502 jmp near 505 ; a 3-byte near jump
0100:0505 jmp far 50a ; a 5-byte far jump

可以将 near 前缀缩写为 ne。


区分字和字节内存位置

当某个操作数可以引用某个字内存位置或者字节内存位置时,必须用前缀 word ptr 或者前缀 byte ptr 指定数据类型。可接受的缩写分别是 wo 和 by。以下范例显示两种格式:

dec wo [si]
neg byte ptr [128]


指定操作数

Debug 使用包括在中括号 ([ ]) 的操作数引用内存地址的习惯用法。这是因为另一方面 Debug 不能区分立即操作数和内存地址的操作数。以下范例显示两种格式:

mov ax,21 ; load AX with 21h
mov ax,[21] ; load AX with the
; contents of
; memory location 21h


使用伪指令

使用 a 命令提供两个常用的伪指令:db 操作码,将字节值直接汇编到内存,dw 操作码,将字值直接汇编到内存。以下是两个伪指令的范例:

db 1,2,3,4,"THIS IS AN EXAMPLE"
db 'THIS IS A QUOTATION MARK:"'
db "THIS IS A QUOTATION MARK:'"
dw 1000,2000,3000,"BACH"


范例

a 命令支持所有形式的间接注册命令,如下例所示:

add bx,34[bp+2].[si-1]
pop [bp+di]
push [si] )

还支持所有操作码同义词,如下例所示:

loopz 100
loope 100
ja 200
jnbe 200

对于 8087 操作码,必须指定 wait 或 fwait 前缀,如下例所示:

fwait fadd st,st(3) ; this line assembles
; an fwait prefix


Debug:C(比较)


比较内存的两个部分。


c range address


参数

range

指定要比较的内存第一个区域的起始和结束地址,或起始地址和长度。

address

指定要比较的第二个内存区域的起始地址。有关有效 address 值的信息,请参看“Debug 说明”。


说明

如果 range 和 address 内存区域相同,Debug 将不显示任何内容而直接返回到 Debug 提示符。如果有差异,Debug 将按如下格式显示:
address1 byte1 byte2 addess2

范例

以下命令具有相同效果:

c100,10f 300
c100l10 300

每个命令都对 100h 到 10Fh 的内存数据块与 300h 到 30Fh 的内存数据块进行比较。

Debug 响应前面的命令并显示如下信息(假定 DS = 197F):

197F:0100 4D E4 197F:0300
197F:0101 67 99 197F:0301
197F:0102 A3 27 197F:0302
197F:0103 35 F3 197F:0303
197F:0104 97 BD 197F:0304
197F:0105 04 35 197F:0305
197F:0107 76 71 197F:0307
197F:0108 E6 11 197F:0308
197F:0109 19 2C 197F:0309
197F:010A 80 0A 197F:030A
197F:010B 36 7F 197F:030B
197F:010C BE 22 197F:030C
197F:010D 83 93 197F:030D
197F:010E 49 77 197F:030E
197F:010F 4F 8A 197F:030F

注意列表中缺少地址 197F:0106 和 197F:0306。这表明那些地址中的值是相同的。


Debug:D(转储)


显示一定范围内存地址的内容。


d [range]


参数

range

指定要显示其内容的内存区域的起始和结束地址,或起始地址和长度。如果不指定 range,Debug 程序将从以前 d 命令中所指定的地址范围的末尾开始显示 128 个字节的内容。

有关显示寄存器内容的信息,请参看Debug R(寄存器)。


说明
当使用 d 命令时,Debug 以两个部分显示内存内容:十六进制部分(每个字节的值都用十六进制格式表示)和 ASCII 码部分(每个字节的值都用 ASCII 码字符表示)。每个非打印字符在显示的 ASCII 部分由句号 (.) 表示。每个显示行显示 16 字节的内容,第 8 字节和第 9 字节之间有一个连字符。每个显示行从 16 字节的边界上开始。

范例
假定键入以下命令:
dcs:100 10f
Debug 按以下格式显示范围中的内容:
04BA:0100 54 4F 4D 00 53 41 57 59-45 52 00 00 00 00 00 00 TOM.SAWYER......
如果在没有参数的情况下键入 d 命令,Debug 按以前范例中所描述的内容来编排显示格式。显示的每行以比前一行的地址大 16 个字节(如果是显示 40 列的屏幕,则为 8 个字节)的地址开头。
对于后面键入的每个不带参数的 d 命令,Debug 将紧接在最后显示的命令后立即显示字节内容。
如果键入以下命令,Debug 将从 CS:100 开始显示 20h 个字节的内容:
dcs:100 l 20
如果键入以下命令,Debug 将显示范围从 CS 段的 100h 到 115h 中所有字节的内容:
dcs:100 115

Debug:E(键入)

将数据输入到内存中指定的地址。
可以按十六进制或 ASCII 格式键入数据。以前存储在指定位置的任何数据全部丢失。

e address [list]

参数
address
指定输入数据的第一个内存位置。
list
指定要输入到内存的连续字节中的数据。
有关集成记忆码的信息,请参看Debug A(汇编)。
有关显示内存部分内容的信息,请参看Debug D (转储)。

说明

使用 address 参数

如果在没有指定可选的 list 参数的值情况下指定 address 的值,Debug 将显示地址和内容,在下一行重复地址,并等待您的输入。此时,您可以执行下列操作之一:

替换字节值。为此,请在当前值后键入新值。如果您键入的值不是有效的十六进制值,或该值包含两个以上的数字,则 Debug 不会回显无效或额外的字符。
进入下一个字节。为此,请按 SPACEBAR(空格键)。要更改该字节中的值,请在当前值后键入新值。如果按 SPACEBAR(空格键)时,移动超过了 8 位界限,Debug 程序将显示新的一行并在行首显示新地址。
返回到前一个字节。为此,请按 HYPHEN 键 (-)。可以反复按 HYPHEN 键 (-) 向后移动超过多个字节。在按 HYPHEN 时,Debug 开始新行并显示当前地址和字节值。
停止执行 e 命令。为此,请按 ENTER 键。在任何字节位置都可以按 ENTER。
使用 list 参数

如果指定 list 参数的值,随后的 e 命令将使用列表中的值替换现有的字节值。如果发生错误,将不更改任何字节值。

List 值可以是十六进制字节或字符串。使用空格、逗号或制表符来分隔值。必须将字符串包括在单或双引号中。

范例

假定键入以下命令:

ecs:100

Debug 按下面的格式显示第一个字节的内容:

04BA:0100 EB.

要将该值更改为 41,请在插入点键入 41,如下所示:

04BA:0100 EB.41_

可以用一个 e 命令键入连续的字节值。在键入新值后按 SPACEBAR(空格键),而不是按 ENTER 键。Debug 显示下一个值。在此范例中,如果按三次 SPACEBAR(空格键),Debug 将显示下面的值:

04BA:0100 EB.41 10. 00. BC._

要将十六进制值 BC 更改为 42,请在插入点键入 42,如下所示:

04BA:0100 EB.41 10. 00. BC.42_

假定决定值 10 应该是 6F。要纠正该值,请按 HYPHEN 键两次以返回到地址 0101(值 10)。Debug 显示以下内容:

04BA:0100 EB.41 10. 00. BC.42-
04BA:0102 00.-
04BA:0101 10._

在插入点键入 6f 更改值,如下所示:

04BA:0101 10.6f_

按 ENTER 停止 e 命令并返回到 Debug 提示符下。

以下是字符串项的范例:

eds:100 "This is the text example"

该字符串将从 DS:100 开始填充 24 个字节

Debug:F(填充)

使用指定的值填充指定内存区域中的地址。

可以指定十六进制或 ASCII 格式表示的数据。任何以前存储在指定位置的数据将会丢失。


f range list


参数

range

指定要填充内存区域的起始和结束地址,或起始地址和长度。关于有效的 range 值的信息,请参看“Debug 说明”。

list

指定要输入的数据。List 可以由十六进制数或引号包括起来的字符串组成。


说明

使用 range 参数

如果 range 包含的字节数比 list 中的数值大,Debug 将在 list 中反复指派值,直到 range 中的所有字节全部填充。

如果在 range 中的任何内存损坏或不存在,Debug 将显示错误消息并停止 f 命令。


使用 list 参数

如果 list 包含的数值多于 range 中的字节数,Debug 将忽略 list 中额外的值。


范例

假定键入以下命令:

f04ba:100l100 42 45 52 54 41

作为响应,Debug 使用指定的值填充从 04BA:100 到 04BA:1FF 的内存位置。Debug 重复这五个值直到 100h 个字节全部填满为止。


Debug:G(转向)


运行当前在内存中的程序。


g [=address] [breakpoints]


参数

=address

指定当前在内存中要开始执行的程序地址。如果不指定 address,Windows 2000 将从 CS:IP 寄存器中的当前地址开始执行程序。

breakpoints

指定可以设置为 g 命令的部分的 1 到 10 个临时断点。

有关执行循环、重复的字符串指令、软件中断或子程序的信息,请参看Debug P(执行)。

有关执行指令的信息,请参看Debug T(跟踪)

Debug:H(十六进制)

对指定的两个参数执行十六进制运算。


h value1 value2


参数

value1

代表从 0 到 FFFFh 范围内的任何十六进制数字。

value2

代表从 0 到 FFFFh 范围内第二个十六进制数字。


说明

Debug 首先将指定的两个参数相加,然后从第一个参数中减去第二个参数。这些计算的结果显示在一行中:先计算和,然后计算差。


范例

假定键入以下命令:

h19f 10a

Debug 执行运算并显示以下结果。
02A9 0095

Debug:I(输入)


从指定的端口读取并显示一个字节值。

i port

参数

port

按地址指定输入端口。地址可以是 16 位的值。

有关将字节值发送到输出端口的信息,请参看Debug O(输出)。


范例

假定键入以下命令:

i2f8

同时假定端口的字节值是 42h。Debug 读取该字节,并将其值显示如下:
42


Debug:L(加载)

将某个文件或特定磁盘扇区的内容加载到内存。

要从磁盘文件加载 BX:CX 寄存器中指定的字节数内容,请使用以下语法:

l [address]

要略过 Windows 2000 文件系统并直接加载特定的扇区,请使用以下语法:

l address drive start number


参数

address

指定要在其中加载文件或扇区内容的内存位置。如果不指定 address,Debug 将使用 CS 寄存器中的当前地址。

drive

指定包含读取指定扇区的磁盘的驱动器。该值是数值型:0 = A, 1 = B, 2 = C 等。

start

指定要加载其内容的第一个扇区的十六进制数。

number

指定要加载其内容的连续扇区的十六进制数。只有要加载特定扇区的内容而不是加载 debug 命令行或最近的 Debug n(名称)命令中指定的文件时,才能使用 drive、start 和 number 参数。

有关指定用于 l 命令的文件的信息,请参看Debug n(名称)。

有关写入调试到磁盘的文件的信息,请参看Debug w(写入)。


注意

使用不带参数的 l 命令

当使用不带参数的 l 命令时,在 debug 命令行上指定的文件将加载到内存中,从地址 CS:100 开始。Debug 同时将 BX 和 CX 寄存器设置为加载的字节数。如果不在 debug 命令行指定文件,所装入的文件将是最近使用 n 命令经常指定的文件。


使用具有 address 参数的 1 命令

如果使用带 address 参数的 l 命令,Debug 将从内存位置 address 开始加载文件或指定扇区的内容。


使用带全部参数的 l 命令

如果使用带所有参数的 l 命令,Debug 将加载指定磁盘扇区的内容而不是加载文件。


加载特定扇区的内容

指定范围内的每个扇区均从 drive 读取。Debug 从 start 开始加载,直到在 number 中指定的扇区数中的内容全部被加载。


加载 .exe 文件

Debug 忽略 .exe 文件的地址 address 参数。如果指定 .exe 文件,Debug 将文件重新定位到 .exe 文件的标题中指定的加载地址。在 .exe 文件被加载到内存前,标题自身从 .exe 文件脱离,因此磁盘上的 .exe 文件大小与内存中的不同。如果要检查整个 .exe 文件,请使用不同的扩展名重命名文件。


打开十六进制文件

Debug 将具有 .hex 扩展名的文件认为十六进制格式文件。键入不带参数的 l 命令,可以加载从十六进制文件中指定的地址处开始的十六进制文件。如果键入的 l 命令包含 address 参数,Debug 将把指定的地址加到在十六进制文件中找到的地址上,以确定起始地址。


范例

假定启动 Debug 并键入以下命令:

nfile.com

现在可以键入 l 命令以加载 File.com。Debug 将加载文件并显示 Debug 提示符。

假定需要从驱动器 C 将起始逻辑扇区为 15 (0Fh) 的 109 (6Dh) 个扇区的内容加载到起始地址为 04BA:0100 的内存中。为此,请键入以下命令:
l04ba:100 2 0f 6d


Debug:M(移动)



将一个内存块中的内容复制到另一个内存块中。

m range address


参数

range

指定要复制内容的内存区域的起始和结束地址,或起始地址和长度。

address

指定要将 range 内容复制到该位置的起始地址。

说明

复制操作对现有数据的影响

如果新数据没有写入正在被复制的数据块中的地址,则源数据将保持不变。但是,如果目标块已经包含数据(就象它在覆盖副本操作中一样),则将改写该数据。(覆盖复制操作是指那些目标数据块部分内容覆盖原数据块部分内容的操作。)


执行覆盖复制操作

m 命令执行目标地址的覆盖复制操作,而不丢失数据。将改写的地址内容首先复制。因此,如果将较高位地址的数据复制到较低位地址,则复制操作从原块的最低位地址开始并向最高位地址进行。反之,如果要将数据从低地址复制到高地址,复制操作从原块的最高地址开始,向最低地址进行。


范例

假定键入以下命令:

mcs:100 110 cs:500
Debug 首先将 CS:110 地址中的内容复制到地址 CS:510 中,然后将 CS:10F 地址中的内容复制到 CS:50F 中,如此操作直至将 CS:100 地址中的内容复制到地址 CS:500 中。要查看结果,请使用 Debug d(转储)命令,并使用 m 命令指定目标地址

Debug:N(名称)



指定 Debug l(加载)或 w(写入)命令的可执行文件的名称,或者指定正在调试的可执行文件的参数。


n [drive:][path] filename


要指定测试的可执行文件的参数,请使用以下语法:

n file-parameters


参数

如果在没有参数的情况下使用,则 n 命令清除当前规范。
[drive:][path] filename

指定要测试的可执行文件的位置和名称。

file-parameters

为正在测试的可执行文件指定参数和开关。

有关将文件或指定磁盘扇区的内容加载到内存中的信息,请参看Debug L(加载)。

有关写入调试到磁盘的文件的信息,请参看Debug W(写入)。


说明

n 命令的两个用途

可以按两种方式使用 n 命令。首先,您可以使用它以指定后面的 l(加载)或 w(写入)命令所使用的文件。如果在没有命名所调试文件的情况下启动 Debug,必须在使用 l 命令加载文件之前使用命令 nfilename。在 CS:5C 为文件控制块 (FCB) 正确编排文件名的格式。其次,可以使用 n 命令指定被调试文件的命令行参数和开关。


内存区域

以下四个内存区域都会受到 n 命令的影响:

内存位置
内容

CS:5C
文件 1 的文件控制数据块 (FCB)

CS:6C
文件 2 的文件控制数据块 (FCB)

CS:80
n 命令行的长度(以字符表示)

CS:81
n 命令行字符的开头


为 n 命令指定的第一个文件名被放在 CS:5C 的 FCB 中。如果指定第二个文件名,此名称将放置到 CS:6C 的 FCB 中。n 命令行上键入的字符数(除第一个字符之外,n)存储在位置 CS:80。n 命令行上的实际字符(再次,除了字母 n 之外)存储在以 CS:81 开头的位置。注意这些字符可以是在 Windows 2000 命令提示符下键入的命令中有效的任何开关和分隔符。


范例

假定已经启动 Debug,并加载了正在调试的程序 Prog.com。接着您决定为 Prog.com 指定两个参数并运行此程序。以下是此范例的命令序列:

debug prog.com
nparam1 param2
g

在这种情况下,Debug g(转向)命令会运行该程序,就好像您已在 Windows 2000 命令提示符后键入了如下命令:

prog param1 param2

所以,测试和调试反映 Prog.com 通常的运行时间环境。

在下面的命令序列中,第一个 n 命令将 File1.exe 指定为后接的 l(加载)命令的文件,该命令将 File1.exe 加载到内存。第二个 n 命令指定 File1.exe 将使用的参数。最后,g 命令将运行 File1.exe 文件,就好像您在 Windows 2000 命令行中键入了 File1 File2.dat File2.dat 一样。

nfile1.exe
l
nfile2.dat file3.dat
g

注意
不要在 n 命令的第二种形式后使用 l 命令。还要注意,如果现在使用 w(写入)命令,Windows 2000 将使用名称 File2.dat 保存正在调试的文件 File1.exe。为避免出现此结果,应该总是在 l 或 w 命令之前立即使用 n 命令的第一种形式。

Debug:O(输出)



将字节值发送到输出端口。


o port byte-value


参数

port

通过地址指定输出端口。端口地址可以是 16 位值。

byte-value

指定要指向 port 的字节值。

有关从输入端口读取字节值的信息,请参看Debug I(输入)。

范例

要将字节值 4Fh 发送到地址为 2F8h 的输出端口,请键入以下命令:
o2f8 4f

Debug:P(执行)



执行循环、重复的字符串指令、软件中断或子例程;或通过任何其他指令跟踪。


p [= address] [number]


参数

=address

指定第一个要执行指令的位置。如果不指定地址,则默认地址是在 CS:IP 寄存器中指定的当前地址。

number

指定在将控制返回给 Debug 之前要执行的指令数。默认值为 1。

有关运行当前在内存中程序的信息,请参看Debug G(转向)。

有关执行指令的信息,请参看Debug T(跟踪)。


说明
控制传送到要测试的程序

当 p 命令将控制从 Debug 传送到要测试的程序时,该程序不间断运行,直到循环、重复字符串指令、软件中断或者完成了指定地址的子例程为止,或者直到执行了指定数量的机器指令为止。控制返回到 Debug。

地址参数的限制

如果 address 参数没有指定段,Debug 将使用被测试程序的 CS 寄存器。如果省略 address,程序将从 CS:IP 寄存器所指定的地址开始执行。必须在 address 参数之前使用等号 (=) 以便将它与 number 参数区分。如果在指定地址处的指令不是循环、重复的字符串指令、软件中断或子例程,则 p 命令与 Debug t(跟踪)命令的作用相同。

使用 p 命令显示的邮件

当 p 执行完一段说明后,Debug 显示出程序的寄存器内容、标志的状态以及下一段将要被执行的指令的解码形式。


警告

不能使用 p 命令跟踪只读内存 (ROM)。

范例

假定正在测试的程序在地址 CS:143F 处包含一个 call 指令。要运行 call 目标位置的子程序然后将控制返回到 Debug,请键入以下命令:

p=143f

Debug 按以下格式显示结果:
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2246 ES=2246 SS=2246 CS=2246 IP=1443 NV UP EI PL NZ AC PO NC
2246:1442 7505 JNZ 144A

Debug:Q(退出)



停止 Debug 会话,不保存当前测试的文件。

当您键入 q 以后,控制返回到 Windows 2000 的命令提示符。


q


参数

该命令不带参数。
有关保存文件的信息,请参看Debug W(写入)。

Debug:R(寄存器)


显示或改变一个或多个 CPU 寄存器的内容。


r [register-name]


参数



如果在没有参数的情况下使用,则 r 命令显示所有寄存器的内容以及寄存器存储区域中的标志。

register-name

指定要显示其内容的寄存器名。

有关显示内存部分内容的信息,请参看Debug D(转储)。

有关反汇编字节的信息,请参看Debug U(反汇编)。


说明

使用 r 命令

如果指定了寄存器名称,Windows 2000 将显示以十六进制标记表示的寄存器的 16 位值,并将冒号显示为提示符。如果要更改包含在寄存器中的值,除非键入新值并按 ENTER 键;否则,请按 ENTER 键返回 Debug 提示符。

有效寄存器名

以下是 register-name 的有效值:ax、bx、cx、dx、sp、bp、si、di、ds、es、ss、cs、ip、pc 及 f。ip 和 pc 都引用指令指针。

如果指定寄存器名称,而不是从前面的列表中指定,Windows 2000 将显示以下消息:

br error

使用 f 字符而不是寄存器名

如果键入 f 字符代替寄存器名,Debug 将每个标记的当前设置显示为两字母代码,然后显示 Debug 提示符。要更改标志的设置,请从下表中键入适当的两字母代码:

标志名
设置
清除

溢出
ov
nv

方向
dn(减)
up(增)

中断
ei(启用)
di(禁用)

正负
ng(负)
pl(正)


zr
nz

辅助进位
ac
na

奇偶校验
pe(偶校验)
po(奇校验)

进位
cy
nc


可以按任何顺序键入新的标志值。不需要在这些值之间留出空格。要停止 r 命令,请按 ENTER 键。任何没有指定新值的标志保持不变。

用 r 命令显示的邮件

如果为标记指定了多个值,Debug 将显示以下消息:

df error

如果指定没有在前面的表中列出的标志代码,Debug 将显示以下消息:

bf error

在这两种情况下,Debug 将忽略所有在无效项目之后指定的设置。

Debug 的默认设置

在启动 Debug 时,会将段寄存器设置到空闲内存的低端,指令指针设置为 0100h,清除所有标志,并且将其余寄存器设置为零,除了被设置为 FFEEh 的 sp 之外。

Debug:R


范例

要查看所有寄存器的内容、所有标记的状态和当前位置的指令解码表,请键入以下命令:

r

如果当前位置是 CS:11A,显示外观将类似于以下内容:

AX=0E00 BX=00FF CX=0007 DX=01FF SP=039D BP=0000 SI=005C DI=0000
DS=04BA ES=04BA SS=04BA CS=O4BA IP=011A NV UP DI NG NZ AC PE NC
04BA:011A CD21 INT 21

要只查看标志的状态,请键入以下命令:

rf

Debug 按以下格式显示信息:

NV UP DI NG NZ AC PE NC - _

现在,您可以按任意顺序键入一个或多个有效的标志值,其中可以有或没有空格,如下所示:

nv up di ng nz ac pe nc - pleicy

Debug 结束 r 命令并显示 Debug 提示符。要查看更改,请键入 r 或 rf 命令。Debug 将显示以下内容:

NV UP EI PL NZ AC PE CY - _
按 ENTER 返回到 Debug 提示符。

Debug:S(搜索)



在某个地址范围搜索一个或多个字节值的模式。


s range list


参数

range

指定要搜索范围的开始和结束地址。

list

指定一个或多个字节值的模式,或要搜索的字符串。用空格或逗号分隔每个字节值和下一个字节值。将字符串值包括在引号中。


说明

如果 list 参数包含多个字节值,Debug 将只显示出现字节值的第一个地址。如果 list 只包含一个字节值,Debug 将显示指定范围内出现该值的所有地址。


范例

假定需要查找包含值 41 并且范围从 CS:100 到 CS:110 的所有地址。为此,请键入以下命令:

scs:100 110 41

Debug 按以下格式显示结果:

04BA:0104
04BA:010D
-

以下命令在 CS:100 到 CS:1A0 的范围内搜索字符串“Ph”。
scs:100 1a0 "Ph"


Debug:T(跟踪)
(SORRY,Debug:T部分暂缺,如果哪位网友有此部分,请通知我)


Debug:U(反汇编)


反汇编字节并显示相应的原语句,其中包括地址和字节值。反汇编代码看起来象已汇编文件的列表。


u [range]


参数



如果在没有参数的情况下使用,则 u 命令分解 20h 字节(默认值),从前面 u 命令所显示地址后的第一个地址开始。

range

指定要反汇编代码的起始地址和结束地址,或起始地址和长度。

有关集成记忆码的信息,请参看Debug A(汇编)。

有关显示内存部分内容的信息,请参看Debug D(转储)。

范例



要反汇编 16 (10h) 字节,从地址 04BA:0100 开始,请键入以下命令:

u04ba:100l10

Debug 按以下格式显示结果:

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH
04BA:0109 65 DB 65
04BA:010A 63 DB 63
04BA:010B 69 DB 69
04BA:010C 66 DB 66
04BA:010D 69 DB 69
04BA:010E 63 DB 63
04BA:010F 61 DB 61

如果只显示从 04BA:0100 到 04BA:0108 特定地址的信息,请键入以下命令:

u04ba:0100 0108

Debug 显示以下内容:

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH

Debug:W(写入)



将文件或特定分区写入磁盘。

要将在 BX:CX 寄存器中指定字节数的内容写入磁盘文件,请使用以下语法:


w [address]


要略过 Windows 2000 文件系统并直接写入特定的扇区,请使用以下语法:

w address drive start number


参数

address

指定要写到磁盘文件的文件或部分文件的起始内存地址。如果不指定 address,Debug 程序将从 CS:100 开始。

drive

指定包含目标盘的驱动器。该值是数值型:0 = A, 1 = B, 2 = C,等等。

start

指定要写入第一个扇区的十六进制数。

number

指定要写入的扇区数。

有关指定用于 w 命令的文件的信息,请参看Debug N(名称)。

有关将文件或文件扇区内容加载到内存中的信息,请参看Debug L(加载)。

说明

必须在启动 Debug 时或者在最近的 Debug n(名称)命令中指定磁盘文件的名字。这两种方法都可以将地址 CS:5C 处文件控制块的文件名正确地编排格式。


在使用不带参数的 w 命令之前重新设置 BX:CX

如果使用了 Debug g(转向)、t(跟踪)、p(执行)或 r(寄存器)命令,必须在使用无参数的 w 命令之前,将 BX:CX 寄存器复位。

将修改后的文件写入磁盘

如果修改文件但不更改文件名、长度或起始地址,Debug 仍然可以正确地将文件写入源磁盘位置。

w 命令的限制

不能用该命令写入 .exe 或 .hex 文件。

警告

因为略过 Windows 2000 文件句柄,所以写入特定的分区非常危险。如果键入错误的值,则磁盘文件结构很容易被损坏。

范例

假定要将起始地址为 CS:100 的内存内容写入到驱动器 B 的磁盘中。需要将数据从磁盘的逻辑扇区号 37h 开始并持续 2Bh 个扇区。为此,键入以下命令:

wcs:100 1 37 2b

当写操作完成时,Debug 再次显示 Debug 提示符。

Debug:XA(分配扩展内存)

分配扩展内存的指定页面数。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xa [count]


参数

count

指定要分配的扩展内存的 16KB 页数。

有关使用扩展内存的其他 Debug 命令的信息,请参看Debug XD(释放扩展内存)、Debug XM(映射扩展内存页)或 Debug XS(显示扩展内存状态)。

说明

如果指定的页面数可用,则 Debug 将显示消息,此消息表明所创建的句柄的十六进制数;否则,Debug 将显示错误消息。



Debug:XA

范例

要分配扩展内存的 8 个页面,请键入以下命令:

xa8

如果命令成功,Debug 将显示类似的以下消息:
Handle created=0003

Debug:XD(释放扩展内存)


释放指向扩展内存的句柄。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xd [handle]


参数

handle

指定要释放的句柄。

有关使用扩展内存的其他 Debug 命令的信息,请参看Debug XA(分配扩展内存)、Debug XM(映射扩展内存页) 或 Debug XS(显示扩展内存状态)。

范例

要释放句柄 0003,请键入以下命令:

xd 0003

如果命令成功,Debug 将显示下列消息:
Hdle 0003 deallocated

Debug:XM(映射扩展内存页)


将属于指定句柄的扩展内存逻辑页映射到扩展内存的物理页。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xm [lpage] [ppage] [handle]


参数

lpage

指定要映射到物理页 ppage 的扩展内存的逻辑页面号。

ppage

指定将 lpage 映射到的物理页面号。

handle

指定句柄。

有关使用扩展内存的其他 Debug 命令的信息,请参看Debug XA(分配扩展内存)、Debug XD(释放扩展内存)或 Debug XS(显示扩展内存)。


范例

要将句柄 0003 的逻辑页 5 映射到物理页 2,请键入以下命令:

xm 5 2 0003

如果命令成功,Debug 将显示下列消息:

Logical page 05 mapped to physical page 02

Debug:XS(显示扩展内存状态)


显示有关扩展内存状态的信息。

要使用扩展内存,必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xs


参数

该命令不带参数。

有关使用扩展内存的其他 Debug 命令的信息,请参看Debug XA(分配扩展内存)、Debug XD(释放扩展内存)或Debug XM(映射扩展内存页)。


说明

Debug 显示的信息有如下格式:

Handle xx has xx pages allocated
Physical page xx = Frame segment xx
xx of a total xx EMS pages have been allocated
xx of a total xx EMS handles have been allocated


范例

要显示扩展内存信息,请键入以下命令:

xs

Debug 显示与以下类似的信息:

Handle 0000 has 0000 pages allocated
Handle 0001 has 0002 pages allocated
Physical page 00 = Frame segment C000
Physical page 01 = Frame segment C400
Physical page 02 = Frame segment C800
Physical page 03 = Frame segment CC00
2 of a total 80 EMS pages have been allocated
2 of a total FF EMS handles have been allocated
(全文完)


<script src="http://www.yueya.com/counter/mystat.asp?siteid=2"></script> <script language=javascript src="http://www.yueya.com/counter/stat.asp?style=&siteid=2&tzone=8&tcolor=16&sSize=1024,768&referrer=http%3A//www.baidu.com/baidu%3Fwd%3Ddebug%26cl%3D3"></script>








 标题: [20cn讲座]跟我学汇编
作者: 霜泉 [ljsh012]    论坛用户  登录
作者: 286 [unique]  版主 回复  收藏 
1 本讲座以汇编初学者或对汇编一点也不了解的读者为对象,汇编高手不属于该范围,但强烈建议高手指导并增补、修改本文。
2 任何读者可以跟此贴,提出疑问,或解答其中的问题,但对于所有跟贴,水贴、内容有错、毫不相干贴将直接删除,有意义的贴可能会合并到下一讲的内容中,合并后也将删除,请跟贴者谅解。同时按学习进步,请提问者逐步提,不要我没开口,你就问怎么编个病毒的问题。
3 借以抛砖引玉,但不希望大家只朝我扔砖头,希望大家踊跃思考,使之完善。



--------------------------------------------------------------------------------
纵行下天,286足矣。

地主 发表时间: 04-11-15 10:09

--------------------------------------------------------------------------------
回复: 286 [unique]  版主 回复  收藏 
第负一讲 学习汇编前你应该知道的知识

大家坐好了,。不要,不要,不要,男女同学不要相互,女同学不要对我....
 
1 汇编需要什么工具和程序,到哪里下载?
目前阶段,汇编程序仅需要两个程序就够了。 masm.exe,link.exe。二者可由http://www.20cn.org/~unique/Download/Tool/masm.rar下载,前者是编译程序,后者是链接程序。
另外,为了验证和调试程序,还需要一个程序debug.exe,该程序由windows本身就提供,所以就不提供下载地址了。
将二者下载后,放到某一个目录中(任意目录都可以),考虑到很多命令需要通过键盘敲入,所以建议你不要把文件放入到长文件名目录、中文目录或很深的目录中。比如你可以建一个“D:/Masm”目录,并建议此后的程序都放这个目录,此后称这个目录为汇编目录。


2 学习汇编需要有哪些编程方面的知识。
没有任何编程方面的知识,学习此语言等于缘木求鱼,所以请放弃学习的想法。一般来说至少要知道如下几点:
*)程序的运行逻辑结构有顺序(按语句依次执行)、分支结构(IF...THEN...ELSE...),循环结构(FOR...NEXT)三种结构。
*)知道什么是子程序,什么是调用。
*)汇编程序员的视角。不同编程视角编程要求是不一样的。比如删除文件,
  >>用户的视角是找到“删除”按钮或菜单,然后单击一下即可。
  >>高级程序员的视角是知道删除的文件,并发出删除命令。这些通过API实现。
  >>汇编程员的视角是得到要删除的文件名,找到该文件所在位置,通过调用删除“中断命令”进行删除。
  >>操作系统开发人员的视角则是接到删除命令后,先找到系统根目录区,由根目录区的链接依次找到子目录区,直到找到要删除的文件,然后按照操作系统删除文件的规则对该文件名进行修改。比如DOS,只把第一个字符改成"?"。

按程序语句等价的角度看,一行VB的打印语句,用汇编实现大约需要一百二十多行。知道汇编语言的视角后就要知道,前面的道路是坎坷的,没有耐心是不行的。想通过几分钟几行程序就完成很复杂的操作不是件容易的事。

3 学汇编有什么用?
汇编产生于DOS时代或更早,而现在是Windows时代,所以可能遗憾地说:尽管还有批牛人在用汇编开发核心级程序,但我们几乎没什么用,除了必要时间能拿来分析一两个程序的部分代码之外,别的也就没干什么用了。并且并不是所有的汇编命令都能在windows下使用。而泛泛地追求“时髦”而学本语言,最后的结果是损了夫人又折兵。所以学之前你要考虑好。我劝那些为了当“黑客”而学汇编的人就此止步。


--------------------------------------------------------------------------------
纵行下天,286足矣。

B1层 发表时间: 04-11-15 14:40

--------------------------------------------------------------------------------
回复: 286 [unique]  版主 回复  收藏 
第零讲 预备知识

1 一个汇编程序的编译过程是怎么样的。
1)首先你需要找一个编辑器,编辑器用任何“纯文本”编辑器都可以。比如记事本。编好以后保存到汇编目录中。扩展名为asm,比如myfirst.asm。但这里建议你找一个能显示出当前行的编译器。这样出错后排错很容易。
2)然后在DOS下进入D:/Masm目录中,输入“masm myfirst.asm",如果有错系统会提示出错的行位置和出错原因。
3)然后再输入“link myfirst.obj”,即可看到当前目录下有一个myfirst.exe程序。

2 宏汇编和汇编有什么区别吗?
二者的区别在于前者提供宏,后者不提供。后者已找不到了,所以你可以认为二者没有区别。

3 机器语言、汇编语言、高级语言的关系
最早的计算机采用机器语言,这种语言直接用二进制数表示,通过直接输入二进制数,插拔电路板等实现,这种“编程”很容易出错,每个命令都是通过查命令表实现,既然是通过“查表”实现的,那当然也可以让计算机来代替人查表实现了。于是就产生了汇编语言,所以不管别人怎么定义机、汇语言,我就认为,二者是等价。后来人们发现,用汇编语言编某一功能的时候,连续一段代码都是相同或相似,于是就考虑用一句语言来代替这一段汇编语言,于是就产生了高级语言。因此,所有高级语言都能转化成汇编语言,而所以汇编语言又可转化成机器语言。反之,所有机器语言可以转成汇编语言(因为二者等价)。但并不是所以汇编语言都能转成高级语言。

4 计算机的组成
通常都把计算机定义成五部分:运算器、控制器、存储器、输入系统、输出系统。
为了简单其间,我们如此理解:运算器+控制器=CPU。存储器=内存(暂不包括外存,永不包括CACHE)。输入系统=键盘(不包括鼠标),输入系统=显示器(不包括打印机,绘图仪)。

5 寄存器和内存的区别
寄存器在CPU中。内存在内存条中。前者的速度比后者快100倍左右。后面的程序要求每条指定要么没有内存数据,要么在有一个寄存器的参与下有一个内存数据。(也就是说,不存在只访问内存的指令)。

6 汇编语言的计数
与生活中的计数不一样,汇编中的计数是从0开始的。比如16个计数,则是从0~15,而不是生活中的1~16。这一点看起来简单,真运算起来就不是件容易的事了,不信等着瞧。

7 进制问题
又与生活中不一样的地方是进制。切记下面的常识:
*)计算机内部存储都用二进制。
*)我们的汇编源程序默认都用十进制。(除非你指明类型)
*)我们用的调试程序debug默认的都是十六进制。(无法指明其他类型)
其中十六进制的十六个个位数依次是:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F。

8 进制转换
一个比较简单的方法是查表法。
十进制 十六进制 二进制
  0  0  0000
  1  1  0001
  2  2  0010
  3  3  0011
  4  4  0100
  5  5  0101
  6  6  0110
  7  7  0111
  8  8  1000
  9  9  1001
  10  A  1010
  11  B  1011
  12  C  1100
  13  D  1101
  14  E  1110
  15  F  1111
 
好了,结合6,7,8三条。大家来算一个“题”。某一组数据显示时,每个数据占了四个位置,
每行共十六个。问:十六进制的13位置在哪里(第几行,第几列)。
格式如下:m m m m n n n n o o o o p p p p '注:之所以没用ABC是怕与上面十六进制弄混。
      r r r r s s s s t t t t u u u u
      ........

[此贴被 286(unique) 在 11月15日15时15分 编辑过]


[此贴被 286(unique) 在 11月15日16时09分 编辑过]


--------------------------------------------------------------------------------
纵行下天,286足矣。

B2层 发表时间: 04-11-15 14:41

--------------------------------------------------------------------------------
回复: 286 [unique]  版主 回复  收藏 
第一讲 基础知识

1 访问内存
程序在内存中,访问内存是几乎每一程序都要进行的操作,计算机对内存编址是线性的,也就是说是一维的,比如256M的内存,地址就应该是从0~(256M-1),这个地址称为物理地址或绝对地址。
1.1 地址表示
但从汇编程序员的角度看,内存却是二维的,要说明一个地址,需要给出两个值,就象你在平面上指定一点需要说出(X,Y)坐标一样,汇编程序员的内存视角也需要两个“坐标”,前一个称为段地址(Segment),后一个称为偏移地址(Offset),该地址称为逻辑地址。
比如“1234:3DF5”就是一个地址。“1F3F:”不是一个地址,因为他只有段地址,没有编移地址。注意此后的地址都用十六进制表示。
1.2 地址计算
前面提到,计算机编址是一维的,汇编程序员是二维的,那么二者怎么换算呢?由后者到前者的换算方法是,“段地址串”后面加个“0”,然后再加上偏移地址。
比如“1234:3DF5”(十六进制的加减运算参见相关资料)
12340 ‘串后加了一个0
3DF5
-----
16135 ’注意此串仍然是十六进制。
  所以,汇编程序员眼中的地址“1234:3DF5”就是物理地址(计算机编址):16135。
  知道了由后者向前者的转换,那么由前者向后者的转换呢?
“不知道”,为什么不知道,继续往下看。
1.3 到底哪个地址对。
  知道了1.2的地址算法后,我又发现一个问题:
  “1000:6135”的物理地址是多少呢? 10000+6135=16135。
  “1001:6125”的物理地址呢? 10010+6125=16135。
  ......
  那么到底哪个对呢?问题的回答是这样的:假设我现在让你按一下“L”键,我可以告诉你如下几种方法中的一种或几种。1 请按一下“L”键; 2请按一下键盘上第四行第十个键;3 请按一下第十列中的第四个键;4 请按一下“K”右边的键;5 按标准指法单击一下右手无名指。
  举上面的例子也就是说,同一个地址有很多种表示方式,具体用哪一种,要看实际使用时的情况。但无论用哪种方式,只要能达到目的即可。(实际中该问题一般不会受此问题困扰,但初学时突然想不通)。
1.4 有多少内存可以访问
无论是段地址还是偏移地址都是四位十六进制(如果不够四位,前面补0)。也就是说:总共可以访问的地址说是:0000:0000~FFFF:FFFF。 总共FFFF0+FFFF+1=10FFF0个地址。也就是不到1M的空间。
记住如下结论:
*)不管你实际内存有多少,目前我们只能访问不到1M的空间。
*)而实际上连这1M也用不完。其中上端的384K的址只能读不能写,只能读,一般称为ROM。
*)低端的640K可以读写。但这640K的低端100多K也不能随便写,因此DOS系统使用该区。
*)原来1024M的内存,汇编程序只能使用其中400多K。这段内存的容易相当于一个普通文档的大小。不过这就足够了。

2 DEBUG的使用
先记住以下两个命令:D命令和Q命令。前者是显示内存内容,后者是退出DEBUG命令。
-------------以下为抄别的人内容---------------
DEBUG.EXE程序是专门为分析、研制和开发汇编语言程序而设计的一种调试工具,具有跟踪程序执行、观察中间运行结果、显示和修改寄存器或存储单元内容等多种功能。它能使程序设计人员或用户触及到机器内部,因此可以说它是80X86CPU的心灵窗口,也是我们学习汇编语言必须掌握的调试工具。

  1)DEBUG程序使用

在DOS提示符下键入命令:

  C>DEBUG [盘符:][路径][文件名.EXE][参数1][参数2]

这时屏幕上出现DEBUG的提示符“-”,表示系统在DEBUG管理之下,此时可以用DEBUG进行程序调试。若所有选项省略,仅把DEBUG装入内存,可对当前内存中的内容进行调试,或者再用N和L命令,从指定盘上装入要调试的程序;若命令行中有文件名,则DOS把DEBUG程序调入内存后,再由DEBUG将指定的文件名装入内存。
2)DEBUG的常用命令
(1)退出命令 Q
  格式:Q
  功能:退出DEBUG,返回到操作系统。
(2)显示存储单元命令 D
格式1:D[起始地址]
  格式2:D[起始地址][结束地址|字节数]
  功能:格式1从起始地址开始按十六进制显示80H个单元的内容,每行16个单元,共8行,每行右边显示16个单元的ASCII码,不可显示的ASCII码则显示“?”。格式2显示指定范围内存储单元的内容,其他显示方式与格式1一样。如果缺省起始地址或地址范围,则从当前的地址开始按格式1显示。
例如:  -D 200    ;表示从DS:0200H开始显示128个单元内容
        -D 100 120  ;表示显示DS:0100-DS:0120单元的内容
  说明:在DEBUG中,地址表示方式有如下形式:
  段寄存器名:相对地址,如:DS:100
段基值:偏移地址(相对地址),如:23A0:1500

--------------------------小抄结束--------------------------------

3 验证第一节里的内容
运行“开始/程序/附件/MS-DOS命令提示符”(这是win2000,win98下自己找吧)
在“_”下输入D,显示
-d
1398:0100 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0110 00 00 00 00 00 00 00 00-00 00 00 00 34 00 87 13 ............4...
1398:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1398:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-
我们记下:1398:011C的值是个34。1389:011C的物理地址应该是:13A9C。
那么1000:3A9C的物理地址也应该是13A9C,他的内存也应该是34,(因为本来就是一个地址吗,就象第三行第十列和第十列第三行当然应该是同一个位置)。
-d 1000:3A9C
1000:3A90                  34 00 87 13      4...
1000:3AA0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3AB0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3AC0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3AD0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3AE0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3AF0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3B00 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
1000:3B10 00 00 00 00 00 00 00 00-00 00 00 00      ............
-
果然如此,同样你可以验证:13A9:000C也肯定是指这一个地址,不信试试。 

--------------------------------------------------------------------------------
[sq回复:]
回复: 霜泉 [ljsh012]  论坛用户 回复  收藏  修改  删除 
286老大,这个讲座很好.希望再开一些其他语言的讲座.
看了以上,我也来说几句,不对的地方还望大家指正.286在讲物理地址的计算时没有讲为什么要在段地址的后面添0,我补充一下,因上面所涉及到的cpu的地址总线为20位,即寻址范围为0到2的20次方。即1MB。而存储器寻址时是通过物理地址,即地址从0开始编号,顺序加1(为线性增长)。而我们表示时是用16进制。所以物理地址是这样的00000--FFFFF(16进制,线性增长,一个16进制位对应4个二进制位,所以上面4*5=20位。)而机器规定每16个字节为一小段,看下面的
00000,00001,00002,......,0000F;
00010,00011,.............,0001F;
..................................
FFFF0,FFFF1,.............,FFFFF;
以上表示的就是内存的物理地址。每行第一个即为小段段地址。
而程序员编程时就不太可能都用物理地址来表示数据存放的地址了。解决这个问题的方法是把内存分段(分大段)。每段的大小可以自由划分(在20位地址总线下最大不超过64KB--为什么不能超过64KB呢?)自己划分的段地址必须为每小段的段首地址(在开辟段时机器会自动得到段地址,程序员只须关心偏移地址)而我们发现段地址(16进制下)的最后一位都是0.故我们表示段地址时只要了16进制下的前4位。这正好是两个字节。(这就便于在计算机中表示了)
  简单的讲,在程序员编程序时,因为段地址是只取了前四位(16进制下),所以在在计算物理地址时就要在后面补0。然后加上偏移地址。即得到实际物理地址。存储器也就找到了准确的存储单元的地址。
复杂点讲,就是机器为16位字长,而机器只识别二进制。段地址上面是取了4个16进制位,即二进制下的16位。偏移地址也是用16位(二进制)两个字节。2^16=64KB,这里说明了上面的段的大小为什么在64KB以下。(当然有时程序需要的空间会大过64KB,而此时光用偏移地址已经无法(不够)表示后面的内容了,所以程序员应该另加说明了(即已经在其他段下了)) 而我们知道上面的地址总线为20位。我们在16位字长的机器里怎样提供20位的地址呢。方法就是把段地址16位左移四位,再加上偏移地址就实现20位物理地址了。而我们知道左移4位即相当于把原先的数乘于2^4。即乘于16d.(10进制)。而16d(10进制)化成16进制后就是10H(16进制)所以在段地址后面添0实际上乘了个10H。

引用:
记住如下结论:
*)不管你实际内存有多少,目前我们只能访问不到1M的空间。
;286老大,这里怎么讲,在32地址总线下也只能寻这麽点,不严密吧,因该指明是在16字长(20为地址总线)的机子下阿。

引用:
大家来算一个“题”。某一组数据显示时,每个数据占了四个位置,
每行共十六个。问:十六进制的13位置在哪里(第几行,第几列)。
格式如下:m m m m n n n n o o o o p p p p '注:之所以没用ABC是怕与上面十六进制弄混。
  r r r r s s s s t t t t u u u u
  ........
你这里我看不明白是说些什么,你是说16进制的13这个地址在几行几列?还是指这个13为内存的一个内容,他在哪里?(内存的内容可以随意阿)还望指教。
谢谢。
偶也是刚学汇编,看了286老大的这篇没完的讲座,颇有收获,也许我说的一些可能不对或者是在钻牛角尖。(但我觉得这正好是初学者容易困惑的,所以写了以上)
还有一点不明白的是存储器即要花一些空间来存放地址,又要花一些空间存放数据。地址是怎样指向数据所在的字节呢?是不是开辟了一个段后,也跟着开辟一个存放地址的空间?不懂,高手指教。
感谢286,支持286。


[此贴被 霜泉(ljsh012) 在 11月18日16时14分 编辑过]
================================================================================
1 即使是32地址总线下,只要采用实模式,就只能使用其中的20根地址线。要使用所有地址线要采用保护模式,那另当别论。你看看,我们现在的机器早不是20位地址线了,可我用DEBUG运行的时候,显示的不还是20根地址线了吗?那是因为我们采用了实模式,只用最低的20根线。真无奈。

2 怨我没说清。我是指第几行第几列这个位置而不是值。这可就是大名鼎鼎的INT 13H。这可是破解硬盘保护卡的基础。

3 “还有一点不明白的是存储器即要花一些空间来存放地址,又要花一些空间存放数据。地址是怎样指向数据所在的字节呢?是不是开辟了一个段后,也跟着开辟一个存放地址的空间?不懂,高手指教。”
请听下回分解。

[此贴被 286(unique) 在 11月19日18时00分 编辑过]


--------------------------------------------------------------------------------
霜(双)化了,
能变成泉(全)么?
我在尽力溶化。
技术、品质、人际---->人生。
  http://shuangquan.oicp.net    


B4层 发表时间: 04-11-18 13:48

--------------------------------------------------------------------------------
回复: 286 [unique]  版主 回复  收藏 
4 DEBUG命令
-------------------继续小抄----------------
前面已学过:显示存储单元命令 D
再学一个命令
(1)修改存储单元命令 E

格式1:E[起始地址] [内容表]

格式2:E[地址]

功能:格式1按内容表的内容修改从起始地址开始的多个存储单元内容,即用内容表指定的内容来代替存储单元当前内容。

例如:?E DS:0100 'VAR' 12 34

表示从DS:0100 为起始单元的连续五个字节单元内容依次被修改为

'V'、'A'、'R'、12H、34H。

格式2是逐个修改指定地址单元的当前内容。

如:?E DS:0010

156F:0010 41.5F

其中156F:0010单元原来的值是41H,5FH为输入的修改值。若只修改一个单元的内容,这时按回车键即可;若还想继续修改下一个单元内容,此时应按空格键,就显示下一个单元的内容,需修改就键入新的内容,不修改再按空格跳过,如此重复直到修改完毕,按回车键返回DEBUG“-”提示符。如果在修改过程中,将空格键换成按“-”键,则表示可以修改前一个单元的内容。

-------------------小抄结束----------------

5 使用DOS时,汇编用户可以从DOS操作系统中得到什么?
现在编程,通常很多功能都是通过调用系统API。很多高级语言都直接把这些API包装起来,以系统接口或函数的方式提供给用户,那么汇编函数都能得到什么呢?
首先,汇编用户有很多东西可以调用。他们主要是:
5.1 BIOS提供的接口。现在硬件与软件的区分已越来越不明显,很多硬件不仅仅是电路,而还要提供一些固化写入硬件的一部分“程序”,这些程序以ROM的方式出现,汇编用户最大的好处就是可以直接使用这些“程序”,这些使用不仅功能强大,而且效率非常高。
5.2 DOS功能调用,作为操作系统也象BIOS一样向用户提供了相应的“程序”。这些程序在很大程序上扩充了BIOS。与BIOS不同的是,这部分程序放在内存中,它可以被修改。而BIOS中不能再修改。
==========================================================
以上两种接口都通过一种相同的格式调用,这些程序统称为“中断”,现在先不要理解中断的本意,你现在可以认为是系统提供给你的函数。
============================================================
5.3 系统共享数据区。编过程序的人都知道全局变量的好处,全局变量方便之外在于任何函数、过程都可以调用、读取、修改。全局变量不足之处是危险性,有一个过程改了这个变量值,其它的也得跟着改变了。DOS操作系统同样也提供了这样的共享数据区,该区是整个系统的共享区,任何程序都可以查找、修改。当然,修改某处必然会对其它程序造成影响。

6 再谈中断
前面5.2已提到中断了,现在问题是不同硬件不一样,即使相同硬件的ROM,不同版本,各个BIOS中断程序所处的位置也不一样,DOS中断也一样,不同版本、不同配置,在内存位置也不一样。那么你使用某一个中断,系统怎么知道你使用的那个中断程序在哪呢?
为了解决这一问题,DOS会在启动的时候,把所有这些(BIOS和DOS)中断的首地址保存到一个地址。这个地址很容易记,这段地址是内存的绝对零地址(0000:0000)。前面已讲过,每个地址在汇编程序员角度来看是二维的,也就是分为段地址和偏移地址。每个地址各占两个字节,所以要表示这个二维地址需要4个字节。所以每个中断首地址由4个字节表示。一共256个中断,占用了1024个字节的位置。
另外需要注意的是,这4个表示地址的字节,数据是由低向高的。比如12 34 56 78所表示的地址是:7856:3412。
一般用INT M表示中断M,如果M是十六进制,则在后面加上一个H。比如19号中断,十六进制应该是13H。所以该中断就是INT 13H。

7 再谈系统共享数据区
该共享数据区在绝对地址:0040:0000开始。

8 验证我上面说的内容
8.1 找中断
运行DEBUG后。输入D 0000:0000。显示绝对零地址的内容。
C:/>debug
-d 0:0
0000:0000 68 10 A7 00 8B 01 70 00-16 00 9B 03 8B 01 70 00 h.....p.......p.
0000:0010 8B 01 70 00 B9 06 0E 02-40 07 0E 02 FF 03 0E 02 ..p.....@.......
0000:0020 46 07 0E 02 0A 04 0E 02-3A 00 9B 03 54 00 9B 03 F.......:...T...
0000:0030 6E 00 9B 03 88 00 9B 03-A2 00 9B 03 FF 03 0E 02 n...............
0000:0040 A9 08 0E 02 99 09 0E 02-9F 09 0E 02 5D 04 0E 02 ............]...
0000:0050 A5 09 0E 02 0D 02 DC 02-B8 09 0E 02 8B 05 0E 02 ................
0000:0060 02 0C 0E 02 08 0C 0E 02-13 0C 0E 02 AD 06 0E 02 ................
0000:0070 AD 06 0E 02 A4 F0 00 F0-37 05 0E 02 71 84 00 C0 ........7...q...
-u 0070:018B
0070:018B 1E      PUSH  DS
0070:018C 50      PUSH  AX
0070:018D B84000    MOV  AX,0040
0070:0190 8ED8    MOV  DS,AX
0070:0192 F70614030024 TEST  WORD PTR [0314],2400
0070:0198 754F    JNZ  01E9
0070:019A 55      PUSH  BP
0070:019B 8BEC    MOV  BP,SP
0070:019D 8B460A    MOV  AX,[BP+0A]
0070:01A0 5D      POP  BP
0070:01A1 A90001    TEST  AX,0100
0070:01A4 7543    JNZ  01E9
0070:01A6 A90002    TEST  AX,0200
0070:01A9 7422    JZ  01CD
首先,D命令把中断首地址显示出来。每4个表示一个地址。其中INT 0的中断首地址为:00A7:1068,INT 1的中断地址为:0070:018B.......0070:018B是中断3的首地址。后面那个U命令就表示显示该地址的“中断程序”的内存。
  你们可以试着找找INT 13H的位置在哪。
8.2 验证系统共享数据区
  系统共享数据区内容极为丰富,我实在记不住哪么多了。我曾记在一个本上,可惜那个本早在N年前(3<N<6)就丢了。兄弟们谁找到这个地址的内容,一定要贴上来,这里有东西可以让大家眼界大开。
  前几年,我用的286计算机是黑白显示器(555555~~~~~~~~~,别嫌我老、旧、慢呀),可当时有个游戏非要彩显,不是彩显不让运行。我就是改了这个区的某一个位,让哪游戏“以为”我用的是彩显,于是游戏能用了。虽然不好看,但总能用。
  在DOS下,你每按一个键,系统都会记下来,下面我们一起找找这个键盘缓冲区的地址。知道这个地址,你就可以作一个“虚拟”键盘,通过发命令来模拟某个人在按键。这个地址位于:0040:001E。 其中每个键有两个字节,一个字节是ASCII码,一个是扫描码。共16个。
C:/>debug
-d 40:0
0040:0000 F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F ..........x.x...
0040:0010 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 20 39 "....(....*.*. 9
0040:0020 34 05 30 0B 3A 27 30 0B-0D 1C 64 20 20 39 34 05 4.0.:'0...d 94.
0040:0030 30 0B 3A 27 30 0B 0D 1C-71 10 0D 1C 64 20 00 00 0.:'0...q...d ..
0040:0040 A2 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00 ..........P.....
0040:0050 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0040:0060 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 A1 B7 11 00 .....)0.........
0040:0070 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01 ................
-d 0040:0000
0040:0000 F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F ..........x.x...
0040:0010 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 3A 27 "....(....*.*.:'
0040:0020 30 0B 30 0B 30 0B 30 0B-0D 1C 64 20 20 39 30 0B 0.0.0.0...d 90.
0040:0030 30 0B 30 0B 30 0B 08 0E-08 0E 34 05 30 0B 00 00 0.0.0.....4.0...
0040:0040 1F 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00 ..........P.....
0040:0050 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0040:0060 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 24 B8 11 00 .....)0.....$...
0040:0070 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01 ................
-
既然是键盘缓冲区,每个输入的键都会显示在该区中,第一次我只输入了“d 40:0”,所以你可以在此后显示数据右边字符中找到这些字符,注意是间隔开的。
第二次我输入“d 0040:0000”,则右边显示的是“d 0040:0000”的内容。你可以找找。




--------------------------------------------------------------------------------
纵行下天,286足矣。

B5层 发表时间: 04-11-19 17:45
回复时间:(2004-11-20 00:34:18.000)
--------------------------------------------------------------------------------
[sq回复:]
回复: 仙人掌 [cailman]  论坛用户 回复  收藏 
找别扭:
*)低端的640K可以读写。但这640K的低端100多K也不能随便写,因此DOS系统使用该区。
*)原来1024M的内存,汇编程序只能使用其中400多K。这段内存的容易相当于一个普通文档的大小。不过这就足够了。


To:霜泉 [ljsh012]
  应该说存储器上的每个字节空间都有编号,里面只能放二进制数.内存(存储器)里的二进制数你把它当指针用的时候它就表示一个地址,把它当数据用的时候它就是数据.
  而你给CPU一个地址然后它怎么找到对应的内存空间,这个我也不懂(我想你问的是这个意思吧).期待懂的人指教.

[此贴被 仙人掌(cailman) 在 11月20日23时15分 编辑过]


--------------------------------------------------------------------------------
20CN的主要作用是为广大计算机爱好者提供一个友好的技术交流平台。并整理和发掘网络安全、黑客方面技术文献及工具、代码。为大家提供发布安全、黑客相关文章及工具的园地。
20CN的建设需要你的参与,按此可为网站更新文档
B7层 发表时间: 04-11-20 23:00

--------------------------------------------------------------------------------
回复: 霜泉 [ljsh012]  论坛用户 回复  收藏  修改  删除 
不错,感觉又有点长进。
而且从中断程序的地址保存在内存绝对物理地址的开始中可以猜想我们的程序的地址或许就紧跟着保存在后面了。(赫赫,这里全属瞎想。)
用U命令能够列出汇编程序,同时显示对应的堆栈的内容(16进制)我想问的是一个汇编指令按理来讲对应的二进制代码应该是相同的。但是用多个u命令列出的程序中,比如push指令,其对应的存储他的代码都不同。说明我的分析不对,那么汇编指令在内存中是怎样存储的?(或许内存中根本不存储汇编指令,而是用机器来确定)
另外一个问题是,用c语言写个赋值语句,比如用a=6;来存储值,&a来得到内存中变量a的地址。然后用%x输出a的地址为ffc4.原本以为用d 0000:ffc4能够显示出a变量中存储的值6,但是结没有显示出来。说明我们用c语言得到的这个变量a的地址并非和内存中实际a的地址相符。(应该有联系,但目前我不知道之间的关系)
286老大,麻烦解答一下上面的问题。谢谢。

To:仙人掌。
  我觉得你对上面的理解或许还有些不实在。你知道为什么要在内存地址开始存储中断的地址吗?那是因为内存加载中断程序时是把它放在绝对地址的后后面了,程序员很难找到在哪里俄。而程序员要调用中断程序时,显然只能通过二维的方法:段地址+偏移地址。而正如上面所讲,dos在加载中断程序时已经把他的绝对物理地址用二维的形式保存在物理地址的开始处了。程序员调用时只须用调用中断的命令int mH(第几个中断)(其实我想也可以直接用段地址+偏移地址的方法找到中断程序所在的地方只是这样就麻烦了。汇编程序直接用个int指令就完成这个工作了,省事。)至于我问的那个问题,还是等待后面几讲之后再作定论。我想到时就能明白了。(其实我现在是这麽想的,绝对物理地址不需要存储的。因为他是成线性增长的。存储器在找由程序员给出的二维地址后(通过计算后就能得到绝对物理地址),而找的这个过程因为有20位(假设是20位总线)的数据总线,而20位的数据总线可以表示2^20个不同的情况,这些情况分别对应内存的不同的实际物理地址。这样就完成找的工作了,这里说明cpu一次只能找到一个地址。而为什么这麽快能,那就是频率的问题了。所以那个fsb(前端控制总线)就是关键影响速度的。赫赫,是自己理解的,或许下一讲后我的想法就崩溃了)

[此贴被 霜泉(ljsh012) 在 11月21日00时49分 编辑过] 回复时间:(2004-11-21 00:52:39.000)
--------------------------------------------------------------------------------
[sq回复:]
回复: 286 [unique]  版主 回复  收藏 
TO peregrine:
你问题的答案部分在你自己发的贴子中都可以找到。还有些请等待并看对霜泉的回答。

TO 仙人掌:
多谢指正及解疑。
“而你给CPU一个地址然后它怎么找到对应的内存空间,”,这个要看计算机原理了。内存访问这一章节。

TO 霜泉:
“从中断程序的地址保存在内存绝对物理地址的开始中可以猜想我们的程序的地址或许就紧跟着保存在后面了”,跟在后面是不紧,但很显然不是“紧”跟在后面,因为中断后面是系统数据区,再向后是操作系统自己的程序占用。这大约占100K左右,当然你运行的系统程序越多,为个数据越大。如果操作系统占的量大太了(比如大于500K),程序就没空间,这时会出现“内存空间不够的错误”。
  “用U命令能够列出汇编程序,同时显示对应的堆栈的内容(16进制)”,不是堆栈内存,而是汇编命令所对应的机器码,这也就是我此前说的汇编语言与机器语言是等价的原因。
  “一个汇编指令按理来讲对应的二进制代码应该是相同的。”一个汇编指令对应是相同,比如push dx与push dx肯定相同,(,别朝我扔砖头),但push dx与push cx不是同一个汇编指令。而是两个不同的指令。
  “另外一个问题是...之间的关系)”,原理对,但不是一两句话就能说清,涉及太多,所以暂且不说。
  你对仙人掌的解答不完全对,,呵呵,一则,中断地址总要放一个地方吧?你说放哪呢?比如放到1234:5678,也很好记,但到哪个时候你还会不会问:为什么放1234:5678,而不是0000:0000的,他总要放个地方。因此放绝对零也无可厚非。另外,你查一下“计算机原理”中内存访问章节,CPU访问所有内存的址时,速度都是完全一样的。也就是说,0000:0000不比FFFF:FFFF快多少。这一点就象是让你写由圆心到圆周上任意一点的矩离相等一样。



--------------------------------------------------------------------------------
纵行下天,286足矣。

B9层 发表时间: 04-11-22 09:21

--------------------------------------------------------------------------------
回复: 憨狗 [hackgou]  论坛用户 回复  收藏 
哇塞!这么热闹啊??呵呵
我也来凑凑热闹!

1。说说仙人掌兄的问题吧:
   
引用:
--------------------------------------------------------------------------------
而你给CPU一个地址然后它怎么找到对应的内存空间,
--------------------------------------------------------------------------------



其实这个挺简单的:
先说说我们讨论的这个问题的大前提:我们现在讨论的是80×86时代的汇编(也是20位的dos时代,可别以为有非20位的dos哦/
:P),而非如今主流的32位平台,因为32位平台向下兼容,所以我们现在的话题有可能是对的,因为很多
内容在32位下就不一定了。

开始主题:   
引用:
--------------------------------------------------------------------------------
而你给CPU一个地址然后它怎么找到对应的内存空间,
--------------------------------------------------------------------------------



在dos时代(硬件方面是386以下),因为16位的处理器无法访问(寻址)20位的地址总线提供的1M内存,于是就使用分段的办
法解决:每个段64K,
(为什么是64K??因为16位寄存器可以存储的最大范围就是2^16=2^6×2^10=64K。
按照最大段来计算,多少段?1M/64K=16个段),这样就可以利用两个16位寄存器来寻址这20位的1M内存(虽然,是浪费了12位
宝贵的寄存器位数,两个16位寄存器合起来的寻址能力是2^32=4G,现在只需利用其中2^20的寻址能力,但却变相实现了利用
两个16位寄存器来寻址20位1M的内存的功能),因此可以利用一个寄存器来表示段地址(那个64K的段从哪儿开始),另外一个
16位的寄存器来表示你要访问的数据在该64K的段内的什么地方。起前一个功能的寄存器就叫段寄存器(按段寄存器所指的段的
用途来分,这些段寄存器又分为:CS、DS、SS、ES等。而后一个功能则一般通过通用寄存器来实现的,通常后面这个用来在段
内寻址的地址就叫做段内偏移(offset),它也是16位的寄存器。

在具体寻址的时候是如何计算的呢?段寄存器和段内偏移地址直接相加?不是的,因为那样最多能够达到17位的寻址能力。正
确的做法是将段寄存器左移4位,然后加上段内偏移地址,这样就得到了20位的地址了,使用则20位地址就能够实现1M的存储空
间寻址了。

这个计算是谁来完成的呢??人工么?还是编译器编译的时候执行的呢??都不是。而是CPU内部的BIU(bus interface unit
,总线接口单元)来完成。它包括段寄存器(CS、DC、SS、ES)和地址产生器(当然不止两个部分,但是和内存寻址的就主要是
这两部分),当遇到一个寻址的指令后,地址产生器就执行逻辑地址(16位的段:16位的偏移)到20位的物理地址(PA)的计
算,计算的公式如前所述(段地址乘以16+偏移地址),这样就“找到对应的内存空间“。


2。 
引用:
--------------------------------------------------------------------------------
一个汇编指令按理来讲对应的二进制代码应该是相同的
--------------------------------------------------------------------------------


这个问题其实和汇编语句到底如何编译位机器语言有关,一条汇编语句包含两个部分:80×86指令和数据部分。其中数据部分
包括:立即数、寄存器等等。比如mov
dx,ax其中mov是指令部分。而dx,ax就是数据部分(也可以理解为汉语的动宾关系:指令为动词,数据部分为宾语,别问我谁是
主语啊?问我就告诉你:EU)。所以如果两条汇编语句的动宾(指令和数据部分)全相同,则他们的二进制代码也就完全相同
。这是以前在C51上亲自进行汇编语句到机器语句的手工翻译时所遵循的规律。因为C51上没有关于栈的操作,所以抱歉的说:
没有push指令方面的具体的翻译经验可以讨论。也无法直接回答你关于push指令不同的问题。但是现在我们参考Intel公司的指
令格式和编码来做做80×86指令系统的试验,先来看看两条关于堆栈操作(push ax)和立即数(mov
ax,1234)操作指令的编码格式来窥窥汇编语句到二进制代码转换的过程,以理解不同语句与其二进制代码的关系:
1。压栈:
PUSH
register 1111 1111 : 11 110 reg
register (alternate encoding) 0101 0 reg

2。弹栈:
POP
register 1000 1111 : 11 000 reg
register (alternate encoding) 0101 1 reg

3。立即数操作:
immediate to register 1100 011w : 11 000 reg : immediate data
immediate to register (alternate encoding) 1011 w reg : immediate data

4。寄存器域:

reg w=0  w=1 reg w=0 w=1
000 AL  AX 000 AL EAX
011 BL  BX 011 BL  EBX

可以看出来Intel本身对同一指令都有两种不同的编码格式,但是无论我们选择哪一种格式编码,得到的二进制结果虽然不一样
,但是执行的结果却是一样的。好了,我们来段简单的汇编语句:
mov ax,1234
push ax
pop bx


我们先来手工翻译一下:

Mov ax,1234指令有两种翻译方法:

汇编语句    ——>  二进制代码        ——>  16进制代码
法一:Mov ax,1234    ——>  11 000 000  1234  ——>  C0 1234
法二:Mov ax,1234    ——>  1011 1 000  1234  ——>  B8 1234

Push ax也有两种翻译方法:

      汇编语句    ——>  二进制代码        ——>  16进制代码
法一:push ax    ——>  1111 1111:11 110 000  ——>  FF:F0
法二:push ax    ——>  0101 0 000            ——>  50

Pop  bx也有两种翻译方法:

      汇编语句    ——>  二进制代码        ——>  16进制代码
法一:Pop bx    ——>  1000 1111:11 000 011  ——>  8F:C3
法二:Pop bx    ——>  0101 1 011            ——>  5B

那么根据我们的手工译码有两套方案:
方案一:
mov ax,1234    ——>  C01234
push ax        ——>  FF:F0
pop bx          ——>  8F:C3

方案二:

mov ax,1234    ——>  B81234
push ax        ——>  50
pop bx          ——>  5B


代码:
--------------------------------------------------------------------------------

-a148E:0100 mov ax,1234
148E:0103 push ax
148E:0104 pop bx
148E:0105-u 100
148E:0100 B83412        MOV    AX,1234 
;怎么样??和我们手工翻译的第二套方案一模一样吧。
148E:0103 50            PUSH    AX    ;还真是一点都不假呢!
148E:0104 5B            POP    BX    ;真的呢!
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0100  NV UP EI PL NZ NA PO NC
148E:0100 B83412        MOV    AX,1234
;为了验证正确性,再来执行一下??注意红色部分的变化
-g 103
AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0103  NV UP EI PL NZ NA PO NC
148E:0103 50            PUSH    AX
-g
104AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEC  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0104  NV UP EI PL NZ NA PO NC
148E:0104 5B            POP    BX
-g
105AX=1234  BX=1234  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0105  NV UP EI PL NZ NA PO NC
148E:0105 0000          ADD    [BX+SI],AL                        DS:1234=00

--------------------------------------------------------------------------------


最后三条红色部分跟踪语句可以换成(t命令,更显专业):

代码:
--------------------------------------------------------------------------------

-t
AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0103  NV UP EI PL NZ NA PO NC
148E:0103 50            PUSH    AX
-t
AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEC  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0104  NV UP EI PL NZ NA PO NC
148E:0104 5B            POP    BX
-t
AX=1234  BX=1234  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0105  NV UP EI PL NZ NA PO NC
148E:0105 0000          ADD    [BX+SI],AL                        DS:1234=00

--------------------------------------------------------------------------------




写完了这些,基本上可以回答霜泉兄的问题吧,.
大家看完了,如果我也写清楚到大家那个完全理解的地步了的话,不知道兄弟们是不是有种想写编译器的冲动啊?呵呵。其实
涉及的东西还远不止这些呢!


[此贴被 霜泉(ljsh012) 在 12月02日13时39分 编辑过]

========================================
霜(双)化了,
能变成泉(全)么?
我在尽力溶化。

技术、品质、人际---->人生。

http://shuangquan.oicp.net



========================================
20CN代表着20世纪的古典黑客精神。我们不是黑客,但是我们拥有真正黑客的内涵,思想,方向,激情与动力。
发表时间: 04-12-01 13:33


回复: NetDemon [netdemon]   ADMIN  登录
20CN服务器损坏,现正使用备用服务器,数据被恢复到11月11日的状态,在此之后注册的用户需要重新注册.

  2004-11-30
  NetDemon


谢谢!!!

========================================

微软给了我窗户,因此UNIX给了我房子。微软给我窗户了吗?
没有!所以UNIX没有给了我房子,我仍然游荡在Internet上
WELCOME TO WWW.20CN.COM
========================================
20CN的主要作用是为广大计算机爱好者提供一个友好的技术交流平台。并整理和发掘网络安全、黑客方面技术文献及工具、代码。为大家提供发布安全、黑客相关文章及工具的园地。
发表时间: 04-12-01 15:41


回复: 286 [unique]   版主  登录
感谢霜泉兄弟,正是你的仔细认真,才得挽救这个文章,其中有很多内容我是在线写的,没有本地备份。
最近太忙,得有空了再接着写。

========================================
纵行下天,286足矣。
========================================
任何成员不得以20CN的名义攻击网站或进行其他危害网络安全或损害本组织形象的行为。
发表时间: 04-12-01 17:53


回复: 霜泉 [ljsh012]   论坛用户  登录
老大们就不用客气了。算是我对20cn的一点点付出,(有点臭美了是不?)毕竟我已在这里汲取了许多知识。

========================================
霜(双)化了,
能变成泉(全)么?
我在尽力溶化。

技术、品质、人际---->人生。

http://shuangquan.oicp.net



========================================
任何成员不得以20CN的名义攻击网站或进行其他危害网络安全或损害本组织形象的行为。
发表时间: 04-12-01 18:48


回复: 憨狗 [hackgou]   论坛用户  登录
感谢霜泉兄对本贴做的本地备份,要不然大家的这些心血可就付诸东流了哦,要知道我当初可是写到了凌晨一点过才完成了最后的修改哦。/:p。:
但是在11号之后我对我的回帖进行了一些修改,还好在本地存有档,如下:麻烦更改一下我的原文,谢谢:


哇塞!这么热闹啊??呵呵
我也来凑凑热闹!

1。说说仙人掌兄的问题吧:
   
引用:
而你给CPU一个地址然后它怎么找到对应的内存空间,


其实这个挺简单的:
先说说我们讨论的这个问题的大前提:我们现在讨论的是80×86时代的汇编(也是20位的dos时代,可别以为有非20位的dos哦/
:P),而非如今主流的32位平台,因为32位平台向下兼容,所以我们现在的话题有可能是对的,因为很多
内容在32位下就不一定了。

开始主题:   
引用:
而你给CPU一个地址然后它怎么找到对应的内存空间,


在dos时代(硬件方面是386以下),因为16位的处理器无法访问(寻址)20位的地址总线提供的1M内存,于是就使用分段的办
法解决:每个段64K,
(为什么是64K??因为16位寄存器可以存储的最大范围就是2^16=2^6×2^10=64K。
按照最大段来计算,多少段?1M/64K=16个段),这样就可以利用两个16位寄存器来寻址这20位的1M内存(虽然,是浪费了12位
宝贵的寄存器位数,两个16位寄存器合起来的寻址能力是2^32=4G,现在只需利用其中2^20的寻址能力,但却变相实现了利用
两个16位寄存器来寻址20位1M的内存的功能),因此可以利用一个寄存器来表示段地址(那个64K的段从哪儿开始),另外一个
16位的寄存器来表示你要访问的数据在该64K的段内的什么地方。起前一个功能的寄存器就叫段寄存器(按段寄存器所指的段的
用途来分,这些段寄存器又分为:CS、DS、SS、ES等。而后一个功能则一般通过通用寄存器来实现的,通常后面这个用来在段
内寻址的地址就叫做段内偏移(offset),它也是16位的寄存器。

在具体寻址的时候是如何计算的呢?段寄存器和段内偏移地址直接相加?不是的,因为那样最多能够达到17位的寻址能力。正
确的做法是将段寄存器左移4位,然后加上段内偏移地址,这样就得到了20位的地址了,使用则20位地址就能够实现1M的存储空
间寻址了。

这个计算是谁来完成的呢??人工么?还是编译器编译的时候执行的呢??都不是。而是CPU内部的BIU(bus interface unit
,总线接口单元)来完成。它包括段寄存器(CS、DC、SS、ES)和地址产生器(当然不止两个部分,但是和内存寻址的就主要是
这两部分),当遇到一个寻址的指令后,地址产生器就执行逻辑地址(16位的段:16位的偏移)到20位的物理地址(PA)的计
算,计算的公式如前所述(段地址乘以16+偏移地址),这样就“找到对应的内存空间“。


2。 
引用:
一个汇编指令按理来讲对应的二进制代码应该是相同的

这个问题其实和汇编语句到底如何编译位机器语言有关,一条汇编语句包含两个部分:80×86指令和数据部分。其中数据部分
包括:立即数、寄存器等等。比如mov
dx,ax其中mov是指令部分。而dx,ax就是数据部分(也可以理解为汉语的动宾关系:指令为动词,数据部分为宾语,别问我谁是
主语啊?问我就告诉你:EU)。所以如果两条汇编语句的动宾(指令和数据部分)全相同,则他们的二进制代码也就完全相同
。这是以前在C51上亲自进行汇编语句到机器语句的手工翻译时所遵循的规律。因为C51上没有关于栈的操作,所以抱歉的说:
没有push指令方面的具体的翻译经验可以讨论。也无法直接回答你关于push指令不同的问题。但是现在我们参考Intel公司的指
令格式和编码来做做80×86指令系统的试验,先来看看两条关于堆栈操作(push ax)和立即数(mov
ax,1234)操作指令的编码格式来窥窥汇编语句到二进制代码转换的过程,以理解不同语句与其二进制代码的关系:
1。压栈:
PUSH
register 1111 1111 : 11 110 reg
register (alternate encoding) 0101 0 reg

2。弹栈:
POP
register 1000 1111 : 11 000 reg
register (alternate encoding) 0101 1 reg

3。立即数操作:
immediate to register 1100 011w : 11 000 reg : immediate data
immediate to register (alternate encoding) 1011 w reg : immediate data

4。寄存器域:

reg w=0  w=1 reg w=0 w=1
000 AL  AX 000 AL EAX
011 BL  BX 011 BL  EBX

可以看出来Intel本身对同一指令都有两种不同的编码格式,但是无论我们选择哪一种格式编码,得到的二进制结果虽然不一样
,但是执行的结果却是一样的。好了,我们来段简单的汇编语句:
mov ax,1234
push ax
pop bx


我们先来手工翻译一下:

Mov ax,1234指令有两种翻译方法:

汇编语句    ——>  二进制代码        ——>  16进制代码
法一:Mov ax,1234    ——>  11 000 000  1234  ——>  C0 1234
法二:Mov ax,1234    ——>  1011 1 000  1234  ——>  B8 1234

Push ax也有两种翻译方法:

      汇编语句    ——>  二进制代码        ——>  16进制代码
法一:push ax    ——>  1111 1111:11 110 000  ——>  FF:F0
法二:push ax    ——>  0101 0 000            ——>  50

Pop  bx也有两种翻译方法:

      汇编语句    ——>  二进制代码        ——>  16进制代码
法一:Pop bx    ——>  1000 1111:11 000 011  ——>  8F:C3
法二:Pop bx    ——>  0101 1 011            ——>  5B

那么根据我们的手工译码有两套方案:
方案一:
mov ax,1234    ——>  C01234
push ax        ——>  FF:F0
pop bx          ——>  8F:C3

方案二:

mov ax,1234    ——>  B81234
push ax        ——>  50
pop bx          ——>  5B


代码:

-a
148E:0100 mov ax,1234
148E:0103 push ax
148E:0104 pop bx
148E:0105

-u 100
148E:0100 B83412        MOV    AX,1234 
;怎么样??和我们手工翻译的第二套方案一模一样吧。
148E:0103 50            PUSH    AX    ;还真是一点都不假呢!
148E:0104 5B            POP    BX    ;真的呢!

-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0100  NV UP EI PL NZ NA PO NC
148E:0100 B83412        MOV    AX,1234
;为了验证正确性,再来执行一下??注意红色部分的变化

-g 103


AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0103  NV UP EI PL NZ NA PO NC
148E:0103 50            PUSH    AX


-g 104

AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEC  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0104  NV UP EI PL NZ NA PO NC
148E:0104 5B            POP    BX


-g 105

AX=1234  BX=1234  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0105  NV UP EI PL NZ NA PO NC
148E:0105 0000          ADD    [BX+SI],AL                        DS:1234=00



最后三条红色部分跟踪语句可以换成(t命令,更显专业):
代码:



-t

AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0103  NV UP EI PL NZ NA PO NC
148E:0103 50            PUSH    AX

-t


AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEC  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0104  NV UP EI PL NZ NA PO NC
148E:0104 5B            POP    BX

-t


AX=1234  BX=1234  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=148E  ES=148E  SS=148E  CS=148E  IP=0105  NV UP EI PL NZ NA PO NC
148E:0105 0000          ADD    [BX+SI],AL                        DS:1234=00





写完了这些,基本上可以回答霜泉兄的问题吧,.
大家看完了,如果我也写清楚到大家那个完全理解的地步了的话,不知道兄弟们是不是有种想写编译器的冲动啊?呵呵。其实
涉及的东西还远不止这些呢!


[此贴被 憨狗(hackgou) 在 12月01日21时53分 编辑过]

========================================
[img]http://www.20cn.net/club/images/freebsd/bsdplate.gif[/img]



========================================
20CN代表着20岁左右的中国人,在这个年龄,我们的热情为祖国为社会为自己而燃烧,我们尝试着用尚显娇嫩的肩膀去承担自己的责任。
发表时间: 04-12-01 21:48


回复: 霜泉 [ljsh012]   论坛用户  登录
憨狗兄,我已把你的原文按照你说的更改了。但是红色字样就没了。而且本贴在美观方面就远不如原先的了,但是看着还行,建议286老大保留着憨狗兄后来的回复。

========================================
霜(双)化了,
能变成泉(全)么?
我在尽力溶化。

技术、品质、人际---->人生。

http://shuangquan.oicp.net



========================================
20CN是民间非盈利网络安全组织
发表时间: 04-12-02 13:46


回复: 林中鸟 [autosee]   论坛用户  登录
感谢20cn各位朋友,更感谢286同志,原本我对汇编没有接触过,以前想学,但听朋友说很难,所以就没去看这方面的书,但自从我看到本贴后,看到286及各位20CN社友的细心讲解,让我知道了汇篇的大门在哪,对它产生了兴趣,至少不像别的那样,一开始就让我感到学起来难,而看到这里的贴子上我跟着朋友们的讲解,思维也跟着朋友的转,没有觉得有什么难处,所以希望各位能将汇编讲解进行到底,虽然没有物质上的奖励,但却有对各位发自内心的感激。

========================================
  书山有路勤为径,学海无涯苦做舟.
========================================

========================================
技术的精纯无私的奉献是我们最大的追求目标。
发表时间: 04-12-02 16:41


回复: ALLyeSNO [allyesno]   论坛用户  登录
问一下 windows里的debug支持调试 32位的汇编吗?

学汇编有什么用?
汇编产生于DOS时代或更早,而现在是Windows时代,所以可能遗憾地说:尽管还有批牛人在用汇编开发核心级程序,但我们几乎没什么用,除了必要时间能拿来分析一两个程序的部分代码之外,别的也就没干什么用了。并且并不是所有的汇编命令都能在windows下使用。而泛泛地追求“时髦”而学本语言,最后的结果是损了夫人又折兵。所以学之前你要考虑好。我劝那些为了当“黑客”而学汇编的人就此止步。

win32汇编呢?黑客守护者 就是用它编出来的

[此贴被 ALLyeSNO(allyesno) 在 12月02日17时54分 编辑过]

========================================
做过客的匆匆 做匆匆的过客
========================================
20CN是民间非盈利网络安全组织
发表时间: 04-12-02 17:43

论坛: 编程破解

 

20CN网络安全小组版权所有
Copyright © 2000-2003 20CN NetSafe Group. All Rights Reserved.
论坛程序编写:NetDemon

程序执行时间:46 ms 其中 23 ms user ,23 ms system
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值