程序集 (x86):<label> db 'string',0 除非有跳转指令,否则不会执行
Assembly (x86): <label> db 'string',0 does not get executed unless there's a jump instruction
我一直在用头撞墙试图理解为什么下面的程序集没有正确地转储 'HELLO_WORLD'.[=18 的内容=]
; Explicitly set 16-bit
[ BITS 16 ]
[ ORG 0x7C00 ]
; Create label for hello world string terminated by null.
HELLO_WORLD db 'hello world', 0
start:
; Move address of HELLO_WORLD into si
mov SI, HELLO_WORLD
call print_string
; Continue until the end of time
jmp $
print_string:
loop:
; Retrieve value stored in address at si
mov al, [SI]
mov ah, 0x0E
cmp al, 0
; Finish execution after hitting null terminator
je return
INT 0x10
; Increment contents of si (address)
inc SI
jmp loop
return:
ret
; boot loader length *must* be 512 bytes.
times 510-($-$$) db 0
dw 0xAA55
最后我发现,如果我们不执行(使其不编码)标签,那么它就可以正常工作。
jmp start
HELLO_WORLD db 'hello world',0
我觉得最令人困惑的部分,查看十六进制转储,HELLO_WORLD 仍然在二进制文件中(在开头 - 并且似乎没有区分其类型)。
猫nojmp_boot.out
00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 00 be 00 7c e8 |hello world...|.|
00000010 02 00 eb fe 8a 04 b4 0e 3c 00 74 05 cd 10 46 eb |........<.t...F.|
00000020 f3 c3 eb e8 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200
猫jmpboot.out
00000000 eb 22 68 65 6c 6c 6f 20 77 6f 72 6c 64 00 be 02 |."hello world...|
00000010 7c e8 02 00 eb fe 8a 04 b4 0e 3c 00 74 05 cd 10 ||.........<.t...|
00000020 46 eb f3 c3 eb e8 00 00 00 00 00 00 00 00 00 00 |F...............|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200
检查前两个字节,我们可以看到 'e8 22' 是到地址 22 (http://net.cs.uni-bonn.de/fileadmin/user_upload/plohmann/x86_opcode_structure_and_instruction_overview.pdf) 的短跳转。
我的问题是:
为什么我们不能'HELLO_WORLD'作为程序执行的一部分,就我而言,代码和数据之间没有区别?
我正在使用以下进行编译:
nasm -f bin -o boot.bin boot.asm && if [ $(stat -c "%s" boot.bin) -ne 512 ]; then x; fi && qemu-system-x86_64 boot.bin
执行从顶部开始。如果省略 jmp start
,则字符 h 将被 CPU 解释为一条指令。你看这样肯定不对吧?
as far I was concerned, there was no distinction between code and data?
当我们考虑它们在二进制文件中的位置时,代码和数据之间没有区别。但是代码和数据仍然是两个完全不同的项目。代码是唯一可以被 CPU.
执行 的代码
由于您正在创建引导扇区,所以执行从生成文件的第一个字节开始。它不会从开始标签或其他任何地方开始。由于字符串 "hello world" 位于文件的开头,因此这些字节首先被执行。这些字节被 CPU 解释为指令,而不是字符,并且它们被执行为它们被解码为的任何指令。
以下是执行的指令:
7c00: 68 65 6c push 0x6c65
7c03: 6c ins BYTE PTR es:[di],dx
7c04: 6f outs dx,WORD PTR ds:[si]
7c05: 20 77 6f and BYTE PTR [bx+0x6f],dh
7c08: 72 6c jb 0x7c76
7c0a: 64 00 be 00 7c add BYTE PTR fs:[bp+0x7c00],bh
7c0f: e8 02 00 call 0x7c14
7c12: eb fe jmp 0x7c12
7c14: 8a 04 mov al,BYTE PTR [si]
...
我一直在用头撞墙试图理解为什么下面的程序集没有正确地转储 'HELLO_WORLD'.[=18 的内容=]
; Explicitly set 16-bit
[ BITS 16 ]
[ ORG 0x7C00 ]
; Create label for hello world string terminated by null.
HELLO_WORLD db 'hello world', 0
start:
; Move address of HELLO_WORLD into si
mov SI, HELLO_WORLD
call print_string
; Continue until the end of time
jmp $
print_string:
loop:
; Retrieve value stored in address at si
mov al, [SI]
mov ah, 0x0E
cmp al, 0
; Finish execution after hitting null terminator
je return
INT 0x10
; Increment contents of si (address)
inc SI
jmp loop
return:
ret
; boot loader length *must* be 512 bytes.
times 510-($-$$) db 0
dw 0xAA55
最后我发现,如果我们不执行(使其不编码)标签,那么它就可以正常工作。
jmp start
HELLO_WORLD db 'hello world',0
我觉得最令人困惑的部分,查看十六进制转储,HELLO_WORLD 仍然在二进制文件中(在开头 - 并且似乎没有区分其类型)。
猫nojmp_boot.out
00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 00 be 00 7c e8 |hello world...|.|
00000010 02 00 eb fe 8a 04 b4 0e 3c 00 74 05 cd 10 46 eb |........<.t...F.|
00000020 f3 c3 eb e8 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200
猫jmpboot.out
00000000 eb 22 68 65 6c 6c 6f 20 77 6f 72 6c 64 00 be 02 |."hello world...|
00000010 7c e8 02 00 eb fe 8a 04 b4 0e 3c 00 74 05 cd 10 ||.........<.t...|
00000020 46 eb f3 c3 eb e8 00 00 00 00 00 00 00 00 00 00 |F...............|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200
检查前两个字节,我们可以看到 'e8 22' 是到地址 22 (http://net.cs.uni-bonn.de/fileadmin/user_upload/plohmann/x86_opcode_structure_and_instruction_overview.pdf) 的短跳转。
我的问题是:
为什么我们不能'HELLO_WORLD'作为程序执行的一部分,就我而言,代码和数据之间没有区别?
我正在使用以下进行编译:
nasm -f bin -o boot.bin boot.asm && if [ $(stat -c "%s" boot.bin) -ne 512 ]; then x; fi && qemu-system-x86_64 boot.bin
执行从顶部开始。如果省略 jmp start
,则字符 h 将被 CPU 解释为一条指令。你看这样肯定不对吧?
as far I was concerned, there was no distinction between code and data?
当我们考虑它们在二进制文件中的位置时,代码和数据之间没有区别。但是代码和数据仍然是两个完全不同的项目。代码是唯一可以被 CPU.
执行 的代码由于您正在创建引导扇区,所以执行从生成文件的第一个字节开始。它不会从开始标签或其他任何地方开始。由于字符串 "hello world" 位于文件的开头,因此这些字节首先被执行。这些字节被 CPU 解释为指令,而不是字符,并且它们被执行为它们被解码为的任何指令。
以下是执行的指令:
7c00: 68 65 6c push 0x6c65
7c03: 6c ins BYTE PTR es:[di],dx
7c04: 6f outs dx,WORD PTR ds:[si]
7c05: 20 77 6f and BYTE PTR [bx+0x6f],dh
7c08: 72 6c jb 0x7c76
7c0a: 64 00 be 00 7c add BYTE PTR fs:[bp+0x7c00],bh
7c0f: e8 02 00 call 0x7c14
7c12: eb fe jmp 0x7c12
7c14: 8a 04 mov al,BYTE PTR [si]
...