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

wei*_*nda 2 x86 assembly bootloader x86-16

例如,我有以下代码(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)   
    ...
    ...
....
Run Code Online (Sandbox Code Playgroud)

现在,我知道这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)
    
    Run Code Online (Sandbox Code Playgroud)

    buffer: 分配内存?

  • 在此代码块中:

    cli             ; Disable interrupts while changing stack
    mov ss, ax
    mov sp, 4096
    sti             ; Restore interrupts
    
    Run Code Online (Sandbox Code Playgroud)

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

    最后,在上面的块之后,我们有:

    mov ax, 07C0h           ; Set data segment to where we're loaded
    mov ds, ax
    
    Run Code Online (Sandbox Code Playgroud)

    我们为什么要做这个?在我看来,这是为了告诉数据段的起源在哪里?

bka*_*sbk 6

times 510-($-$$) db 0
Run Code Online (Sandbox Code Playgroud)

它是一个(NASM)汇编程序特定指令,它将填充剩余的可用空间,最多510个字节,并在二进制(内存)中的当前偏移量处使用零.它自己的标签不会创造任何标签.唯一的指令,将创建/分配的字节是DB,DW,DD,DQ等,这是没有 CPU的指令,而是通过汇编PROGRAMM解释的一种宏观的.

编辑(什么是标签?):

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

MyFirstLabel:
    db 1, 2, 3, 4
MySecondLabel:
    db 5, 6, 7, 8
Start:
Run Code Online (Sandbox Code Playgroud)

如果这是你的汇编程序文件并且它在偏移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寄存器会禁止所有中断,直到执行下一条指令为止.此操作允许在发生中断之前使用下一条指令(MOV ESP,堆栈指针值)将堆栈指针加载到ESP寄存器中.

因此,如果没有cli/sti,以下将是正确的

mov bx, 4096
mov ss, ax 
mov sp, bx
Run Code Online (Sandbox Code Playgroud)

以下是不正确的

mov ss, ax 
mov ax, 4096
mov sp, ax
Run Code Online (Sandbox Code Playgroud)

你说得对,mov ds, ax会改变数据段寄存器.该寄存器的含义取决于我们是否以实模式,保护模式等运行.您应该在您喜欢的搜索引擎中搜索"x86分段存储模型".