Inserting a comment in __asm results in C2400 error (VS2012) - c++

I was trying to check the compiled assembler of some code in VS 2012. I added two lines (before and after my code) as such:
__asm ; it begins here!
// My code
__asm ; it ends here!
However, VS didn't like that. I got
error C2400: inline assembler syntax error in 'opcode'; found 'bad token'
So I added a NOP, which I didn't want to:
__asm NOP ; Comment!
That worked fine. My question is twofold.
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?

The reason it doesn't work is that __asm is a keyword, just like int is a keyword, it cannot appear by itself and must follow the proper syntax. Take the following bit of code as an example:
int main()
{
int // here's a comment, but it's ignored by the compiler
return 0;
}
The following code will fail with a compilation error, more specifically in VS2012 you get error C2143: syntax error : missing ';' before 'return'. This is an obvious error since we do not have the ending semi-colon to denote end of instruction; add the semi-colon and it compiles fine because we did not dis-obey the syntax of the C (or C++ in this case) language:
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;
}
The same is true of the following code:
int main()
{
__asm ; here's a comment but it's ignored
return 0;
}
Except here we get the error error C2400: inline assembler syntax error in 'opcode'; found 'constant', becuase it's treating everything after the __asm keyword as an assembler instruction and the comment is being rightfully ignored .. so the following code WOULD work:
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;
}
So that answers your first question: Why didn't VS allow me to add an assembly comment?.. because it is a syntax error.
Now for your second question: Is there a different way to add an assembly comment without adding an instruction, including NOP?
Directly, no, there is not, but indirectly, yes there is. It's worth noting that the __asm keyword gets compiled into inline assembly in your program, so comments will be removed from the compiled assembly just as if it were a standard C/C++ comment, so trying to 'force' a comment in your assembly via that method is not necessary, instead, you can use the /FAs compiler flag and it will generate the assembly (machine code) mixed with the source, example:
Given the following (very simple) code:
int main()
{
// here's a normal comment
__asm { ; here's an asm comment and empty block
} // here's another normal comment
return 0;
}
When compiled with the /FAs compiler flag, the file.asm that was produced had the following output in it:
; 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
Notice how it includes the source and comments. If this code did more, you would see more assembly and the source associated with that as well.
If you're wanting to put comments in the inline assembly itself, then you can use normal C/C++ style comments as well as assembly comments within the __asm block itself:
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;
}
Hope that can help.
EDIT:
It should be noted the following bit of code also compiles without error and I'm not 100% sure why:
int main()
{
__asm
__asm ; comment
// also just doing it on a single line works too: __asm __asm
return 0;
}
Compiling this code with the single __asm ; comment gives the compilation error, but with both it compiles fine; adding instructions to the above code and inspecting the .asm output shows that the second __asm is ignored for any other assembly commands preceding it. So I'm not 100% sure if this is a parsing bug or part of the __asm keyword syntax as there's no documentation on this behavior.

On Linux, g++ accepts this:
__asm(";myComment");
and outputs, when you run g++ -S -O3 filename.cpp:
# 5 "filename.cpp" 1
;myComment
However, clang++ does not like it, and complains with this, when you run 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
^~~~~~~~~
I was, however, able to get both g++ and clang++ to accept:
__asm("//myComment");
which outputs the same comment as in the assembly output above, for both compilers.
What clued me into this, as I was unable to find it anywhere else on the internet, was reading from here:
Microsoft Specific
Instructions in an __asm block can use assembly-language comments:
C++
__asm mov ax, offset buff ; Load address of buff
Because C macros expand into a single logical line, avoid using
assembly-language comments in macros. (See Defining __asm Blocks as C
Macros.) An __asm block can also contain C-style comments; for more
information, see Using C or C++ in __asm Blocks.
END Microsoft Specific
This page then links to here and here. These provide more information on the matter.

Related

How to translate assembly code typed by {} into ()

