#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.
Related
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.
So I am trying to link a simple assembly script with c++, and so far no luck.
Assembly Script
section .data
global getebx
getebx:
mov eax, 0x0
cpuid
mov eax, ebx
ret
c++
#include <iostream>
extern "C" unsigned getebx();
int main (){
std::cout << (const char *)getebx()<< std::endl;
return 0;
}
And to build i am simply running the following commands.
nasm -f elf32 cpuidtest.asm
g++ -m32 -g main.cc cpuidtest.o
When I ran the executable I got a Segmentation Fault (Core dumped) error. So my next instinct was to take it to gdb. Here is what it returned:
program received signal SIGSEGV, Segmentation fault.
0xf7da0e86 in ?? () from /lib/i386-linux-gnu/libc.so.6
How can I fix this problem? Thank you in advance.
Calling convention mandates you must preserve some registers. In your case, that applies to ebx. You should modify your code to save and restore that, such as:
getebx:
push ebx
mov eax, 0x0
cpuid
mov eax, ebx
pop ebx
ret
Also, putting code into the .data section isn't the best idea ;)
Furthermore, ebx does not hold a string (a pointer to char) so you can not print it like that. It holds 4 characters, so something like this works better:
int main (){
unsigned ebx = getebx();
std::cout << std::string((char*)&ebx, 4) << std::endl;
return 0;
}
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.
How can I put Intel asm code into my c++ application?
I'm using Dev-C++.
I want to do sth like that:
int temp = 0;
int usernb = 3;
pusha
mov eax, temp
inc eax
xor usernb, usernb
mov eax, usernb
popa
This is only example.
How can I do sth like that?
UPDATE:
How does it look in Visual Studio ?
You can find a complete howto here http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
#include <stdlib.h>
int main()
{
int temp = 0;
int usernb = 3;
__asm__ volatile (
"pusha \n"
"mov eax, %0 \n"
"inc eax \n"
"mov ecx, %1 \n"
"xor ecx, %1 \n"
"mov %1, ecx \n"
"mov eax, %1 \n"
"popa \n"
: // no output
: "m" (temp), "m" (usernb) ); // input
exit(0);
}
After that you need to compile with something like:
gcc -m32 -std=c99 -Wall -Wextra -masm=intel -o casm casmt.c && ./casm && echo $?
output:
0
You need to compile with the -masm=intel flag since you want intel assembly syntax :)
UPDATE: How does it look in Visual Studio ?
If you are building for 64 bit, you cannot use inline assembly in Visual Studio. If you are building for 32 bit, then you use __asm to do the embedding.
Generally, using inline ASM is a bad idea.
You're probably going to produce worse ASM than a compiler.
Using any ASM in a method generally defeats any optimizations which try to touch that method (i.e. inlining).
If you need to access specific features of the processor not obvious in C++ (e.g. SIMD instructions) then you can use much more consistent with the language intrinsics provided by most any compiler vendor. Intrinsics give you all the speed of that "special" instruction but in a way which is compatible with the language semantics and with optimizers.
Here's a simple example to show the syntax for GCC/Dev-C++:
int main(void)
{
int x = 10, y;
asm ("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(y) /* y is output operand */
:"r"(x) /* x is input operand */
:"%eax"); /* %eax is clobbered register */
}
It depends on your compiler. But from your tags I guess you use gcc/g++ then you can use gcc inline assembler. But the syntax is quite weird and a bit different from intel syntax, although it achieves the same.
EDIT: With Visual Studio (or the Visual C++ compiler) it get's much easier, as it uses the usual Intel syntax.
If it's for some exercices I'd recommend some real assembler avoiding inlined code as it can get rather messy/confusing.
Some basics using GCC can be found here.
If you're open to trying MSVC (not sure if GCC is a requirement), I'd suggest you have a look at MSVC's interpretation which is (in my opinion) a lot easier to read/understand, especially for learning assembler. An example can be found here.
I tried to compile with GCC inline assembly code which compiled fine with MSVC, but got the following errors for basic operations:
// var is a template variable in a C++ function
__asm__
{
mov edx, var //error: Register name not specified for %edx
push ebx //error: Register name not specified for %ebx
sub esp, 8 //error: Register name not specified for %esp
}
After looking through documentation covering the topic, I found out that I should probably convert (even if I am only interested in x86) Intel style assembly code to AT&T style. However, after trying to use AT&T style I got even more weird errors:
mov var, %edx //error: Expected primary-expression before % token
mov $var, edx //error: label 'LASM$$s' used but not defined
I should also note that I tried to use LLVM-GCC, but it failed miserably with internal errors after encountering inline assembly.
What should I do?
For Apple's gcc you want -fasm-blocks which allows you to omit gcc's quoting requirement for inline asm and also lets you use Intel syntax.
// test_asm.c
int main(void)
{
int var;
__asm__
{
mov edx,var
push ebx
sub esp,8
}
return 0;
}
Compile this with:
$ gcc -Wall -m32 -fasm-blocks test_asm.c -o test_asm
Tested with gcc 4.2.1 on OS X 10.6.
g++ inline assembler is much more flexible than MSVC, and much more complicated. It treats an asm directive as a pseudo-instruction, which has to be described in the language of the code generator. Here is a working sample from my own code (for MinGW, not Mac):
// int BNASM_Add (DWORD* result, DWORD* a, int len)
//
// result += a
int BNASM_Add (DWORD* result, DWORD* a, int len)
{
int carry ;
asm volatile (
".intel_syntax\n"
" clc\n"
" cld\n"
"loop03:\n"
" lodsd\n"
" adc [edx],eax\n"
" lea edx,[edx+4]\n" // add edx,4 without disturbing the carry flag
" loop loop03\n"
" adc ecx,0\n" // Return the carry flag (ecx known to be zero)
".att_syntax\n"
: "=c"(carry) // Output: carry in ecx
: "d"(result), "S"(a), "c"(len) // Input: result in edx, a in esi, len in ecx
) ;
return carry ;
}
You can find documentation at http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm.