亲爱的堆栈溢出用户!
试图在这里学习汇编,我偶然发现了这样一个事实,到目前为止,我已经找到了三种使用汇编(AT&T语法)创建变量的方法:
.equ
生成变量
.skip
为变量保留特定数量的存储
.quad/long/word/byte
创建一个小变量。
到目前为止,我收集的唯一区别是.quad
方法可能导致变量在特定条件下执行(并且.skip
像堆内存一样工作?我想?
所以至少,我想知道,有什么理由使用任何特定的方法吗?您认为哪一个最适合用于存储字符串、整数以及用户的一些输入等内容?
Edit:按照fuz的解释,我构造了以下代码来测试差异:
.data
bar: .int 128
.equ bob, 128
.bss
buf: .skip 128
buf1: .skip bar
buf2: .skip bob
.text
.global main
main:
mov $256, %rax
mov %rax, bar
mov %rax, bob
mov %rax, buf
ret
预期行为:
除buf1: .skip bar
和mov %rax, bob
外的所有作品。
实际行为:
除buf1: .skip bar
外的所有作品。错误test.s:11: Error: .space specifies non-absolute value
出现。
问题:
为什么我可以在运行时更改bob
?
第一个指令.equ
用于定义符号常量。 形式的指令
.equ foo, 42
也可以拼写为
foo= 42
并将符号foo
设置为值 42。 每当你提到符号foo
时,汇编器或链接器将替换值42。 至关重要的是,这不是一个变量。 不能在运行时更改foo
的值,并且foo
不会存储在程序中的任何位置。 另一方面,作为一个符号常量,你可以在任何可以使用数字的地方使用foo
。 例如,您可以跳过foo
个字节
.skip foo
如果foo
不是符号常数,您将无法做到这一点。
至于其他人,这些从根本上只是保留内存区域的不同方法。.byte
保留 1 个字节,.word
保留 2 个字节,.long
保留 4 个字节,.quad
保留 8 个字节。 您需要在指令之后给出内存将获得的初始值:
.int 23
保留 4 个字节的内存并将数字 23 写入该内存。 如果要为该内存区域命名,请在前面加上一个标签:
bar: .int 23
.skip
指令与此类似,但保留您告诉它的字节数。 但是,您不能设置它们的初始值,它们将始终为零。 例如,要保留 100 字节的缓冲区,请执行
buf: .skip 100
请注意,对于所有这些,将指令放置在哪里都很重要。 内存保留在当前部分中。 因此,如果将这些指令放入执行路径中,数据将作为代码执行。 如果您希望能够写入保留的内存,则需要将指令放入可写部分,例如.data
。
.data
foo: .int 42
bar: .byte 23
对于使用.skip
保留的缓冲区,将它们放入.bss
部分可能会很有用,因为这会减小磁盘上可执行文件的大小。 您只能在.bss
中保留.skip
或类似的存储(即初始内存内容均为零)。 否则,它的行为与.data
相同。
.bss
buf: .skip 100