Can I use Intel syntax of x86 assembly with GCC?
Asked Answered
J

2

86

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!

Jonejonell answered 19/2, 2012 at 8:54 Comment(2)
If 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).Asseveration
Be 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.Waddington
M
103

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:

Misbehave answered 19/2, 2012 at 9:2 Comment(8)
@ugoren: -masm=intel makes the compiler generate Intel syntax. You really need it for inline assembly, otherwise "m" memory constraints won't work.Misbehave
.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.Centric
@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.Misbehave
OK. 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.Centric
I 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.Posticous
@ninjalj, can you pls update the answer to include the correct use of -masm=intel. It's kind of unclear right now.Said
@Centric 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 of 8(%rdi) for "m" operands). If you want code to work regardless of command line opts, use dialect alternatives: "mov {%1, %0 | %0, %1}".Asseveration
IIRC, 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.Asseveration
S
9

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();
}
Selfreliant answered 5/1, 2017 at 11:11 Comment(1)
Quality headers will use dialect alternatives so they can compile with -masm=intel or without.Asseveration

© 2022 - 2024 — McMap. All rights reserved.