【问题标题】:Inserting a comment in __asm results in C2400 error (VS2012)在 __asm 中插入注释会导致 C2400 错误(VS2012)
【发布时间】:2015-09-24 13:46:28
【问题描述】:

我试图检查 VS 2012 中某些代码的编译汇编程序。我添加了两行(在我的代码之前和之后):

__asm ; it begins here!
// My code
__asm ; it ends here!

但是,VS 不喜欢这样。我得到了

错误 C2400:“操作码”中的内联汇编语法错误;发现“坏令牌”

所以我添加了一个NOP,我不想这样做:

__asm NOP ; Comment!

效果很好。我的问题是双重的。

  1. 为什么 VS 不允许我添加程序集注释?
  2. 有没有其他方法可以在不添加指令的情况下添加汇编注释,包括NOP

【问题讨论】:

  • __asm { / // Comment / } 也不起作用?当您将 cmets 单独放置在一行时,或者仅当 __asm 块中根本没有指令时,是否总是会发生这种情况?
  • 您的建议不起作用(我认为注释和} 被解析为C++ 注释)。正如我在问题中所写,__asm NOP ; Comment! 有效。问题出在没有指令的时候。
  • 我的评论中代码格式块之间的斜线代表换行符,所以它并不是全部放在一行上。但也许你明白了。
  • 哦,您希望这些 cmets 出现在编译器的程序集输出中吗?那没关系。
  • 如果您希望 cmets 出现在程序集中,无论您使用什么格式的注释、程序集样式或 C/C++ 样式都没有关系。无论哪种方式,cmets 都不会出现在生成的程序集中,除非您使用 /FAs 选项,在这种情况下,整个源代码行都会作为注释显示在程序集中。

标签: c++ visual-studio assembly visual-c++


【解决方案1】:

它不起作用的原因是__asm是一个关键字,就像int是一个关键字一样,它不能单独出现,必须遵循正确的语法。以下面这段代码为例:

int main()
{
    int      // here's a comment, but it's ignored by the compiler
    return 0;
}

以下代码将因编译错误而失败,更具体地说,在 VS2012 中您会得到 error C2143: syntax error : missing ';' before 'return'。这是一个明显的错误,因为我们没有结束分号来表示指令的结束;添加分号并编译正常,因为我们没有违反 C(或本例中为 C++)语言的语法:

int main()
{
    int      // here's a comment, but it's ignored by the compiler
    ; // white space and comments are ignored by the compiler
    return 0;
}

下面的代码也是如此:

int main()
{
    __asm ; here's a comment but it's ignored

    return 0;
}

除了这里我们得到错误error C2400: inline assembler syntax error in 'opcode'; found 'constant',因为它将__asm关键字之后的所有内容都视为汇编指令,并且注释被正确地忽略了..所以下面的代码可以工作:

int main()
{
    __asm ; here's a comment but it's ignored
    NOP ; white space and comments are ignored by the compiler

    __asm {; here's an __asm 'block'
    } // outside of __asm block so only C style comments work
    return 0;
}

这就回答了你的第一个问题:Why didn't VS allow me to add an assembly comment?.. 因为它语法错误。

现在回答你的第二个问题:Is there a different way to add an assembly comment without adding an instruction, including NOP?

直接,不,没有,但间接,是的。值得注意的是,__asm 关键字在您的程序中被编译为内联程序集,因此 cmets 将从已编译的程序集中删除,就好像它是标准 C/C++ 注释一样,因此尝试在您的程序集中“强制”注释不需要通过该方法,相反,您可以使用/FAs 编译器标志,它将生成与源代码混合的程序集(机器代码),例如:

给出以下(非常简单的)代码:

int main()
{
    // here's a normal comment
    __asm { ; here's an asm comment and empty block
    } // here's another normal comment
    return 0;
}

使用/FAs 编译器标志编译时,生成的file.asm 具有以下输出:

; Listing generated by Microsoft (R) Optimizing Compiler Version 18.00.31101.0 

    TITLE   C:\test\file.cpp
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
; Function compile flags: /Odtp
; File c:\test\file.cpp
_TEXT   SEGMENT
_main   PROC

; 2    :     {

    push    ebp
    mov ebp, esp

; 3    :         // here's a normal comment
; 4    :         __asm { ; here's an asm comment and empty block
; 5    :         } // here's another normal comment
; 6    :         return 0;

    xor eax, eax

; 7    :     }

    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
END

注意它是如何包含源和 cmets 的。如果这段代码做得更多,你会看到更多的程序集和与之相关的源代码。

如果您想将 cmets 放入内联程序集本身,则可以使用普通 C/C++ 样式 cmets 以及 __asm 块本身内的程序集 cmets:

int main()
{
    // here's a C comment
    __asm { ; here's an asm comment
        // some other comments
        NOP ; asm type comment
        NOP // C style comment
    } // here's another comment
    return 0;
}

希望能有所帮助。

编辑:

应该注意以下代码也可以正确编译,但我不是 100% 确定原因:

int main()
{
    __asm
    __asm ; comment
    // also just doing it on a single line works too: __asm __asm
    return 0;
}

使用单个 __asm ; comment 编译此代码会产生编译错误,但两者都可以正常编译;在上面的代码中添加指令并检查.asm 输出表明第二个__asm 被其前面的任何其他汇编命令忽略。所以我不能 100% 确定这是一个解析错误还是 __asm 关键字语法的一部分,因为没有关于这种行为的文档。

【讨论】:

    【解决方案2】:

    在 Linux 上,g++ 接受:

    __asm(";myComment");
    

    和输出,当你运行g++ -S -O3 filename.cpp:

    # 5 "filename.cpp" 1
        ;myComment
    

    但是,clang++ 不喜欢它,并抱怨这个,当你运行clang++ -S -O3 filename.cpp:

    filename.cpp:5:9: error: invalid instruction mnemonic 'myComment'
      __asm(";myComment");
            ^
    <inline asm>:1:3: note: instantiated into assembly here
            ;myComment
             ^~~~~~~~~
    

    但是,我能够让 g++ 和 clang++ 都接受:

    __asm("//myComment");
    

    这两个编译器都输出与上述汇编输出相同的注释。


    由于我无法在互联网上的其他任何地方找到它,所以让我想到了这一点,是从 here 阅读的:

    微软特定

    __asm 块中的指令可以使用汇编语言 cmets:

    C++

    __asm mov ax, offset buff ; Load address of buff
    

    由于 C 宏扩展为单个逻辑行,因此请避免使用 宏中的汇编语言 cmets。 (请参阅将 __asm 块定义为 C 宏。)一个 __asm 块也可以包含 C 风格的 cmets;更多 有关信息,请参阅在 __asm 块中使用 C 或 C++。

    END Microsoft 特定

    然后此页面链接到herehere。这些提供了有关此事的更多信息。

    【讨论】:

    • x86 GNU 汇编器语法的注释字符是#。分号 (;) 分隔两个指令或指令,例如 dec %ecx; jnz .Lloop。 clang 有一个内置的汇编器,它需要 asm 有效才能使其甚至 编译,而 GCC 只在模板上进行文本替换,并不关心 asm 输出中的文本内容 -尝试构建没有 -S。 (或者在 Godbolt 上,使用“二进制”模式完全组装 + 反汇编。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2014-03-16
    相关资源
    最近更新 更多