Gcc 有没有办法在gnu汇编常量中使用数学表达式?

Gcc 有没有办法在gnu汇编常量中使用数学表达式?,gcc,assembly,x86-16,gnu-assembler,osdev,Gcc,Assembly,X86 16,Gnu Assembler,Osdev,执行以下操作的正确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 wil

执行以下操作的正确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>"
这让我感到困惑,因为我需要标签的内存地址时应该使用
$
,对吗

(2) 如果使用
data\u buffer
而不是
$data\u 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}
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) 当然,缺少“')”是怎么回事?

在GNU汇编程序中使用表达式时,它们必须解析为绝对值。GNU汇编器不知道代码的原点实际在哪里。这就是链接器的用途。由于
数据\u缓冲区
绝对地址在链接完成之前是未知的,因此被认为是可重新定位的。如果取一个绝对值,如0x9fc00,然后从中减去一个可重定位值,则得到一个可重定位值。不能在常量(绝对)表达式中使用可重定位值

一切都没有失去。一旦链接器安排了内存中的所有内容,它自己就会知道绝对地址。您似乎建议您已经使用了链接器脚本,这意味着您需要做的工作非常少。您可以使用链接器计算
max\u buffer\u扇区的值

链接器脚本将有一个
部分
指令,如:

SECTIONS
{
    [your section contents here]
}
您可以创建链接器符号
max\u buffer\u sectors
,如下所示:

SECTIONS
{
    max_buffer_sectors = (0x9fc00 - (data_buffer)) / 512;
    [your section contents here]
}
这将允许链接器计算大小,因为它将知道内存中的
data\u 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>"

您不应该使用
$
。即便如此,你所能做的还是有限的。另外请注意,对于16位代码,通常使用多段和gas不是一个好主意。PS:我的汇编程序(v2.22)抱怨“-”的
操作数(*ABS*和.data2部分)无效,这至少有道理。为什么
$
在这种情况下不合适?(我发现这是反复试验的结果,但我仍然不清楚何时使用
$
)(另请参见)我的玩具操作系统以实模式启动,切换到保护模式运行“常规”32位代码,然后在最后返回实模式,将内存缓冲区转储回磁盘。如果gas不是16位代码的正确工具,那么什么是好的替代方案?使用nasm编译16位代码,使用gcc编译其余代码并将其全部链接怎么样?
$
只是指令中立即数操作数的信号,它告诉汇编程序发出立即数而不是有效地址。它也适用于整个操作数,而不是符号,例如,
movl$4+foo,%eax
是合法的。是的,您可以使用
nasm
,但通常不希望链接16位和32位代码。让nasm生成平面二进制输出,并根据需要使用构建系统来构建图像。转换通常通过固定地址进行。
mov $max_buffer_sectors, %ax