Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何将JMP映射到MBR中重新定位的代码?_Assembly_X86_Nasm_Bootloader_Osdev - Fatal编程技术网

Assembly 如何将JMP映射到MBR中重新定位的代码?

Assembly 如何将JMP映射到MBR中重新定位的代码?,assembly,x86,nasm,bootloader,osdev,Assembly,X86,Nasm,Bootloader,Osdev,我正在尝试编写一个非常简单的MBR来开始学习如何编写MBR/内核。这就是我到目前为止所做的(从其他MBR的片段创建)。使用nasm和ld-to-link得到的二进制文件与仅使用nasm两者有点不同,但这似乎不是问题所在 我最初是从jmp 0:continue开始的,但它似乎跳转到0000:7c22(或001d仅用nasm…我相信我没有指定它从7c00)开始,但我希望跳转到:7a22或:7a1d,重新定位代码的地址。我尝试只使用jmp continue,然后如下面未注释所示,将堆栈指针添加到con

我正在尝试编写一个非常简单的MBR来开始学习如何编写MBR/内核。这就是我到目前为止所做的(从其他MBR的片段创建)。使用nasm和ld-to-link得到的二进制文件与仅使用nasm两者有点不同,但这似乎不是问题所在

我最初是从
jmp 0:continue
开始的,但它似乎跳转到
0000:7c22
(或
001d
仅用nasm…我相信我没有指定它从
7c00
)开始,但我希望跳转到
:7a22
:7a1d
,重新定位代码的地址。我尝试只使用
jmp continue
,然后如下面未注释所示,将堆栈指针添加到continue指针,按下它并返回。当添加到我的第一个扇区时,我得到的只是一个闪烁的光标。感谢您的帮助

                            ; 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]

使用以下命令编译和链接:
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
hextump-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
00000000 31 c9 8e c1 8e d9 8e d1 bc 00 7a 89 e7 66 be 00 | 1………z..f|
00000010 7c 00 fc b5 01 f3 a5 ea 1d 7a 00 fb 66 be | | | | z…f|

000000 20 35 7a 00 00 b4 0e bb 07 00 ac 3c 00 74 04 cd 10 | 5z……。正如您所发现的,您可以为整个引导加载程序将原点设置为
ORG 0x7A00
。这非常有效。将引导扇区复制到0x7A00的代码不依赖于任何绝对标签,只依赖于相关标签。这个答案更多的是一个思维实验,也是一种不同的方法

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

  • NASM允许BIN格式(
    -f BIN
    )包含具有一个(原点)和一个物理地址(起点)的部分。对于引导加载程序的布局,此方法限制太多
  • 使用定义引导加载程序的布局
  • 重新组织代码以使用0x0000的组织(原点),并相应地设置段寄存器。请听我回答这个问题
  • 这一回答侧重于备选方案2。对于Stackoverflow来说,解释LD链接器脚本如何工作太广泛了。这是最好的信息来源,它确实有例子。我们的想法是允许引导加载程序被放置在链接器脚本中。我们可以设置LMA(加载内存地址)来指定将节加载到内存中的内存地址。VMA是截面的原点。节中的所有标签和地址将相对于其VMA进行解析

    我们可以方便地使用带有特定LMA的节将引导签名直接放入输出文件中,而不是在汇编代码中指定它。我们还可以使用NASM
    extern
    指令从汇编代码中定义链接器脚本中的符号

    所有这些的一个优点是,您可以在汇编代码中按任何顺序定义节,链接器脚本将重新排序。还可以将多个对象文件链接在一起。应该首先列出包含要首先显示的启动代码的目标文件

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

    用于布局此引导加载程序的链接器脚本可能类似于:

    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
    中的数据,我在复制之前显示了一个字符串。然后,我对重新定位的代码执行远JMP。重新定位的代码将显示一个成功字符串

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

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


    一看拆卸 下面提供了原点为0x7c00的
    .bootinit
    部分。这是该节的OBJDUMP片段(为了简洁起见,没有数据):

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

    参赛作品:

    00007a3d <rel_entry-0x1>:
            ...
    
    应该指出的是,我们在NASM中使用ELF32格式,而不是BIN格式。然后使用LD创建二进制文件
    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
    
    与第一种方法不同的是,我们不使用LD的
    --oformat=binary
    选项。结果将生成一个ELF32映像,并将其放置在输出文件
    boot.elf
    中。我们不能直接使用
    boot.elf
    作为引导映像,因此我们使用OBJCOPY将ELF32文件转换为名为
    boot.bin
    的二进制文件。如果我们使用这样的命令来转储ELF文件的内容和反汇编,就可以看出这样做的有用性:

    • -D
      选项为全部反汇编
    • -x
      输出标题
    • -mi8086
      反汇编为16位8086代码
    • -Mintel
      反汇编应为英特尔语法,而不是默认的ATT语法

    重新定位MBR/引导加载程序的另一种选择,它不涉及链接器脚本,但允许引导加载程序中的所有代码和数据重新定位到段:偏移对=段:0x0000的任何位置。这并没有限制
    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>
    
    00007a3d <rel_entry-0x1>:
            ...
    
    nasm -f elf32 -o boot.o boot.asm
    ld -melf_i386 -Tlinker.ld -o boot.bin --oformat=binary boot.o
    
    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
    
    objdump boot.elf -Mintel -mi8086 -Dx
    
    Physical address = (segment << 4) + offset
    
    Physical address = (0x0000 << 4) + 0x7c00 = 0x07c00
    
    Physical address = (0x07c0 << 4) + 0x0000 = 0x07c00
    
    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
    
    nasm -f bin boot.bin boot.asm