【问题标题】:How to write multiple assembly statements within asm() without "\t\n" separating each line using GCC?如何在 asm() 中编写多个汇编语句而不使用 GCC 分隔每一行?
【发布时间】:2017-08-20 13:28:33
【问题描述】:

如何在 asm() 中编写多个汇编语句而不使用 GCC 分隔每一行?

我见过一些教科书在asm() 中写了多个汇编语句:

asm("
movl $4, %eax
movl $2, %ebx
addl %eax, %ebx
...
");

但是,我的编译器 (GCC) 无法识别此语法。相反,我必须依靠"\t\n" 分隔每一行或使用多个asm()

asm(
"movl $4, %eax\t\n"
"movl $2, %ebx\t\n"
"addl %eax, %ebx\t\n"
...);

asm("movl $4, %eax");
asm("movl $2, %ebx");
asm("addl %eax, %ebx");
...

如何启用没有"\t\n" 或重复asm() 的“干净”语法?

【问题讨论】:

  • 你的问题是什么?带有换行符的语法是“干净的”。不知道你为什么使用标签。无论如何如果不可避免,应谨慎使用内联汇编,并且仅用于短 sn-ps。
  • 我认为正确的解决方案是一开始就使用内联汇编。 :)
  • 解决方法很简单:使用单独的程序集文件。
  • 您为什么不直接编写清晰、可维护的 C++ 并让编译器担心 asm?除非你正在做一些真的低级别的事情或优化一个真的关键功能(并且真的知道你在做什么),否则编译器可能会反正写得比你好。
  • 什么样的建议是'你不应该写汇编程序'?天哪,这里没有人做过实验吗?

标签: c gcc assembly x86 inline-assembly


【解决方案1】:

海合会

不建议您使用内联汇编,因为您在未通知编译器的情况下更改了寄存器。您应该使用带有适当输入和输出约束的GCC's extended inline assembler。使用内联汇编程序应该用作last resort,并且您应该准确了解自己在做什么。 GCC 的内联汇编非常无情,因为看起来可以工作的代码甚至可能都不正确。

话虽如此,每个字符串都以\n\t 结尾,这样生成的汇编代码看起来更干净。您可以通过使用-S 参数进行编译以生成相应的汇编代码来看到这一点。您可以选择使用;(分号)。这将分隔每条指令,但将在同一汇编行上输出所有指令。是的,这很重要:查看 -S 输出是了解编译器如何将操作数替换到您的 asm 模板中并在您的周围放置自己的代码的好方法。

另一种选择是使用 C 行继续符\(反斜杠)。虽然以下代码会在生成汇编代码时产生过多的空白,但它会按预期编译和汇编:

int main()
{
    __asm__("movl $4, %eax; \
             movl $2, %ebx; \
             addl %eax, %ebx"
          ::: "eax", "ebx");
}

虽然这是一种方法,但我并不是说这是一种好的形式。我偏爱您在第二个示例中使用的表单,使用 \n\t 不带续行字符。


关于将多条指令拆分为单独的ASM语句:

asm("movl $4, %eax");
asm("movl $2, %ebx");     // unsafe, no operands specifying connections
asm("addl %eax, %ebx");

这是有问题的。编译器可以将它们相互重新排序,因为它们是没有依赖关系的基本汇编程序。编译器可以生成此代码:

movl $4, %eax
addl %eax, %ebx
movl $2, %ebx

这当然不会产生您期望的结果。当您将所有指令放在单个 ASM 语句中时,它们将按照您指定的顺序生成。


MSVC/C++

32 位 Microsoft C 和 C++ 编译器支持语言扩展,允许您在 __asm {} 之间放置多行内联汇编。使用这种机制,您不会将内联程序集放在 C 字符串中;不需要使用续行;并且不需要以;(分号)结束语句。

这方面的一个例子是:

__asm {
    mov eax, 4
    mov ebx, 2
    add ebx, eax
}

【讨论】:

  • 谢谢@Michael - 终于找到了解决我问题的答案。
  • 我仍然觉得很奇怪,例如Shellcoder Hacker's Handbook,使用我首先提到的语法。
  • @Shuzheng 我只能访问 Shellcoders 手册的第二版(在线),很明显他们在这方面犯了一些错误。在第二版中,尽管他们在示例中的第 4 章第 79 页中得到了正确的语法。在这种情况下,他们使用反斜杠继续字符并以; 结束每一行,就像我在回答中所做的那样,但我个人并不喜欢这样做。
  • 使用asm volatile强制编译器按顺序生成代码
  • asm("") 隐含为volatile;重新排序不是问题(除了有问题的编译器;缺少 clobber 声明意味着它不能在非naked 函数中安全使用
【解决方案2】:

你也可以这样做......

int main()
{
    __asm__(
            "movl $4, %eax;"
            "movl $2, %ebx;"
            "addl %eax, %ebx;"
           );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-19
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    相关资源
    最近更新 更多