【发布时间】:2021-01-10 04:50:35
【问题描述】:
为了在调试器之外进行调试,我通常会添加基本的打印语句,例如:
str: .string "Hello!\n"
mov $1, %rdi
mov $str, %rsi
mov $7, %rdx
mov $1, %eax
syscall
有没有办法创建一个宏,我可以改为这样写:
print ($str, $7)
它会自动扩展为:
mov $1, %rdi
mov $1, %eax
mov $str, %rsi
mov $7, %rdx
syscall
我查看了macro 的gas 文档,但似乎它使用的语法我不确定它是在哪里定义的(似乎他们正在使用for 循环?)。是否可以在 asm 中执行上述操作?我想如果不是,我可以在 vim 中创建一个可以“扩展”到上述内容的 sn-p。
感谢您的建议。我用来打印上面的测试宏是:
.macro DEBUG str_addr, str_len
mov $1, %edi
mov $\str_addr, %rsi
mov $\str_len, %edx
mov $1, %eax
syscall
.endm
DEBUG str, 7
虽然语法有点奇怪,但对于“普通指令”(而不是循环或条件,例如),宏语法被称为:
macro arg1, arg2
并定义为:
.macro <macro_name> <arg1>, <arg2>, ...
.endm
变量名需要用\ 转义。因此,例如要引用arg1,您必须执行\arg1。
【问题讨论】:
-
CPP 宏通常比 GAS 的原生宏更易于使用。如果你想要
()围绕 args,你可能需要 CPP 风格的宏。我认为调用 GAS 宏使用的语法类似于 asm 指令macroname arg, arg。如果您在 Google 上搜索gas macro并查看一些出现在 SO 问题中的示例,您可以看到这一点。 -
@PeterCordes 我明白了。宏在汇编中被认为是“不好的做法”,还是根本没有使用?
-
Asm 宏确实可以使用,它们只是不使用您要求的语法,所以我建议使用 CPP 宏。 GAS 宏在某些方面不如 NASM 方便,至少如果你想重复某事可变的次数,但这很简单。如果您仔细记住它破坏的寄存器是什么,调试打印宏可能是有意义的。 (您可能想要推送/弹出宏周围使用的所有寄存器,包括 RCX 和 R11)通常使用调试器来查看执行的位置很有效:与 C 不同,机器确实直接执行您的指令,因此调试器非常有用。
-
另外,如果你不小心的话,asm 宏会让你的代码很容易膨胀。如果你只是天真地使用一堆宏,你就会失去在事物之间进行优化的机会。 (如果您不关心优化,那么用 asm 编写没有多大意义。)当然,调试打印宏不是问题;它们仅用于调试。
标签: assembly x86 gnu-assembler