【问题标题】:How can I JMP to relocated code in my MBR?如何 JMP 到 MBR 中的重定位代码?
【发布时间】:2016-09-15 10:26:58
【问题描述】:

我正在尝试编写一个极其简单的 MBR,以开始学习如何编写 MBR/内核。这就是我到目前为止所拥有的(从其他 MBR 的片段创建)。我使用 nasm 然后 ld 链接得到的二进制文件与仅使用 nasm 进行链接有点不同,但这似乎不是问题。

我最初是从jmp 0:continue 开始,但它似乎跳到0000:7c22(或单独使用nasm 的001d...我相信我没有指定它从7c00 开始)但我想跳到@ 987654325@或:7a1d,重定位代码的地址。我尝试只使用jmp continue,然后如下面未注释的那样,将堆栈指针添加到 continue 指针,将其推送并 ret。当 dd'ed 到我的第一个扇区时,我得到的只是一个闪烁的光标。任何帮助表示赞赏。

                            ; nasm+ld       nasm            comment
global _start
_start:
    xor    cx, cx           ; 6631c9        31c9            Set segment registers to zero
    mov    es, cx           ; 8ec1          8ec1
    mov    ds, cx           ; 8ed9          8ed9
    mov    ss, cx           ; 8ed1          8ed1
    mov    sp, 0x7A00       ; 66bc007a      bc007a          Stack
    mov    di, sp           ; 6689e7        89e7            Bottom of relocation point
    mov    esi, _start      ; be007c0000    66be00000000
    cld                     ; fc            fc
    mov    ch, 1            ; b501          b501            cx = 256
    rep movsw               ; f366a5        f3a5            Copy self to 0:7A00

;----------------------------------------------------------------------------------------------------------------------
    xor    eax,eax
    mov    ax, sp
    add    ax, continue

    ;jmp    0:continue      ; ea227c00000000    ea1d000000      near JMP to copy of self
                            ; or
    ;jmp    continue        ; (eb00)
    push eax
    ret
;----------------------------------------------------------------------------------------------------------------------

continue:
    sti                     ; fb            fb

ERROR:
    mov esi, errormsg       ; be3b7c0000 (be36) 66be36000000        Error Message loc
    mov ah, 0x0E            ; b40e          b40e
    mov bx, 7               ; 66bb          bb0700
disp:
    lodsb                   ; ac            ac
    cmp ah, 0x00            ; 80fc00        80fc00
    je end                  ; 7404          7404
    int 10h                 ; cd10          cd10
    jmp disp                ; ebf6          ebf6

end:
    nop                     ; 90            90
    jmp end                 ; ebfd          ebfd            infinte loop

errormsg db 10,'YOU MESSED UP.',13,0

times (0x1b8 - ($-$$)) nop  ; 90            90          Padding

UID db 0xf5,0xbf,0x0f,0x18                                         ;Unique Disk ID

BLANK times 2 db 0

PT1 db 0x80,0x20,0x21,0x00,0x0C,0x50,0x7F,0x01,0x00,0x08,0x00,0x00,0xb0,0x43,0xF9,0x0D ;First Partition Entry
PT2 times 16 db 0                                      ;Second Partition Entry
PT3 times 16 db 0                                      ;Third Partition Entry
PT4 times 16 db 0                                      ;Fourth Partition Entry

BOOTSIG dw 0xAA55                                      ;Boot Signature[/code]

【问题讨论】:

  • 看起来您的链接器正在生成 32 位代码,这对于引导扇区是错误的。 (虽然我从来没有听说过ld 实际上在说明之前插入大小前缀......整个事情看起来很奇怪)。您用来组装和链接的实际命令是什么?你如何在这两种情况下转储结果?
  • @davmac 链接器没有这样做。是 NASM。他需要一个BITS 16 指令来明确说明。
  • @RossRidge 好的,但他的 cmets 中“nasm”列中的操作码看起来像正确的 16 位代码。当然,我不知道他实际上是从哪里得到的。
  • @davmac NASM 根据使用的对象格式为 BITS 选择默认值。 elf 默认为 32,bin 默认为 16。
  • @Willdorf 您可以使用 32 位指令,但代码必须在 16 位模式下生成。 (将根据需要生成带有操作数大小前缀的 32 位指令)。您现在看到的是不应该出现的操作数大小前缀 (66h)。 (处理器可以处于 16 位或 32 位模式;在任何一种模式下,66h 前缀都会切换到备用操作数大小。引导扇区将以 16 位模式执行)。

