【问题标题】:Can't get 16 bit assembly program to jump to 0x1000:0x0000无法让 16 位汇编程序跳转到 0x1000:0x0000
【发布时间】:2012-06-22 22:19:42
【问题描述】:

我知道我成功地使用int 13h 将代码写入该地址,因为我可以在该内存位置看到它。我不能做的就是跳到那里。

我将0x1000(那里三个零)放入es0x0000 放入bx,我知道[es:bx] 表示由(es * 0x10) + bx 计算的地址,它等于0x10000(那里四个零)。但是指令指针eip 永远不会去那里。

我已经尝试过jmp [es:bx]jmp 0x1000:0x0000 以及NASM 甚至不接受的许多其他排列。

我目前的引导加载程序(仍然无法工作)是here。我在 Qemu 中启动它并在 0x10000 的前 50 个字节上做了一个 memsave,通过调整打开它,并在那里看到了我的“内核”代码(简单。但 EIP 仍然拒绝成为 0x10000,或者到达它然后挂在我想要的地方,这就是我的意思)。全图情况here

【问题讨论】:

  • 编辑我的错,你提供了代码。
  • 在 16 位程序中设置 EIP 会很困难,这是一个 32 位寄存器。跳转后IP的值为0。
  • @Pete - jmp [es:bx] 将间接跳转到存储在[es:bx] 的地址。但是,jmp seg:offsetjmp far seg:offset 应该可以工作。而且,就像 Hans 所说,在 0x1000:0 处,您将拥有 CS=0x1000IP=0

标签: assembly x86 x86-16 bootloader


【解决方案1】:

远跳转不能只为段使用内存位置。您可以通过以下几种方式做到这一点:

1) 段和偏移量的简单硬编码地址。

jmp 0x1000:0

2) 使用完整地址的间接跳转:

entry dw 0x0000 ; offset
      dw 0x1000 ; segment

jmp far dword ptr [entry] ; far jump (syntax might differ)

3) 远去

push SYSADDR ; segment
push 0       ; offset
retf         ; far return

在 DOS 时代使用的一个常见技巧是修补指令:

  mov ax, SYSADDR
  mov word ptr [myjump+3], ax
myjump:
  jmp 0x0000:0x0000

或将其中的一部分用作变量:

myjump:
  db 0xEA           ; far jmp opcode 
  dw 0x0000         ; offset part
  SYSADDR dw 0x1000 ; segment part

免责声明:以上所有内容均来自记忆,我可能弄错了某些部分(例如,段/偏移的顺序非常混乱)。

【讨论】:

  • 固定代码。段在高地址。您的免责声明是正确的!
  • 像第四个示例中那样修补指令在较旧的 DOS 时代 CPU 上无法可靠地工作,因为当您尝试修改 JMP 指令时,它可能位于预取缓冲区中。您需要在修改和正在修改的指令之间放置一条控制转移指令以清除预取队列。例如。 mov word ptr [myjump+3], axjmp myjump
【解决方案2】:

你应该能够做你正在尝试的事情。这是一个做同样事情的例子,大概是出于同样的原因:

; http://www.free2code.net/tutorials/view/writing_your_own_operating_system-12/page1.html
...
mov bx,0x1000  ;Es and Bx put together are where to load the program too 
               ; (see jmp x1000:0x00)
mov es,bx
mov bx,0x00
int 13h        ;Int 13 is all functions for disks
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 2011-12-08
    • 2021-03-27
    相关资源
    最近更新 更多