assembly - x86 实模式函数调用未执行
问题描述
我有一些 x86 实模式汇编代码,其行为与预期不完全一致。我相信这个问题与错误计算的 jmp/call 偏移有关,但我可能弄错了。
这是汇编语言代码:
[org 0x7c00]
mov ah, 0x0e
mov al, 'h'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
mov al, 'l'
int 0x10
mov al, 'o'
int 0x10
mov al, '!'
;int 0x10
call print_char
;loop:
; jmp loop
mov si, mystring
call print_string
jmp $
; fill to 512 bytes
times 510 - ($ - $$) db 0
dw 0xAA55
; the address is stored in si
print_string:
pusha
; load character from si
mov al, [si]
cmp al, 0x00
jz print_string_end
call print_char ; print the char using the print_char function
inc si ; increment the string printing index si
print_string_end:
popa
ret
; print function: print a single character
; the character is stored in al
print_char:
pusha
mov ah, 0x0e
int 0x16
popa ; don't know what registers int 0x16 modifies
ret
mystring:
db "loading operating system",0x00
这是反汇编:objdump -D -b binary -m i8086 -M intel bootsector.bin
bootsector.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: b4 0e mov ah,0xe
2: b0 68 mov al,0x68
4: cd 10 int 0x10
6: b0 65 mov al,0x65
8: cd 10 int 0x10
a: b0 6c mov al,0x6c
c: cd 10 int 0x10
e: b0 6c mov al,0x6c
10: cd 10 int 0x10
12: b0 6f mov al,0x6f
14: cd 10 int 0x10
16: b0 21 mov al,0x21
18: e8 f2 01 call 0x20d
1b: be 14 7e mov si,0x7e14
1e: e8 df 01 call 0x200
21: eb fe jmp 0x21
...
1fb: 00 00 add BYTE PTR [bx+si],al
1fd: 00 55 aa add BYTE PTR [di-0x56],dl
200: 60 pusha
201: 8a 04 mov al,BYTE PTR [si]
203: 3c 00 cmp al,0x0
205: 74 04 je 0x20b
207: e8 03 00 call 0x20d
20a: 46 inc si
20b: 61 popa
20c: c3 ret
20d: 60 pusha
20e: b4 0e mov ah,0xe
210: cd 16 int 0x16
212: 61 popa
213: c3 ret
214: 6c ins BYTE PTR es:[di],dx
215: 6f outs dx,WORD PTR ds:[si]
216: 61 popa
217: 64 69 6e 67 20 6f imul bp,WORD PTR fs:[bp+0x67],0x6f20
21d: 70 65 jo 0x284
21f: 72 61 jb 0x282
221: 74 69 je 0x28c
223: 6e outs dx,BYTE PTR ds:[si]
224: 67 20 73 79 and BYTE PTR [ebx+0x79],dh
228: 73 74 jae 0x29e
22a: 65 6d gs ins WORD PTR es:[di],dx
...
该文件是用nasm bootsector.asm -f bin -o bootsector.bin
网上1e
有说明call 0x200
。除非我误解,否则这会将当前(指令指针 + 1)推入堆栈,并跳转以执行 offset 处的代码0x200
。这是内存中原点下方的某个位置,即0x7c00
,因此它似乎是与函数print_char
所在的地址不同的地址。
至少我认为这是正在发生的事情,但我可能完全错了,因为我是新手。
另外-也许我不允许将超过 512 字节的文件作为引导扇区?
解决方案
(这可能会帮助您记住,英特尔汇编代码可以为一个汇编助记符使用多个操作码。因此需要注意几种不同版本的“调用”)
在偏移量 +1e 处反汇编的“调用 0x200”被编码为 e8 df 01,CPU 将作为对下一条指令 +01df 的相对调用执行。
因为反汇编默认从偏移量 +0 开始,反汇编为 21+1df (=0200),或十进制的 512。请记住, print_string 是在 512 字节引导扇区之后立即组装的,因此相加。
如果您的代码在 0000:7c00 加载,则相对调用将转到 0000:7e00,这是正确计算的,但正如其他人所说,代码不会在那里,因为它不会被 BIOS 加载,它只会加载第一个部门。
我前段时间做了一个引导扇区,我的建议是 a) 很容易耗尽空间,所以使用紧凑的代码 b) 不要假设 CS:IP 以外的任何东西都指向你的代码。如果您依赖 DS、ES、SS,您可能会发现它们由不同的 BIOS 和模拟器设置不同,因此请尝试靠近顶部的“mov ax,cs”和“mov ds,ax”等,以确保安全。
您的代码使用“mov al,[si]”来加载字符串数据。si 默认与 ds 配对,因此它从 ds:[si] 加载。因此,您的意外输出可能是因为 ds:[si] 指向错误的数据。如果您设置了 Bochs,您将能够找到答案。
推荐阅读
- flutter - 在页面上保持键盘打开并禁用每个关闭选项
- algorithm - 获取满足所有键的最少值
- laravel - Laravel 中的自定义多态类型
- java - 如何在鼠标移动创建的矩形上使用工具提示 - Java
- python - 运行假设时如何退出 pdb 调试?
- c# - 当同时撰写多封电子邮件时,Outlook 不会触发 AttachmentAdd 事件,但一封电子邮件除外
- json - 如何在 json 文件中使用变量?
- react-native - React Native webview with login facebook总是在发布模式下重定向到另一个url(仅限android)
- amazon-web-services - 如何从 AWS VPC 中的私有子网连接到 Internet?
- python - 如何在数据框列 pandas 中找到最接近所选数字的 5 个数字的索引?