66
votes

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!

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).Peter Cordes
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.jww

2 Answers

79
votes

If you are using separate assembly files, gas has a directive to support Intel syntax:

.intel_syntax noprefix

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.)


If you are using 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.) This may not work with clang.

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.

8
votes

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();
}