有没有一种方法可以在gnu汇编常量中使用数学表达式?

Zac*_*ack 3 assembly gcc gnu-assembler osdev x86-16

执行以下操作的正确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>"
Run Code Online (Sandbox Code Playgroud)

具体来说,我正在编写一个玩具OS。上面的代码是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}
Run Code Online (Sandbox Code Playgroud)

我会感到困惑,因为$当我想要标签的内存地址时,应该使用它,对吗?

(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
Run Code Online (Sandbox Code Playgroud)

这似乎表明汇编程序正在抱怨中间值的大小(该中间值不需要适合16位字)。

(3)当然,丢失的')'是怎么回事?

Mic*_*tch 5

在GNU汇编器中使用表达式时,它们必须解析为绝对值。GNU汇编器不知道代码的实际起点。这就是链接器的作用。由于只有data_buffer在完成链接后才能知道该绝对地址,因此它被认为是可重定位的。如果您采用0x9fc00之类的绝对值并从中减去一个可重定位的值,则将获得一个可重定位的值。可重定位的值不能用于常量(绝对)表达式中。

一切都不会丢失。一旦链接器将所有内容安排在内存中,链接器本身将知道绝对地址。您似乎建议您已经使用了链接描述文件,这意味着您要做的工作很少。您可以使用链接器计算的值max_buffer_sectors

您的链接描述文件将具有如下SECTIONS指令:

SECTIONS
{
    [your section contents here]
}
Run Code Online (Sandbox Code Playgroud)

您可以使用以下内容创建链接器符号max_buffer_sectors

SECTIONS
{
    max_buffer_sectors = (0x9fc00 - (data_buffer)) / 512;
    [your section contents here]
}
Run Code Online (Sandbox Code Playgroud)

这将使链接器能够计算大小,因为它会知道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>"
Run Code Online (Sandbox Code Playgroud)

您会注意到我曾经使用过.globl data_buffer。这将导出符号并使它成为全局符号,以便链接器可以使用它。

然后,您可以max_buffer_sectors在代码中使用该符号,例如:

mov $max_buffer_sectors, %ax
Run Code Online (Sandbox Code Playgroud)