bootsect.s:我们如何在将代码本身移开后访问下一行?

bootsect.s: How com that we can access the next line after moving the code itself away?

本人是在线学习操作系统的新手,其中提到了bootsect.s: https://kernel.googlesource.com/pub/scm/linux/kernel/git/nico/archive/+/v0.99-pl8/boot/bootsect.S 但是这段代码对我来说很陌生:

        mov ax,#BOOTSEG
        mov ds,ax
        mov ax,#INITSEG
        mov es,ax
        mov cx,#256
        sub si,si
        sub di,di
        cld
        rep
        movsw
        jmpi    go,INITSEG

奇怪的是最后三行。按照我的理解,rep movsw已经把代码本身移走了,所以当pc指向jumpi,计算机要执行pc指向的代码时,应该会报错,因为代码jumpi go, INITSEG 已搬走。那么为什么这段代码仍然有效并且 jumpi go, INITSEG 仍然可以找到并执行?

来自

...but the pc is pointed to the section start with #BOOTSEG, where there is no code anymore. So I thought jumpi go,INITSEG will not execute.

放心,代码还在!

当 BIOS 在线性地址 00007C00h 加载引导扇区时,内存是这样填充的:

00007C00    mov ax,#BOOTSEG     ; 07C0h
00007C03    mov ds,ax
00007C05    mov ax,#INITSEG     ; 9000h
00007C08    mov es,ax
00007C0A    mov cx,#256
00007C0D    sub si,si
00007C0F    sub di,di
00007C11    cld
00007C12    rep movsw
00007C14    jmpi    go,INITSEG  ; Far jump (EAh, 19h, 00h, 00h, 90h)
00007C19    go:

一旦 rep movsw 指令完成其任务,00090000h 处的内存将包含在 00007C00h 处找到的 512 字节的精确 副本。虽然这段代码的作者说代码自己移走了,但这只是口头上的问题。它始终是创建的副本。源字节仍然存在,除非 DS:SIES:DI 的 2 个内存区域之间存在重叠,但这里不是这种情况。

因此,指令指针将位于 00007C14h 并执行远跳转(段间)到线性地址 00090019h,其中 go 标签所在。
从这一点开始,可以忽略 00007C00h 的 512 个字节。