Can I use Intel syntax of x86 assembly with GCC?
Solution 1
If you are using separate assembly files, gas has a directive to support Intel syntax:
.intel_syntax noprefix # not recommended for inline asm
which uses Intel syntax and doesn't need the % prefix before register names.
(You can also run as
with -msyntax=intel -mnaked-reg
to have that as the default instead of att
, in case you don't want to put .intel_syntax noprefix
at the top of your files.)
Inline asm: compile with -masm=intel
For inline assembly, you can compile your C/C++ sources with gcc -masm=intel
(See How to set gcc to use intel syntax permanently? for details.) The compiler's own asm output (which the inline asm is inserted into) will use Intel syntax, and it will substitute operands into asm template strings using Intel syntax like [rdi + 8]
instead of 8(%rdi)
.
This works with GCC itself and ICC, but for clang only clang 14 and later.
(Not released yet, but the patch is in current trunk.)
Using .intel_syntax noprefix
at the start of inline asm, and switching back with .att_syntax
can work, but will break if you use any m
constraints. The memory reference will still be generated in AT&T syntax. It happens to work for registers because GAS accepts %eax
as a register name even in intel-noprefix mode.
Using .att_syntax
at the end of an asm()
statement will also break compilation with -masm=intel
; in that case GCC's own asm after (and before) your template will be in Intel syntax. (Clang doesn't have that "problem"; each asm template string is local, unlike GCC where the template string truly becomes part of the text file that GCC sends to as
to be assembled separately.)
Related:
-
GCC manual: asm dialect alternatives: writing an
asm
statement with{att | intel}
in the template so it works when compiled with-masm=att
or-masm=intel
. See an example usinglock cmpxchg
. - https://stackoverflow.com/tags/inline-assembly/info for more about inline assembly in general; it's important to make sure you're accurately describing your asm to the compiler, so it knows what registers and memory are read / written.
- AT&T syntax: https://stackoverflow.com/tags/att/info
- Intel syntax: https://stackoverflow.com/tags/intel-syntax/info
- The x86 tag wiki has links to manuals, optimization guides, and tutorials.
Solution 2
You can use inline assembly with -masm=intel as ninjalj wrote, but it may cause errors when you include C/C++ headers using inline assembly. This is code to reproduce the errors on Cygwin.
sample.cpp:
#include <cstdint>
#include <iostream>
#include <boost/thread/future.hpp>
int main(int argc, char* argv[]) {
using Value = uint32_t;
Value value = 0;
asm volatile (
"mov %0, 1\n\t" // Intel syntax
// "movl $1, %0\n\t" // AT&T syntax
:"=r"(value)::);
auto expr = [](void) -> Value { return 20; };
boost::unique_future<Value> func { boost::async(boost::launch::async, expr) };
std::cout << (value + func.get());
return 0;
}
When I built this code, I got error messages below.
g++ -E -std=c++11 -Wall -o sample.s sample.cpp
g++ -std=c++11 -Wall -masm=intel -o sample sample.cpp -lboost_system -lboost_thread
/tmp/ccuw1Qz5.s: Assembler messages:
/tmp/ccuw1Qz5.s:1022: Error: operand size mismatch for `xadd'
/tmp/ccuw1Qz5.s:1049: Error: no such instruction: `incl DWORD PTR [rax]'
/tmp/ccuw1Qz5.s:1075: Error: no such instruction: `movl DWORD PTR [rcx],%eax'
/tmp/ccuw1Qz5.s:1079: Error: no such instruction: `movl %eax,edx'
/tmp/ccuw1Qz5.s:1080: Error: no such instruction: `incl edx'
/tmp/ccuw1Qz5.s:1082: Error: no such instruction: `cmpxchgl edx,DWORD PTR [rcx]'
To avoid these errors, it needs to separate inline assembly (the upper half of the code) from C/C++ code which requires boost::future and the like (the lower half). The -masm=intel option is used to compile .cpp files that contain Intel syntax inline assembly, not to other .cpp files.
sample.hpp:
#include <cstdint>
using Value = uint32_t;
extern Value GetValue(void);
sample1.cpp: compile with -masm=intel
#include <iostream>
#include "sample.hpp"
int main(int argc, char* argv[]) {
Value value = 0;
asm volatile (
"mov %0, 1\n\t" // Intel syntax
:"=r"(value)::);
std::cout << (value + GetValue());
return 0;
}
sample2.cpp: compile without -masm=intel
#include <boost/thread/future.hpp>
#include "sample.hpp"
Value GetValue(void) {
auto expr = [](void) -> Value { return 20; };
boost::unique_future<Value> func { boost::async(boost::launch::async, expr) };
return func.get();
}
Hlib
Updated on February 11, 2022Comments
-
Hlib about 2 years
I want to write a small low level program. For some parts of it I will need to use assembly language, but the rest of the code will be written on C/C++.
So, if I will use GCC to mix C/C++ with assembly code, do I need to use AT&T syntax or can I use Intel syntax? Or how do you mix C/C++ and asm (intel syntax) in some other way?
I realize that maybe I don't have a choice and must use AT&T syntax, but I want to be sure..
And if there turns out to be no choice, where I can find full/official documentation about the AT&T syntax?
Thanks!
-
Peter Cordes over 8 yearsIf you write some whole functions in asm, they can be in a separately-compiled file. If you don't mind a build-dependency on YASM or NASM, it's then easy to use whatever syntax you like. (But then your asm has to deal with the different ABIs for Windows and Linux, maybe with assembler macros.) The GNU assembler manual is online, and also usually installed with gcc/binutils. (
info as
). -
jww almost 8 yearsBe careful with Intel syntax because Clang's integrated assembler chokes on it. Also see LLVM Issue 24232: Inline assembly operands don't work with .intel_syntax. The bug report shows Clang has trouble with a simple negate.
-
-
ninjalj about 12 years@ugoren:
-masm=intel
makes the compiler generate Intel syntax. You really need it for inline assembly, otherwise"m"
memory constraints won't work. -
ugoren about 12 years
.att_syntax noprefix
is needed to undo.intel_syntax noprefix
. I'm pretty sure you can use"m"
with AT&T syntax as well. It's just a matter of convenience, AFAIK. -
ninjalj about 12 years@ugoren: if you use
.intel_syntax
without-masm=intel
,"m"
will give memory references in AT&T syntax. If you use-masm=intel
you do not need to (and should not) go back to AT&T, since the compiler outputs Intel syntax. -
ugoren about 12 yearsOK. So you can use
"m"
with AT&T syntax, but not when mixing the two. I guess mixing them is possible, but not such a good idea. -
Per Lundberg about 9 yearsI think mixing them sounds like a bad idea. Either accept the AT&T syntax (which is weird, but something you can learn to live with) or go with Intel syntax all the way.
-
Johan almost 7 years@ninjalj, can you pls update the answer to include the correct use of
-masm=intel
. It's kind of unclear right now. -
Peter Cordes over 4 yearsQuality headers will use dialect alternatives so they can compile with
-masm=intel
or without. -
Peter Cordes over 3 years@ugoren please consider deleting your earlier comments. Using
intel_syntax noprefix
or.att_syntax
inside an inline asm statement is usually a bad idea. Only use them in stand-alone.S
files. Using-masm=intel
on the command line is much better, and will get GCC to fill in the asm template properly (with RDI instead of %RDI for example, or more importantly with[rdi+8]
instead of8(%rdi)
for"m"
operands). If you want code to work regardless of command line opts, use dialect alternatives:"mov {%1, %0 | %0, %1}"
. -
Peter Cordes over 3 yearsIIRC, clang will error on
%rdi
in Intel-syntax mode, so switching to.intel_syntax noprefix
in inline asm even as a dirty hack in clang won't work. I wrote an answer on How to set gcc to use intel syntax permanently? re: clang: basically nothing works well, just use AT&T syntax.