【发布时间】:2019-02-14 11:01:20
【问题描述】:
在从书中学习汇编语言时,有一个清单显示了一些基本操作:
segment .data
a dq 176
b dq 4097
segment .text
global _start
_start:
mov rax, [a] ; Move a into rax.
add rax, [b] ; add b o rax.
xor rax, rax
ret
在使用"$yasm -f elf64 -g dwarf2 -l listing.lst listing.asm" 命令组装并与"$ld -o listing listing.o" 链接后,我在gdb 中运行了程序。每当我尝试打印变量的值时,gdb 都会显示以下错误消息:
(gdb) p a
'a' has unknown type; cast it to its declared type
其他变量“b”也是如此。但是为 int 强制转换 'a' 或 'b' 有效:
(gdb) p (int)a
$11 = 176
(gdb) p (int)b
$12 = 4097
但这不应该在没有强制转换的情况下工作吗?为什么我需要投?我在源文件中犯了什么错误?
【问题讨论】:
-
dq在您的目标平台上很可能不是int(我从头到尾都不确定int在哪个目标平台上是64b)。因此,您可能只打印了铸造值的 32 位部分。 (而且我也不确定 gdb 识别什么类型,p (int64_t)a是否有效,或者您必须使用基本 C 类型,如p (long long)a?甚至一些 asm 也被识别为p (qword)a?) -
感谢您注意到 Ped7g。 sizeof() 在我的 PC 中为 int 返回 4。所以应该是dd。但是将 dq 更改为 dd 并不能解决问题。
-
mov rax,[a]确实读取了 8 个字节,因此如果您只想使用dd来定义数据,那么它应该是mov eax,[a](或者movsx rax,dword [a]如果您想要符号扩展32 位内存值转换为 64 位rax)。我也看不出dq与dd将如何解决任何问题,它只是改变了标签a之后定义的内存量。在调试信息中提供标签a某种类型信息超出了我通常在汇编中所做的工作(你让我有点认识到 8 位时代如何迫使我如此多地跟踪头脑中的所有内容,而我没有甚至考虑调试器知道“类型”)。 -
我的意思是,对我来说,你的问题甚至不是“问题”,我总是自己在调试器中为特定符号选择正确的大小。既然您问了这个问题,是的,如果汇编器能提供有关调试器符号的更多信息,那就太好了。然后,通常当一个人需要汇编程序(很少)时,他也经常需要非常规的内存工作,因此为标签
a定义某种“类型”实际上可能会影响您(如果您通过以下方式访问该内存)不同的指令,例如,如果你对一些代码进行矢量化,一次访问多个元素)。 -
so “但是这不应该在没有强制转换的情况下工作吗?” - 不,不是靠它自己。当特定标签还附加了有关存储在那里的预期数据“类型”的信息时,调试器将执行此操作,这是高级语言通常提供的,因为在 C 中,
int32_t a = 1;之类的东西确实定义了 32 位整数,但在汇编中类似于a: dd 1确实定义了指向发出机器码的下一个第一个字节的标签(行的a:部分),然后它定义了四个字节1, 0, 0, 0(行的dd 1部分),它们就像断开连接的实体,你甚至可以使用两条线。