将 GCC/ATT 风格的汇编器转换为 Visual Studio 汇编器?

Posted

技术标签:

【中文标题】将 GCC/ATT 风格的汇编器转换为 Visual Studio 汇编器?【英文标题】:Convert GCC/ATT style assembler to visual studio assembler? 【发布时间】:2014-12-28 17:24:56 【问题描述】:

我正在尝试重写这个sn-p以在visual studio中工作,但我显然不明白如何使用冒号的目的和__volatile__的含义,

你能提供一些帮助吗:)?

__asm__ __volatile__ (
    "mov %0, %%edi\n"
    "xor %%eax, %%eax\n"
    "xor %%ecx, %%ecx\n"
    "dec %%ecx\n"
    "repne scasb\n"
    "sub %%ecx, %%eax\n"
    "dec %%eax\n"
:
: "m" (src)
: "memory", "%ecx", "%edi", "%eax");

谢谢!

【问题讨论】:

First hit on Google。您实际上是在要求我们总结该页面吗? 不行,我自己尝试了好几种方法都没有成功,所以我把原代码贴在这里.. 这看起来很像strlen() 或类似的。你为什么要打扰而不使用普通的循环或适当的现有替代品? 包括你失败的尝试,有人可能会指出你出错的地方并解释原因。 我认为这不应该被关闭。 GCC 和 Visual Studio 内联汇编器是完全不同的,所以这个问题一点也不小。 【参考方案1】:

这两个内联汇编器是完全不同的。 Visual Studio 内联汇编器更原始但更易于使用。在 VS 中:

内联汇编语言不需要包含在字符串中; 指令操作数的顺序是dest,src; C/C++ 变量按原样访问; 等

您的代码没有任何输出运算符(在第一个冒号之后),所以我看不出它有什么影响。但是假设eax 寄存器要保存在最后的src 变量中。然后你想要这样的东西:

char* src;
...
__asm 
    mov   edi,src
    xor   eax,eax
    xor   ecx,ecx
    dec   ecx
    repne scasb
    sub   eax,ecx
    dec   eax

    mov   src,eax    // save result

顺便说一句,它对我来说似乎不是最佳选择。如果我正确理解代码,not ecx 可以完成与eax 的所有业务:

__asm 
    mov   edi,src
    xor   al,al
    xor   ecx,ecx
    dec   ecx
    repne scasb
    not   ecx

    mov   src,ecx    // save result

【讨论】:

你为什么放弃 XOR EAX,EAX ? @user3144770:你为什么认为这是必要的? SCASB 指令使用 AL 寄存器。那么为什么不能正确初始化呢?【参考方案2】:

...我不明白...冒号的用途...

正如 Columbo 在他的评论中指出的,这里是相关的手册页:6.43.2 Extended Asm - Assembler Instructions with C Expression Operands。冒号只是分隔 ASM 块中的标记。它们类似于终止 C 语句的分号(或者更准确地说,可能是逗号运算符,因为它们是相关的)。

重申一下页面在说什么,一般格式是:

asm (
        Instructions (Assembler Code)
        : Outputs (C variables modified by the instructions)
        : Inputs (C expressions read by the instructions)
        : Clobbers (Registers or other values changed by the instructions)
    )

有时分号之间不会有任何标记。例如,下面是内存屏障的样子:

__asm__ __volatile__ ("" ::: "memory")

没有汇编代码,没有用作输出的 C 变量,也没有用作输入的 C 表达式。但是内存被列为 clobbered,因此编译器知道在执行下一条指令之前确保挂起的读取和写入已经完成。


...我不明白...__volatile__的意思

好吧,这就是一堆蠕虫,因为 GCC 和 Visual Studio 对 volatile 的含义的解释不同(即使它们使用相同的 C 语言规范)。

在 GCC 中,使用volatile 的唯一原因是硬件可以更改内存。所以我认为在上面的示例中使用限定符volatile 是一种滥用(因为看起来该函数正在扫描NULL 字节,而不是执行内存映射I/O)。

您可以在volatile shared memory 的 GCC 邮件列表中找到相关讨论。提供以下回复的 Ian Lance Taylor 是 GCC 开发人员之一:

不,volatile 无法解决这个问题。这不是什么易变的 限定符是为。 volatile 限定符是为使用而设计的 内存映射硬件。它不是为多处理器共享而设计的 记忆。如果程序不是多处理器安全的,则添加 volatile 永远不会使其多处理器安全。


编辑:正如 Tony 在下面指出的那样,volatile is used to tame the optimizer 以便在编译期间不会删除 ASM 块。


另请注意,您可以将代码转换为 x86 的内联汇编程序,但不能为 x64 执行此操作。 Microsoft 不支持 x64 的内联汇编。请参阅 MSDN 上的 Intrinsics and Inline Assembly。

【讨论】:

volatile 是阻止 GCC 编译器优化整个 asm 块所必需的。这在 Visual Studio 中是无关紧要的,它做梦也不会做这样的事情。 @Tony - 这很有趣。我不记得在 GCC 文档中阅读过它。你有引用吗? (我可能需要更新那个答案)。 gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile。确实在大多数情况下volatile 是不必要的,但除非你不在乎你的 asm 块是否被优化掉,否则默认使用它是谨慎的。

以上是关于将 GCC/ATT 风格的汇编器转换为 Visual Studio 汇编器?的主要内容,如果未能解决你的问题,请参考以下文章

学习总结

编译汇编链接加载

将 Fortran 转换为 C 或 C++

如何将UNIX风格时间转换为标准格式

如何将 SSE 汇编代码转换为 AVX1/2 汇编代码?

用汇编语言将 .string 转换为 .quad