如何在 GNU 汇编程序中使用字符串文字作为直接操作数(并将其移动到地址)?
Posted
技术标签:
【中文标题】如何在 GNU 汇编程序中使用字符串文字作为直接操作数(并将其移动到地址)?【英文标题】:How to use a string literal as an immediate operand (and move it to an address) in GNU assembler? 【发布时间】:2020-10-03 00:37:04 【问题描述】:我的意思是我在 NASM 中这样写的东西:
mov dword [0xA0BF17C], ' : )'
我在 GNU 汇编器中尝试过这样的事情:
movd " : )", 0xB8000
movd $" : )", 0xB8000
movd ' : )', 0xB8000
movd " : )", $0xB8000
但是......他们都导致了这个错误:
Error: unbalanced parenthesis in operand 1.
【问题讨论】:
我认为这在 GNU 汇编器中是不可能的。你查过说明书吗? 那里没有写怎么做,但这并不意味着你不能这样做。 所以基本上,GNU 汇编器不支持使用字符串文字作为整数常量。一种解决方案是手动查找这些字符的 ASCII 码并形成一个整数文字。 【参考方案1】:GAS 仅支持将单字符文字作为数字。 UTF-8 多字节单字符是可以的,但 not 是多个单独的字符。您可以使用movb $' ', 0xB8000
,但您不想使用 4 条指令来处理 4 个字节。
你有两个真正的选择:将单字符文字一起转换成一个数字,或者用十六进制写出来。 (两种方式都考虑到 x86 是 little-endian)
# NASM mov eax, "abcd"
movl $'a' + ('b'<<8) + ('c'<<16) + ('d'<<24), 0xB8000
movl $0x64636261, 0xB8000 # or manual ASCII -> hex, little-endian
移位/加法技巧适用于任意字节;您甚至可以制作一个 #define
CPP 宏来执行此操作(采用 4 个参数)。
使用 EAX 目标而不是内存(以简化机器代码),反汇编回 GAS Intel 语法(objdump -drwC -Mintel
),我们可以看到它们都以相同的方式组装(as --32
):
0: b8 61 62 63 64 mov eax,0x64636261
5: b8 61 62 63 64 mov eax,0x64636261
或者你的记忆目的地。同样,32 位模式,因为这会在实模式下 #GP 因超过 0xb8000 偏移量的 64k DS 段限制而出错。
另请注意,机器代码中的立即字节与将作为数据存储到内存目的地的顺序相同。 (如果您使用的是 NASM mov dst, "abcd"
,它们会匹配源顺序。
a: c7 05 00 80 0b 00 61 62 63 64 mov DWORD PTR ds:0xb8000,0x64636261
与 NASM 不同,GAS 不支持多字符字面量作为数字常量。它不支持它们,甚至会混淆 GAS 的解析器1! GAS 主要是为汇编编译器输出而设计的,编译器不需要这个。
GAS 仅支持(双)引用的多个字符的字符串作为 .ascii
/ .asciz
/ .string8/16/32
的 args,而不是 .byte
(与 NASM db
不同)或作为指令的立即操作数。
如果支持,x86 AT&T 语法将为movl $' : )', 0xB8000
。
不是movd
,直接操作数总是需要$
。
请参阅When using the MOV mnemonic to load/copy a string to a memory register in MASM, are the characters stored in reverse order? 了解 NASM 与 MASM 与 GAS 的多字符文字。只有 NASM 可以直观地工作。
双引号也不起作用:mov $"foo", %eax
汇编,但它的汇编与 mov $foo, %eax
相同 - 将符号 foo
的地址放入寄存器。有关示例,请参阅 relocation R_X86_64_8 against undefined symbol `ELF' can not be used when making a PIE object。
脚注 1: 因此出现“不平衡括号”之类的错误,而不是“字符文字包含多个字符”之类的合理错误。
mov $'abcd', %eax
是另一个完全混淆解析器的例子。它将b
视为本地标签的反向符号引用,如jmp 1b
以反向引用1:
标签。但是它在这里查找的标签号是 97,即'a'
的 ASCII 值。这完全是疯子
foo.s: Assembler messages:
foo.s:4: Error: backward ref to unknown label "97:"
foo.s:4: Error: junk `cd44%eax' after expression
foo.s:4: Error: number of operands mismatch for `mov'
所有这些都使用as --version
= GNU assembler (GNU Binutils) 2.34 进行了测试。
【讨论】:
以上是关于如何在 GNU 汇编程序中使用字符串文字作为直接操作数(并将其移动到地址)?的主要内容,如果未能解决你的问题,请参考以下文章