执行以下操作的正确gnu汇编语法是什么:
.section .data2
.asciz "******* Output Data ********"
total_sectors_written: .word 0x0
max_buffer_sectors: .word ((0x9fc00 - $data_buffer) / 512) # <=== need help here
.align 512
data_buffer: .asciz "<The actual data will overwrite this>"
具体来说,我正在写一个玩具操作系统。上面的代码是16位实模式。我正在设置一个将被转储回启动盘的数据缓冲区。我想计算在data_buffer
放置在内存中的扇区数与该数据缓冲区的上限之间的扇区数。 (地址0x9fc00是缓冲区将运行到为其他目的保留的RAM的位置。)
我知道我可以编写汇编代码来计算它;但是,因为它是一个在构建时已知的常数,所以我很好奇我是否可以让汇编程序为我计算它。
我遇到了三个具体问题:
(1)如果我使用$data_buffer
,我会收到此错误:
os_src/boot.S: Assembler messages:
os_src/boot.S:497: Error: missing ')'
os_src/boot.S:497: Error: can't resolve `L0' {*ABS* section} - `$data_buffer' {*UND* section}
我觉得很困惑,因为当我想要标签的内存地址时,我应该使用$
,对吗?
(2)如果我使用data_buffer
代替$data_buffer
,我会收到此错误:
os_src/boot.S: Assembler messages:
os_src/boot.S:497: Error: missing ')'
os_src/boot.S:497: Error: value of 653855 too large for field of 2 bytes at 31
make: *** [obj/boot/dd_test.o] Error 1
这似乎表明汇编程序抱怨中间值的大小(不需要适合16位字)。
(3)当然,还有失踪的&#39;&#39;&#39;
答案 0 :(得分:4)
在GNU汇编程序中使用表达式时,必须解析为绝对值。 GNU汇编器不知道代码的起源实际上是什么。这就是链接器的用途。由于data_buffer
绝对地址在链接完成之前是未知的,因此它被认为是可重定位的。如果采用像0x9fc00这样的绝对值并从中减去可重定位值,则会得到可重定位的值。可重定位值不能用于常量(绝对)表达式。
一切都不会丢失。链接器本身将在内存中排列所有内容后知道绝对地址。您似乎建议您已经使用链接描述文件,这意味着您必须做的工作很少。您可以使用链接器计算max_buffer_sectors
的值。
您的链接描述文件将具有SECTIONS
指令,如:
SECTIONS
{
[your section contents here]
}
您可以使用以下内容创建链接符号max_buffer_sectors
:
SECTIONS
{
max_buffer_sectors = (0x9fc00 - (data_buffer)) / 512;
[your section contents here]
}
这将允许链接器计算大小,因为它将知道内存中的data_buffer
绝对地址。
您的GNU程序集文件需要进行一些调整:
.globl data_buffer
.section .data2
.asciz "******* Output Data ********"
total_sectors_written: .word 0x0
.align 512
data_buffer: .asciz "<The actual data will overwrite this>"
你会注意到我使用了.globl data_buffer
。这会导出符号并使其成为全局符号,以便链接器可以使用它。
然后,您可以在代码中使用符号max_buffer_sectors
:
mov $max_buffer_sectors, %ax