Assembly 会在您写标签时创建内存位置吗?
Does Assembly create memory locations the moment you write a label?
比如我有下面的代码(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
为什么要清除Clear the Interrupts?如果我没记错的话,这段代码分配了 4096 字节的堆栈。
最后,在上面的块之后,我们有这个:
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
我们为什么要这样做?在我看来,这样做是为了告诉Data Segment start它的起源在哪里?
times 510-($-$$) db 0
这是一条 (NASM) 汇编器特定指令,它将在二进制文件(内存)的当前偏移量处用零填充剩余的 space 最多 510 个字节。
它自己的标签 不会 创建任何 .唯一会 create/allocate 字节的指令是 DB
、DW
、DD
、DQ
等。它是 no 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。所以这个标签的"address"例如是0008h(相对于data/code段)。
所以在你的情况下,如果你用零填充剩余内存最多 510 个字节(这是你的 times 510-($-$$) db 0
指令正在做的),分配一个额外的数据字 (DW 0AA55h
) 然后buffer
标签的偏移量正好是 512 (0200h)(通常是主引导记录的大小)。
cli
指令将告诉处理器在调用 sti
之前不允许被中断。这一点很重要,因为堆栈指针寄存器 (sp) 和堆栈段寄存器 (ss) 会发生变化,并且这两条指令 可能不会 保证是不间断的。这意味着在更改这些寄存器之一期间可能会发生中断。在这种情况下,堆栈可能是 undefined/invalid。正如对此帖子的评论中所暗示的,实际上并不需要用于更改堆栈段和堆栈指针的 cli/sti。请参阅有关 "MOV" 指令的英特尔文档:
Loading the SS register with a MOV instruction inhibits all interrupts until after the execution of the next instruction. This operation allows a stack pointer to be loaded into the ESP register with the next instruction (MOV ESP,
stack-pointer value) before an interrupt occurs.
所以如果没有 cli/sti
,下面的内容也是正确的
mov bx, 4096
mov ss, ax
mov sp, bx
以下不正确
mov ss, ax
mov ax, 4096
mov sp, ax
你说得对,mov ds, ax
会改变数据段寄存器。这个寄存器的含义取决于我们是运行在实模式还是保护模式等。你应该在你喜欢的搜索引擎中搜索"x86 segmented memory model"。
记忆一直都在。 buffer:
只是给它起一个象征性的名字。
禁用中断以防止其他进程干扰可能需要多个指令的东西。专门用于设置堆栈,您不必这样做,因为设置 ss
寄存器将禁用下一条指令的中断。目的是您也应该有时间设置 sp
。
无论如何,在完成后启用中断可能是个好主意,因为它们最初可能没有启用。
ds
寄存器必须设置为您要执行的代码假定的段。否则程序将找不到您的变量。
比如我有下面的代码(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
为什么要清除Clear the Interrupts?如果我没记错的话,这段代码分配了 4096 字节的堆栈。
最后,在上面的块之后,我们有这个:
mov ax, 07C0h ; Set data segment to where we're loaded mov ds, ax
我们为什么要这样做?在我看来,这样做是为了告诉Data Segment start它的起源在哪里?
times 510-($-$$) db 0
这是一条 (NASM) 汇编器特定指令,它将在二进制文件(内存)的当前偏移量处用零填充剩余的 space 最多 510 个字节。
它自己的标签 不会 创建任何 .唯一会 create/allocate 字节的指令是 DB
、DW
、DD
、DQ
等。它是 no 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。所以这个标签的"address"例如是0008h(相对于data/code段)。
所以在你的情况下,如果你用零填充剩余内存最多 510 个字节(这是你的 times 510-($-$$) db 0
指令正在做的),分配一个额外的数据字 (DW 0AA55h
) 然后buffer
标签的偏移量正好是 512 (0200h)(通常是主引导记录的大小)。
cli
指令将告诉处理器在调用 sti
之前不允许被中断。这一点很重要,因为堆栈指针寄存器 (sp) 和堆栈段寄存器 (ss) 会发生变化,并且这两条指令 可能不会 保证是不间断的。这意味着在更改这些寄存器之一期间可能会发生中断。在这种情况下,堆栈可能是 undefined/invalid。正如对此帖子的评论中所暗示的,实际上并不需要用于更改堆栈段和堆栈指针的 cli/sti。请参阅有关 "MOV" 指令的英特尔文档:
Loading the SS register with a MOV instruction inhibits all interrupts until after the execution of the next instruction. This operation allows a stack pointer to be loaded into the ESP register with the next instruction (MOV ESP, stack-pointer value) before an interrupt occurs.
所以如果没有 cli/sti
,下面的内容也是正确的mov bx, 4096
mov ss, ax
mov sp, bx
以下不正确
mov ss, ax
mov ax, 4096
mov sp, ax
你说得对,mov ds, ax
会改变数据段寄存器。这个寄存器的含义取决于我们是运行在实模式还是保护模式等。你应该在你喜欢的搜索引擎中搜索"x86 segmented memory model"。
记忆一直都在。 buffer:
只是给它起一个象征性的名字。
禁用中断以防止其他进程干扰可能需要多个指令的东西。专门用于设置堆栈,您不必这样做,因为设置 ss
寄存器将禁用下一条指令的中断。目的是您也应该有时间设置 sp
。
无论如何,在完成后启用中断可能是个好主意,因为它们最初可能没有启用。
ds
寄存器必须设置为您要执行的代码假定的段。否则程序将找不到您的变量。