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 了解引导加载程序汇编代码和内存位置_Assembly_X86 16_Bootloader_Real Mode - Fatal编程技术网

Assembly 了解引导加载程序汇编代码和内存位置

Assembly 了解引导加载程序汇编代码和内存位置,assembly,x86-16,bootloader,real-mode,Assembly,X86 16,Bootloader,Real Mode,我想检查我对以下引导加载程序代码的理解: BITS 16 start: mov ax, 07C0h ; Set up 4K stack space after this bootloader add ax, 288 ; (4096 + 512) / 16 bytes per paragraph mov ss, ax mov sp, 4096 mov ax, 07C0h ; Set data segment to where we

我想检查我对以下引导加载程序代码的理解:

BITS 16

start:
    mov ax, 07C0h   ; Set up 4K stack space after this bootloader
    add ax, 288     ; (4096 + 512) / 16 bytes per paragraph
    mov ss, ax
    mov sp, 4096

    mov ax, 07C0h       ; Set data segment to where we're loaded
    mov ds, ax

    mov si, text_string ; Put string position into SI
    call print_string   ; Call our string-printing routine

    jmp $           ; Jump here - infinite loop!

    text_string db 'This is my cool new OS!', 0

print_string:           ; Routine: output string in SI to screen
    mov ah, 0Eh     ; int 10h 'print char' function

.repeat:
    lodsb           ; Get character from string
    cmp al, 0
    je .done        ; If char is zero, end of string
    int 10h         ; Otherwise, print it
    jmp .repeat

.done:
ret

    times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
    dw 0xAA55       ; The standard PC boot signature
以下是我对代码的理解:

移动轴,07C0h:

  • 内存地址可以从堆栈段值(存储在ss寄存器中)和偏移量(存储在sp寄存器中)中获得。通过执行以下操作获得地址:堆栈段值x 16+偏移量值
  • 我们使用07C0h段在代码中设置空格。因此,当07C0h偏移为0时,它将引用0x7C00的地址。BIOS尝试从0x7C00启动代码。在0x7C00中复制的代码示例是MBR
  • 每个段以16字节的块递增,因此07C0h将为您提供地址范围0x7C00-0x7C0F。下一段07C1h将为您提供地址0x7C10-0x7C1F
加上ax,288

  • 要在引导加载程序之后设置4K堆栈空间,我们需要在每个段落中添加从(4096+512)/16字节中获得的288个。十进制值288等于120h
  • 现在存储在ax寄存器中的值是08e0h,我通过以下方式获得:07c0h+120h=08e0h(120h是十进制288)
mov-ss,ax

  • 将寄存器ax中的值复制到ss寄存器中。偏移现在包含段:08e0h
莫夫sp,4096

  • 偏移值为4096,即0x1000h。ss:sp对给出的值为08e0:1000
  • 堆栈的底部从内存地址0x8e00开始,堆栈的顶部在0x9e00(从0x8e00+0x1000=0x9e00)
下面是内存中的代码图和分配的空间,如下所示


注意:此图中的引导加载程序和内存引用很可能不正确,我假设它不是顺序的,汇编程序将以不同的方式编译机器代码。但是,代码将从较低的内存地址(0x7C00)开始,引导签名将从较高的地址开始(0xaa55磁盘签名从0x7c0:0x1fe(物理地址0x7c0*16+0x1fe=0x7dfe)开始,这是从0x7c0:0x0000到0x7c0:0x200的第一个512字节扇区的最后两个字节(0x7C32,它是512字节的结尾)

奇怪的是,分配的空间是两个4096字节的块:一个用于堆栈,另一个包含代码和数据

以下引导加载程序代码:

BITS 16

start:
    mov ax, 07C0h   ; Set up 4K stack space after this bootloader
    add ax, 288     ; (4096 + 512) / 16 bytes per paragraph
    mov ss, ax
    mov sp, 4096

    mov ax, 07C0h       ; Set data segment to where we're loaded
    mov ds, ax

    mov si, text_string ; Put string position into SI
    call print_string   ; Call our string-printing routine

    jmp $           ; Jump here - infinite loop!

    text_string db 'This is my cool new OS!', 0

print_string:           ; Routine: output string in SI to screen
    mov ah, 0Eh     ; int 10h 'print char' function

.repeat:
    lodsb           ; Get character from string
    cmp al, 0
    je .done        ; If char is zero, end of string
    int 10h         ; Otherwise, print it
    jmp .repeat

.done:
ret

    times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
    dw 0xAA55       ; The standard PC boot signature
它缺少如何设置汇编代码的相对地址的信息,即如何计算本地偏移量。通常引导加载程序从
org 0x7C00
开始,以明确代码期望从
cs:ip=0000:7C00
开始。但是您会这样做吗,
ds=07C0
将是错误的,这表明code希望偏移量被组装成从
07C0:0000开始,而不是从
0000:7C00开始。虽然两个地址都指向相同的物理内存地址,但段:偏移量对则不同

每个段以16字节为单位递增,因此07C0h将为您提供地址范围0x7C00-0x7C0F。下一段07C1h将为您提供地址0x7C10-0x7C1F

每个段提供64kiB的范围,尽管起始地址只增加了16个字节,因此段之间有很多重叠,您可以通过多种组合来寻址相同的物理地址。例如,
ds=07C0
提供进入物理内存范围的窗口
07C00-17BFF


然后,您将值转换为十六进制是错误的(另请参见Michael注释),288=0x120,4096=0x1000,但您正确地推断出有512B的引导加载程序代码(块设备的单扇区),4096B的空闲空间,然后是4096B的堆栈空间。如果将4096个字节以上的字节放入堆栈中,它将不会在编码后到达空闲空间,但会环绕到
08E0:FFFE
(远高于堆栈的原始开始)

我假设它不是顺序的,汇编程序将以不同的方式编译机器代码


相反,源代码中的指令和定义的字节在生成的机器代码中按顺序发出命令行开关,查看汇编器如何为特定行发出机器代码。例如,您是否可以将
文本\u string db'这是我的酷炫新OS!',0
行移到
BITS 16
指令的开头,该文本将位于机器代码的开头,由BIOS在
0000处加载并执行:7C00
地址,将文本字节作为指令执行。

0x7C0放入AX中。288(十进制)被添加到其中。288十进制是0x120。因此,在添加AX=0x8e0之后。0x8e0被放入SS(堆栈段)。4096(0x1000)因此,堆栈指针为SS:SP=0x8e0:0x1000。即物理地址0x8e0*16+0x1000=0x9E00。堆栈从那里向下扩展,但将在0x8e0:0000处包装回64kb段的顶部。0xaa55磁盘签名从0x7c0:0x1fe开始(物理地址0x7c0*16+0x1fe=0x7dfe)这是从0x7c0:0x0000到0x7c0:0x200运行的第一个512字节扇区的最后两个字节。谢谢。为了便于其他人在参考本文时理解,我编辑了Michael Petch的更正。更正为18h到120h(288十进制),07d8h到08e0h(7c0h+120h),256h到1000h(4096十进制),堆栈顶部为0x9e00,堆栈包装为0x8e00,引导签名地址为0x7dfe。此代码基于,并且它们不使用
org
指令,因此默认为
org 0x0000
。它们的引导加载程序实际上设计为使用0x7c0段。通常引导加载程序将自身从物理地址0x7c00重新定位到较低的memory(即:0x600)将使用0x7c0作为初始段,偏移量为0x0000。一个
组织0x0000
可以很容易地重新定位到任何段。我发现Michael关于组织指令使用的一篇很好的帖子。它建议