当您编写标签时,Assembly是否会创建内存位置?

时间:2015-08-27 08:14:38

标签: assembly x86 x86-16 bootloader

例如,我有以下代码(MikeOS)。

jmp short bootloader_start  ; Jump past disk description section
nop                         ; Pad out before disk description
...
...

OEMLabel            db "MIKEBOOT"   ; Disk label
BytesPerSector      dw 512          ; Bytes per sector
SectorsPerCluster   db 1            ; Sectors per cluster
ReservedForBoot     dw 1            ; Reserved sectors for boot record
NumberOfFats        db 2            ; Number of copies of the FAT

bootloader_start:
    mov ax, 07C0h           ; Set up 4K of stack space above buffer
    add ax, 544             ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)   
    ...
    ...
....

现在,我知道jmp short bootloader_start意味着它跳过OEMLabel...部分并跳转到标签。

由于我不熟悉集会,我有几个问题:

  • 汇编在写入指令时是否分配内存?例如,在最后几行中,代码如下:

      times 510-($-$$) db 0 ; Pad remainder of boot sector with zeros
      dw 0AA55h             ; Boot signature (DO NOT CHANGE!)
    
    buffer:                 ; Disk buffer begins (8k after this, stack starts)
    

    buffer:分配内存?

  • 在此代码块中:

    cli             ; Disable interrupts while changing stack
    mov ss, ax
    mov sp, 4096
    sti             ; Restore interrupts
    

    为什么我们要清除中断?如果我没错,这段代码会分配4096字节的堆栈。

    最后,在上述块之后,我们有了这个:

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

    为什么我们这样做?在我看来,这样做是为了告诉数据段从哪里开始?

1 个答案:

答案 0 :(得分:6)

times 510-($-$$) db 0

这是一个(NASM)汇编程序特定的指令,它将填充剩余的可用空间,最多510个字节,并在二进制(内存)中的当前偏移处使用零。 它自己的标签将创建任何标签。创建/分配字节的唯一指令是DBDWDDDQ等。它是 cpu指令,但是由汇编程序解释的宏。

编辑(标签是什么?):

标签只表示偏移量(内存中或二进制文件中的地址)。以下面为例:

MyFirstLabel:
    db 1, 2, 3, 4
MySecondLabel:
    db 5, 6, 7, 8
Start:

如果这是你的汇编程序文件并且在偏移0处加载到内存中,它将如下所示:

OFS   DATA
0000h: 01 02 03 04
0004h: 05 06 07 08

您会注意到,MyFirstLabel只是存储数据的偏移量,在这种情况下偏移量为0. MySecondLabel只是另一个偏移量,但它从先前分配的数据开始,在这种情况下偏移量4.我的标签Start例如表示文件中的偏移量8。因此,该标签的“地址”是0008h(相对于数据/代码段),例如。

所以在你的情况下,如果你用零填充剩余的内存最多510个字节(这是你的times 510-($-$$) db 0指令正在做的事情),分配一个额外的数据字(DW 0AA55h)然后偏移您的buffer标签正好是512(0200h)(通常是主引导记录的大小)。

cli指令将告诉处理器在调用sti之前不允许中断。这很重要,因为堆栈指针寄存器(sp)和堆栈段寄存器(ss)会发生变化,这两条指令可能不会保证不会中断。这意味着在更改其中一个寄存器期间可能会发生中断。在这种情况下,堆栈可能是未定义/无效的。正如在这篇文章的评论中暗示的那样,实际上并不需要改变堆栈段和堆栈指针的cli / sti。请参阅有关“MOV”指令的英特尔文档:

  

使用MOV指令加载SS寄存器会禁止所有中断,直到执行下一条指令为止。此操作允许使用下一条指令将堆栈指针加载到ESP寄存器中(MOV ESP,   在发生中断之前的堆栈指针值。

如果没有cli / sti

,那么以下是正确的
mov bx, 4096
mov ss, ax 
mov sp, bx

以下是不正确的

mov ss, ax 
mov ax, 4096
mov sp, ax

您是对的,mov ds, ax将更改数据段寄存器。该寄存器的含义取决于我们是以实模式,保护模式等运行。您应该在您最喜欢的搜索引擎中搜索“x86分段存储模型”。