First of all... I am a total noob with assembly. I understand almost nothing. But this code which you are gonna see below works fine in Visual Studio. I just need to compile this to .o file using a simple g++ command.
g++ -o fileName.o filename.cpp
I need to translate assembly code written inside brackets {} to assembly written inside parentheses (). When I am trying to compile below code it crashes. Compiler suggest to use ( instead of {
unsigned char decode5a[0x0dac];
unsigned char* srcbuf = new unsigned char[4000];
m_image = new unsigned char[4000];
unsigned char* dstbuf = m_image;
__asm
{
lea eax, decode5a
push srcbuf
push dstbuf
call eax
add esp, 8
}
I tried something like that but it crash also. I think I am passing variable incorrectly.
__asm__(
"lea eax, decode5a \n
push srcbuf \n
push dstbuf \n
call eax \n
add esp, 8 \n
");
Here's how you would write that in gcc extended inline assembly, but this still may not work depending on what the function does.
In particular, any registers modified by the function have to be listed in the clobbers.
__asm__(
"push %1\n"
"push %2\n"
"call *%0\n"
"add $8, %%esp \n"
: : "r"(decode5a), "r"(srcbuf), "r"(dstbuf)
: "eax", "memory");

C++ inline assembly PROC ENDP error

I am trying to create procedure in assembly x86 inside a C++ program. My code is:
#include <stdio.h>
#include <stdlib.h>
int main(void){
_asm{
input1 PROC
push inputnumber
lea eax, inputmsg
push eax
call printf
add esp, 8
push ebx
lea eax, format
push eax
call scanf
add esp, 8
jmp check1
ret
input1 ENDP
}
}
However, when I try to compile the program with Visual studio I get the following error:
C2400 inline assembler syntax error in 'opcode'; found 'PROC'
C2400 inline assembler syntax error in 'opcode'; found 'ENDP'
I've read online but I cannot resolve it. Any suggestions how to fix it ?
Surprised that those are the only errors you get. PROC and ENDP are not recognized by the C inline assembler. Anyway, defining a function inside a function in C isn't a good idea. Try
int main(){
_asm{
push inputnumber
lea eax, inputmsg
:
call scanf
add esp, 8
ret
}
}
You will then end up with a whole bunch of undeclared variables and possibly warnings about scanf if you're using one of the MS compilers.

investigating visual studio assembly output

While using /FA option for compiling code that uses this dummy class
class A {
public:
A() {}
int Initialize() {
return 0;
}
};
I looked over the generated asm file where this was defined and also used and saw this in the asm file
PUBLIC ?Initialize#A##QEAAHXZ ; A::Initialize
PUBLIC ??0A##QEAA#H#Z ; A::A
??0A##QEAA#H#Z PROC ; A::A, COMDAT
; File d:\dev\temp\consoleapplication1\consoleapplication1\consoleapp2.cpp
; Line 7
mov rax, rcx
ret 0
??0A##QEAA#H#Z ENDP ; A::A
_TEXT ENDS
; Function compile flags: /Ogtpy
; COMDAT ?Initialize#A##QEAAHXZ
_TEXT SEGMENT
this$dead$ = 8
?Initialize#A##QEAAHXZ PROC ; A::Initialize, COMDAT
; File d:\dev\temp\consoleapplication1\consoleapplication1\consoleapp2.cpp
; Line 9
xor eax, eax
; Line 10
ret 0
?Initialize#A##QEAAHXZ ENDP ; A::Initialize
As you can see there is generated "trivial" implementation functions for both constructor and Initialize function.
At first I thought that this non inline implementation was going to be used where class A is used but debugging showed that this was not the case (code seemed to be inlined). Class A is not used anywhere else except this asm file so why are those functions generated if not used ?
Whole program optimization was in place.
"so why are those functions generated if not used ?"
You are inspecting assembly code generated for a single translation unit, not the final assembly after linking.
The linker will strip out any unused functions finally.

Inline Assembly with GCC

#include <stdio.h>
int
get_random(void)
{
asm(".intel_syntax noprefix\n"
"mov eax, 42 \n");
asm("mov eax, 42 \n");
}
int
main(void)
{
return printf("The answer is %d.\n", get_random());
}
I am trying to compile this C++ program with these CLI commands:
g++ asm.cpp -o asm
Error messages:
/tmp/ccXHbaRO.s: Assembler messages:
/tmp/ccXHbaRO.s:41: Error: no such instruction: `movl %eax,%esi'
/tmp/ccXHbaRO.s:42: Error: no such instruction: `movl $.LC0,%edi'
/tmp/ccXHbaRO.s:43: Error: no such instruction: `movl $0,%eax'
Because I added asm(".intel_syntax noprefix\n"); I thought I wouldn't need to add the GCC flag -masm=intel?
Also, where can I find out more information about the -masm flag? Is there a NASM equivalent?
The code you write in assembly gets placed verbatim in the output of the compiler.
This means that if you change the format or other global options about how to parse assembly code you will need to restore the default options at the end.
If you don't do this the code generated by the compiler after your part will become invalid.

Why isn't my inline assembly in C++ working?

Strangest error output:
#include <iostream>
int main(int arg, char **LOC[])
{
asm
(
"mov eax, 0CF;"
"pusha;"
);
return 0;
}
It complains, and here is the error from GCC:
t.s: Assembler messages:
t.s:31: Error: too many memory references for `mov'
You get this error because your assembly is malformatted. Register accesses are done like %eax, $ is used for immediate operands. Furthermore, GCC, by default (see DanielKO's comment), uses the AT&T syntax, which has the destination on the right and the source on the left. Is this what you are looking for?
mov $0xcf, %eax
Also, your pusha is unbalanced, ie you don't clean up the stack correctly before you return from your function. It would be nice to know what your overall goal is, because right now it seems like you copied and pasted only an incomplete fraction of the source.