如何在 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 汇编程序中使用字符串文字作为直接操作数(并将其移动到地址)?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 es6 模板文字作为 Angular 组件输入

简述gnu与linux的关系

如何在html中禁止文字的复制

wpf直接绑定xml生成应用程序

linux 学习笔记 GNU工具链简介

在编译时为大型 C/C++ 项目使用 GNU m4