2011-05-06 76 views
2

我想我开始明白怎么回事,但现在我已经花年龄试图理解为什么下面不工作:访问此字符串常量的此程序集有什么问题?

org 0x7C00 

mov ax,0x0000 
mov ds,ax 

mov si, HelloWorld 

HelloWorld db 'Hello World',13,10,0 

什么我期待的是,mov si, HelloWorld指令将将0x7C08的值设置为si(即0x7c00 + HelloWorld的偏移量),准备好像lodsb之类的值。

当我建立这个(使用NASM),并运行它(使用Bochs的)我找到了该结束的指令,实际上是这样的:

mov si, 0x8400 

这是为什么,而其中的值是0x8400来自?

更新:我发现,在数据段将HelloWorld产生预期的输出:

section .data 
HelloWorld db 'Hello World',13,10,0 

这是为什么?

FYI用于构建该命令是nasm -f bin input.asm -o output.bin

更新2我突然意识到0x84000x7c00 + 0x0800,其中8是从输出开始偏移的HelloWorld - 我注意到这一点,当我发现当使用org 0时,使用的地址是0x0800

我仍然不明白发生了什么 - 虽然发现这只是让我更加困惑!

按照要求,使用ndisasm拆解:

00000000 B80000   mov ax,0x0 
00000003 8ED8    mov ds,ax 
00000005 BE0084   mov si,0x8400 
00000008 48    dec ax 
00000009 656C    gs insb 
0000000B 6C    insb 
0000000C 6F    outsw 
0000000D 20576F   and [bx+0x6f],dl 
00000010 726C    jc 0x7e 
00000012 640D0A00   fs or ax,0xa 
+1

你如何建立和运行它?以下是我所看到的: 'mov si,07C08' – 2011-05-06 16:12:03

+1

您是否在nasm命令行上使用了任何特殊标志?当我通过nasm运行上面的代码时,我得到了你期望的。 – Aaron 2011-05-06 16:14:46

+0

是的,给我们完整的'nasm'命令行来重现这一点。 – NPE 2011-05-06 16:19:03

回答

1

升级您的nasm副本。

使用NASM 2.09rc1我得到以下(意外)拆卸:

00000000 B80000   mov ax,0x0 
00000003 8ED8    mov ds,ax 
00000005 BE0084   mov si,0x8400 
00000008 48    dec ax 
00000009 656C    gs insb 
0000000B 6C    insb 
0000000C 6F    outsw 
0000000D 20576F   and [bx+0x6f],dl 
00000010 726C    jc 0x7e 
00000012 640D0A00   fs or ax,0xa 

使用NASM 08年9月2日,我得到以下(预期)拆卸:

00000000 B80000   mov ax,0x0 
00000003 8ED8    mov ds,ax 
00000005 BE087C   mov si,0x7c08 
00000008 48    dec ax 
00000009 656C    gs insb 
0000000B 6C    insb 
0000000C 6F    outsw 
0000000D 20576F   and [bx+0x6f],dl 
00000010 726C    jc 0x7e 
00000012 640D0A00   fs or ax,0xa 

我想这是一个发布候选人的原因... :)

+0

再次感谢您的帮助 - 我现在感觉有点聪明(现在我意识到我的程序集一直都是正确的),而且对于管理安装错误的版本来说真的很愚蠢! – Justin 2011-05-07 06:13:24

0

嗯...... 'H' 是0x48。也许你在拉取'Hello World'的第一个字节而不是地址。

+0

什么会将半字节翻转为0x84? – 2011-05-06 16:11:41

+0

我也在想 - 除了那个值将是0x4800,而不是0x8400。另外 - 这是一个16位移动。 – Aaron 2011-05-06 16:13:25

+0

我想知道这一点,所以试图改变字符串开始与另一个字符,但我得到了相同的价值,所以得出结论,这只是一个巧合。 – Justin 2011-05-06 16:16:52

2

除非您使用bin格式,否则允许nasm将您的数据移动到segment .data这在编译为PE格式(如.EXE)时非常有用。

换句话说,你确定0x8400是不是正确的地址,一旦输出二进制已经布局和链接?我知道您正在尝试发出segment .text中的数据 - 为此,我认为您需要bin指令。

编辑:

既然你使用的是bin格式,并考虑您的附加信息,建立了HelloWorld字符串中segment .data不工作,我怀疑你需要做的是:

lea si, [cs:HelloWorld] 

我可能会忽略语法 - 我已经使用16位x86编码已经有好几年了 - 但重要的是,您正在根据关于ds的值的假设得到一个抵消值,您明确要清除这个值,以及汇编器可能会假设其值为segment .code或类似的。 (感谢阿龙纠正我的MOV的执法机关。)

+0

所以我使用'-f bin',同时'0x7C08'是我调试时字符串的实际地址。 – Justin 2011-05-06 16:25:49

+0

我认为语法是'mov si,[cs:HelloWorld]',但是NASM只产生'mov si,[ds:0x8400]',我仍然不明白。 – Justin 2011-05-07 05:36:29

+0

@Kragen - 我相信最后一条语句将地址'[cs:HelloWorld]'中的数据移动到si中 - 而不是地址。要移动你需要的地址'lea si,[cs:HelloWorld]''。但我不相信这实际上是你想要的。 – Aaron 2011-05-07 05:48:44

1

MASM帮助:

包含代码 应该启动它的代码段与 线像RESB 100h的第一目标文件。这是为了 确保代码开始于偏移相对于 代码段的开始 100H,使得接头或 转换器程序没有生成.COM文件时 调整 文件内地址的引用。 其他装配使用ORG指令 为了这个目的,但是ORG在NASM是 特定格式的指令到bin 输出格式,因为它在 MASM兼容汇编确实并不意味着 同样的事情。

因此,你有代码段CS和数据段DS,它们不相等,因此标签指针也不同,取决于节。 在x86下,段对齐通常是4096字节,它适合内存页的大小。

+0

但它们没有被0x100关闭,它们被0x800关闭 - 这是一个虚拟机页面(4096字节),让我想知道他的@data是否等于他的@text减去0x800--给PE或MZ头在EXE上。 – 2011-05-06 19:10:49

+0

不,不要在程序启动之前先启动手动DS和SC(SS也)段寄存器。正确的CS和DS值写入程序头表中。 CS和DS之间的内存空间是在编译时定义的(通常至少有一个内存页)。因此,你必须使用节.text,.data和.bss – 2011-05-06 19:28:10

+0

这是一个引导程序,所以没有程序头表。 – Justin 2011-05-07 05:00:52