标签: assembly x86 nasm bootloader osdev


【解决方案1】:

另一种重定位 MBR/引导加载程序的替代方法,它不涉及链接描述文件,但允许 ALL引导加载程序中的代码和数据被重定位到段:偏移对 = 段:0x0000 的任何位置.这并不限制引导加载程序在 64kb 内存中被复制。这涉及使用一些段数学和对代码进行一些小的改动。我将使用您的原始代码进行一些清理以及我在第一个答案中添加的说明,该说明在 JMP 之前打印一个字符串。

请记住,在 x86 real mode segmentation 中,物理地址由段寄存器的内容和偏移量决定。计算如下:

Physical address = (segment << 4) + offset

在引导加载程序的情况下,许多人将 0x0000 放入 DSES,您在代码中就是这样做的。您的原始代码使用了ORG 0x7c00(实际上是偏移量)。当您获取段和偏移量并计算您获得的物理地址时:

Physical address = (0x0000 << 4) + 0x7c00 = 0x07c00

0x07c00 是 BIOS 放置在内存中的引导加载程序的物理地址。但是,通常有不止一种方法可以将单个物理地址表示为段:偏移量对。

例如,如果我们使用 0x07c0 的段和 0x0000 的 ORG(offset),我们会发现等式产生:

Physical address = (0x07c0 << 4) + 0x0000 = 0x07c00

如果将原始段寄存器设置为 0x07c0 并在引导加载程序中使用 ORG 0x0000 指令会怎样。那行得通吗?是的,它会的。链接器和 NASM 真的不知道用户如何设置段寄存器。当 NASM 创建对 NEAR 绝对地址的引用时,它假定这些段将由开发人员在运行时适当地设置。

如果我们使用ORG 0x0000,那么要从 0x7c00 复制到 0x7a00,我们可以将 0x07c0 放入 DS 并将 SI 放入 0 (0x07c0:0x0000)。我们可以将 ES 设置为 0x07a0 并将 DI 设置为 0 (0x07a0:0x0000)。 CX 将设置为 256(我们将复制单词)。这会将 512 字节的内存从物理地址 0x07c00 复制到 0x07a00。复制整个引导加载程序后,我们使用 FAR JMPCS 设置为跳转中指定的段,并将指令指针 (IP) 设置为标签的偏移量。

一旦我们跳转到复制引导加载程序的内存(从物理地址 0x7a00 开始的区域),我们就会相应地设置段寄存器。所以在我们的例子中,我们会在跳转到 0x07a0 之后设置寄存器 DSES。这应该允许所有引导加载程序代码和数据在新位置按预期运行。

以下是与上面建议的类似的代码:

BITS 16
ORG 0x0000

global _start
_start:
    xor    bp, bp           
    mov    ss, bp           ; Set SS segment register to zero
    mov    sp, 0x7A00       ; Set stack to SS:SP=0x0000:0x7A00
    mov    dx, 0x07C0
    mov    ds, dx           ; DS = 0x07C0 - Segment:Offset = 0x07c0:0x0000 = 0x07C00
    sub    dx, 0x20         ; DX = 0x07C0-0x20=0x07A0
    mov    es, dx           ; ES = 0x07A0 - Segment:Offset = 0x07a0:0x0000 = 0x07A00
    cld

    ; Print message before the copy
    mov si, copymsg         ; Copy message (DS:[copymsg])
    call outputstr

    ; Copy 256 words of memory from 0x07c00 to 0x07a00
    mov    di, bp           ; Destination is ES:DI = 0x07a0:0x0000 = 0x07a00
    mov    si, bp           ; Source is DS:SI = 0x07c0:0x0000 = 0x07c00
    mov    cx, 256          ; CX = 256 words to copy
    rep movsw               ; Copy self to destination

    jmp    0x07A0:rel_entry
                            ; far JMP jumps to phys address 0x07a00, sets
                            ; CS = 0x07A0 and IP = rel_entry.

rel_entry:
    sti                     ; Enable interrupts
    mov    ds, dx           ; DS=ES=0x07A0
                            ; ES already 0x07A0 before the jump, no need to set again
.success:
    ; Print the "Success!" message
    mov si, successmsg      ; Success Message location (DS:[successmsg])
    call outputstr

    cli                     ; Disable interrupts
.end:
    hlt                     ; CPU hlt
    jmp .end                ; infinite loop

; Function: outputstr
; Inputs:
;    SI = address of string
; Outputs:
;    None
; Registers destroyed:
;    AX, BX, SI
;
outputstr:
    mov ah, 0x0E            ; 0E TTY Output
    mov bx, 7               ; Page number
.disp:
    lodsb                   ; Load next char from DS:[SI], SI+=2
    test al, al             ; Compare to zero
    je .end                 ; If so, end
    int 0x10                ; Display char
    jmp .disp               ; Loop
.end:
    ret

successmsg db 10,'Success!',13,0
copymsg db 10,'Before copy!',13,0

times (0x1b8 - ($-$$)) db 0x00 ; Padding

UID     db 0xf5,0xbf,0x0f,0x18 ; Unique Disk ID
BLANK   times 2 db 0
PT1     db 0x80,0x20,0x21,0x00,0x0C,0x50,0x7F,0x01
PT1more db 0x00,0x08,0x00,0x00,0xb0,0x43,0xF9,0x0D
PT2     times 16 db 0
PT3     times 16 db 0
PT4     times 16 db 0

BOOTSIG dw 0xAA55              ;Boot Signature

此引导加载程序调用函数outputstr 以在复制之前的代码中以及跳转到重新定位的代码之后向控制台显示消息。这是有效的,因为在这两种情况下,所有标签仍然处于相同的偏移量,只有段发生了变化。

上面的引导加载程序可以使用如下命令组装:

nasm -f bin boot.bin boot.asm

【讨论】:

    【解决方案2】:

    正如您所发现的,您可以将整个引导加载程序的原点设置为 ORG 0x7A00。这工作得很好。将引导扇区复制到 0x7A00 的代码不依赖于任何绝对标签,仅依赖于相对标签。这个答案更像是一个思想实验和一种不同的处理方式。

    如果我们想在复制之前显示一个字符串作为示例,会发生什么?有哪些可能的选择?

    1. NASM 允许 BIN 格式 (-f bin) 具有采用 virtual starting point(起点)和物理地址(起点)的部分。这种方法对于引导加载程序的布局方式过于严格。
    2. 使用LD linker script 定义引导加载程序的布局。
    3. 重组代码以使用 0x0000 的 ORG(原点)并相应地设置段寄存器。关于这个问题,请参阅我的 other answer

    此答案侧重于选项 2。解释 LD 链接器脚本的工作原理对于 Stackoverflow 来说过于宽泛。 LD manual 是最好的信息来源,它确实有例子。这个想法是我们允许引导加载程序在链接描述文件中布局。我们可以设置LMA(加载内存地址)来指定段将被加载到内存中的内存地址。 VMA 是一个部分的起点。一个部分中的所有标签和地址都将相对于其 VMA 进行解析。

    我们可以方便地使用具有特定 LMA 的部分将引导签名直接放入输出文件中,而不是在汇编代码中指定它。我们还可以从链接描述文件中定义符号,这些符号可以使用 NASM extern 指令从汇编代码中访问。

    所有这一切的一个优点是您可以在汇编代码中按您想要的任何顺序定义部分,并且链接描述文件将重新排序。您还可以将多个目标文件链接在一起。应该首先列出包含要首先出现的引导代码的目标文件。

    此链接器脚本的布局大致如下:

    Non-relocatable portion of boot code (boot.text) Relative to an origin of 0x7c00
    Non-relocatable portion of boot data (boot.data)
    --------------------------------------- Word aligned
    Relocatable portion of boot code (rel.text) - Relative to an origin of 0x7a00
    Relocatable portion of boot data (rel.data)
    Relocatable portion of partition data at offset 0x1b8 (partition.data)
    ---------------------------------------
    Boot signature at offset 0x1fe
    

    用于布局此引导加载程序的链接描述文件可能如下所示:

    ENTRY(_start);
    OUTPUT(elf_i386);
    
    SECTIONS
    {
        /* Set the base of the main bootloader offsets */
        _bootbase = 0x7c00; /* Where bootloader initially is loaded in memory */
        _relbase  = 0x7a00; /* Address entire bootsector will be copied to
                               This linker script expects it to be word aligned */
        _partoffset = 0x1b8; /* Offset of UID and Partition data */
        _sigoffset  = 0x1fe; /* Offset of the boot signature word */
    
    
        /* SUBALIGN(n) in an output section will override the alignment
         * of any input section that is encontered */
    
        /* This is the boot loader code and data that is expected to run from 0x7c00 */
        .bootinit _bootbase : SUBALIGN(2)
        {
            *(boot.text);
            *(boot.data);
        }
    
        /* Note that referencing any data in the partition table will
         * only be usable from the code that is in the .bootrel section */
    
        /* Partition data */
        .partdata _relbase + _partoffset :
            AT(_bootbase + _partoffset) SUBALIGN(0)
        {
            *(partition.data);
        }
    
        /* Boot signature */
        .bootsig :
            AT(_bootbase + _sigoffset) SUBALIGN(0)
        {
            SHORT(0xaa55);
        }
        /* Length of region to copy in 16-bit words */
        _rel_length = 256;
        /* Address to copy to */
        _rel_start = _relbase; /* Word aligned start address */
    
        /* Code and data that will expect to run once relocated
         * is placed in this section. Aligned to word boundary.
         * This relocateable code and data will be placed right
         * after the .bootinit section in the output file */
        .bootrel _relbase + SIZEOF(.bootinit) :
            AT(_bootbase + SIZEOF(.bootinit)) SUBALIGN(2)
        {
            *(rel.text);
            *(rel.data);
        }
    }
    

    使用此链接描述文件和其中定义的符号的代码的修订副本可能如下所示:

    BITS 16
    
    extern _bootbase
    extern _relbase
    extern _rel_length
    extern _rel_start
    
    section boot.text
                                ; comment
    global _start
    _start:
        xor    cx, cx           ; Set segment registers to zero
        mov    es, cx
        mov    ds, cx
        mov    ss, cx
        mov    sp, 0x7A00       ; Stack
        cld
    
    .copymsg:
        mov si, copymsg         ; Copy message
        mov ah, 0x0E            ; 0E TTY Output
        mov bx, 7               ; Page number
    .dispcopy:
        lodsb                   ; Load next char
        test al, al             ; Compare to zero
        jz .end                 ; If so, end
        int 10h                 ; Display char
        jmp .dispcopy           ; Loop
    .end:
        mov    di, _rel_start   ; Beginning of relocation point
        mov    si, _bootbase    ; Original location to copy from
        mov    cx, _rel_length  ; CX = words to copy
        rep movsw               ; Copy self to destination
    
        jmp    0:rel_entry      ; far JMP to copy of self
    
    section rel.text
    rel_entry:
        sti                     ; Enable interrupts
    
        mov si, successmsg      ; Error Message location
        mov ah, 0x0E            ; 0E TTY Output
        mov bx, 7               ; Page number
    .disp:
        lodsb                   ; Load next char
        test al, al             ; Compare to zero
        je .end                 ; If so, end
        int 10h                 ; Display char
        jmp .disp               ; Loop
    
        cli                     ; Disable interrupts
    .end:
        hlt                     ; CPU hlt
        jmp .end                ; infinte loop
    
    section rel.data
    successmsg db 10,'Success!',13,0
    
    section boot.data
    copymsg db 10,'Before copy!',13,0
    
    section partition.data
    UID db 0xf5,0xbf,0x0f,0x18  ;Unique Disk ID
    
    BLANK times 2 db 0
    
    PT1 db 0x80,0x20,0x21,0x00,0x0C,0x50,0x7F,0x01
        db 0x00,0x08,0x00,0x00,0xb0,0x43,0xF9,0x0D
    PT2 times 16 db 0
    PT3 times 16 db 0
    PT4 times 16 db 0
    

    作为确保boot.text 部分中的代码可以访问boot.data 中的数据的实验,我在复制之前显示了一个字符串。然后我对重新定位的代码执行 FAR JMP。重定位的代码显示一个成功字符串。

    我将代码修改为不使用像 ESI 这样的 32 位寄存器,因为您将在实模式下执行此代码。我还修改了你的无限循环以使用HLT 指令。

    可以将代码和链接器脚本修改为仅从重定位数据的开头复制到第 512 个字节,但这超出了此答案的范围。


    看看反汇编

    下面提供了原点为 0x7c00 的 .bootinit 部分。这是该部分的 OBJDUMP sn-p(为简洁起见,没有数据):

    Disassembly of section .bootinit:
    
    00007c00 <_start>:
        7c00:       31 c9                   xor    cx,cx
        7c02:       8e c1                   mov    es,cx
        7c04:       8e d9                   mov    ds,cx
        7c06:       8e d1                   mov    ss,cx
        7c08:       bc 00 7a                mov    sp,0x7a00
        7c0b:       fc                      cld
    
    00007c0c <_start.copymsg>:
        7c0c:       be 2e 7c                mov    si,0x7c2e
        7c0f:       b4 0e                   mov    ah,0xe
        7c11:       bb 07 00                mov    bx,0x7
    
    00007c14 <_start.dispcopy>:
        7c14:       ac                      lods   al,BYTE PTR ds:[si]
        7c15:       84 c0                   test   al,al
        7c17:       74 04                   je     7c1d <_start.end>
        7c19:       cd 10                   int    0x10
        7c1b:       eb f7                   jmp    7c14 <_start.dispcopy>
    
    00007c1d <_start.end>:
        7c1d:       bf 00 7a                mov    di,0x7a00
        7c20:       be 00 7c                mov    si,0x7c00
        7c23:       b9 00 01                mov    cx,0x100
        7c26:       f3 a5                   rep movs WORD PTR es:[di],WORD PTR ds:[si]
        7c28:       ea 3e 7a 00 00          jmp    0x0:0x7a3e
    

    左列上的所有 VMA 地址似乎都相对于原点 0x7c00 正确设置。 FAR JUMP (jmp 0x0:0x7a3e) 也跳到了所有东西都被重新定位(复制)的位置。 .bootrel 部分的类似缩写转储显示为:

    Disassembly of section .bootrel:
    
    00007a3d <rel_entry-0x1>:
            ...
    
    00007a3e <rel_entry>:
        7a3e:       fb                      sti
        7a3f:       be 54 7a                mov    si,0x7a54
        7a42:       b4 0e                   mov    ah,0xe
        7a44:       bb 07 00                mov    bx,0x7
    
    00007a47 <rel_entry.disp>:
        7a47:       ac                      lods   al,BYTE PTR ds:[si]
        7a48:       3c 00                   cmp    al,0x0
        7a4a:       74 05                   je     7a51 <rel_entry.end>
        7a4c:       cd 10                   int    0x10
        7a4e:       eb f7                   jmp    7a47 <rel_entry.disp>
        7a50:       fa                      cli
    
    00007a51 <rel_entry.end>:
        7a51:       f4                      hlt
        7a52:       eb fd                   jmp    7a51 <rel_entry.end>
    

    左列中的 VMA 相对于 0x7A00 的开头,这是正确的。指令mov si,0x7a54 是一个绝对近内存地址,它被正确编码以引用successmsg 地址(为简洁起见,我将数据剪掉了,所以它不会出现)。

    参赛作品:

    00007a3d <rel_entry-0x1>:
            ...
    

    是与将.bootrel 部分对齐到偶数字边界相关的信息。使用此链接描述文件rel_entry 将始终具有偶数地址。


    编译和链接这个引导加载程序

    最简单的方法是使用这些命令:

    nasm -f elf32 -o boot.o boot.asm
    ld -melf_i386 -Tlinker.ld -o boot.bin --oformat=binary boot.o
    

    需要指出的是,我们使用 ELF32 格式和 NASM,而不是 BINLD 然后用于创建二进制文件boot.bin,它应该是引导扇区的 512 字节映像。 linker.ld 是链接描述文件的名称。

    如果您希望能够方便地获取对象转储,那么您可以使用这些命令来组装和链接:

    nasm -f elf32 -o boot.o boot.asm
    ld -melf_i386 -Tlinker.ld -o boot.elf boot.o
    objcopy -O binary boot.elf boot.bin
    

    与第一种方法的不同之处在于我们不使用--oformat=binary 选项和LD。结果将是生成一个ELF32 图像并将其放置在输出文件boot.elf 中。我们不能直接使用boot.elf 作为我们的启动映像,所以我们使用OBJCOPYELF32 文件转换为一个名为boot.bin 的二进制文件。如果我们使用这样的命令来转储ELF文件的内容和反汇编,就可以看出这样做的用处:

    objdump boot.elf -Mintel -mi8086 -Dx
    
    • -D 选项是全部反汇编
    • -x 输出标题
    • -mi8086 反汇编为 16 位 8086 代码
    • -Mintel 反汇编应该是 INTEL 语法而不是默认的 ATT 语法

    【讨论】:

    • 感谢您提供了很多关于链接器脚本、编译和反汇编的有用信息!
    【解决方案3】:

    编译和链接使用:nasm -f bin -o mbr.bin mbr.asm

    [BITS 16]
    ORG 0x00007a00
                                ; opcodes       comment
    global _start
    _start:
        xor    cx, cx           ; 31c9          Set segment registers to zero
        mov    es, cx           ; 8ec1
        mov    ds, cx           ; 8ed9
        mov    ss, cx           ; 8ed1
        mov    sp, 0x7A00       ; bc007a        Stack
        mov    di, sp           ; 89e7          Bottom of relocation point
        mov    esi, 0x00007C00  ; 66be007c0000  Original location
        cld                     ; fc
        mov    ch, 1            ; b501          CX = 256
        rep movsw               ; f3a5          Copy self to 0:7A00
        jmp    0:continue       ; ea1d7a0000    near JMP to copy of self
    
    continue:
        sti                     ; fb
    
    ERROR:
        mov esi, errormsg       ; 66be357a0000  Error Message location
        mov ah, 0x0E            ; b40e          0E TTY Output
        mov bx, 7               ; bb0700        Page number
    disp:
        lodsb                   ; ac            Load next char
        cmp al, 0x00            ; 3c00          Compare to zero
        je end                  ; 7404          If so, end
        int 10h                 ; cd10          Display char
        jmp disp                ; ebf6          Loop
    
    end:
        nop                     ; 90            Do Nothing
        jmp end                 ; ebfd          infinte loop
    
    errormsg db 10,'YOU MESSED UP!',13,0
    
    times (0x1b8 - ($-$$)) nop  ; 90909090...   Padding
    
    UID db 0xf5,0xbf,0x0f,0x18  ;Unique Disk ID
    
    BLANK times 2 db 0
    
    PT1 db 0x80,0x20,0x21,0x00,0x0C,0x50,0x7F,0x01
    PT1more db 0x00,0x08,0x00,0x00,0xb0,0x43,0xF9,0x0D
    PT2 times 16 db 0
    PT3 times 16 db 0
    PT4 times 16 db 0
    
    BOOTSIG dw 0xAA55           ;Boot Signature
    

    hexdump -C mbr.bin的输出:

    00000000  31 c9 8e c1 8e d9 8e d1  bc 00 7a 89 e7 66 be 00  |1.........z..f..|
    00000010  7c 00 00 fc b5 01 f3 a5  ea 1d 7a 00 00 fb 66 be  ||.........z...f.|
    00000020  35 7a 00 00 b4 0e bb 07  00 ac 3c 00 74 04 cd 10  |5z........<.t...|
    00000030  eb f7 90 eb fd 0a 59 4f  55 20 4d 45 53 53 45 44  |......YOU MESSED|
    00000040  20 55 50 21 0d 00 90 90  90 90 90 90 90 90 90 90  | UP!............|
    00000050  90 90 90 90 90 90 90 90  90 90 90 90 90 90 90 90  |................|
    *
    000001b0  90 90 90 90 90 90 90 90  f5 bf 0f 18 00 00 80 20  |............... |
    000001c0  21 00 0c 50 7f 01 00 08  00 00 b0 43 f9 0d 00 00  |!..P.......C....|
    000001d0  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
    

    【讨论】:

    • 没有理由使用 ESI 而不是 SI,因为 16 位 MOVSW 和 LODSB 指令只使用 16 位 SI 寄存器。
    • 为什么将ORG 设置为0x7a00。这应该是0x7c00
    • @DavidHoelzer :他已将其设置为 0x7a00,因为执行复制的代码是可重定位的(此时组织是什么并不重要)。复制完成后,他的其余代码现在被复制到 0x7a00,因此它应该按预期运行。这是相当非正统的,但在这种情况下它应该可以工作。
    • @DavidHoelzer :关于他的 SP 。由于他已将引导加载程序的 512 个字节从 0x7c00 复制到 0x7a00,因此他似乎选择将堆栈放置在他复制的目标下方 - 这似乎是合理的。我猜他正在建造一个链式装载机。
    • 你说得对,@MichaelPetch - 老实说,我没有比奇怪的 ORG 和 SP 调整更进一步。
    猜你喜欢
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2023-04-02
    • 2016-03-18
    • 2012-04-06
    相关资源
    最近更新 更多