Use of constraints when mapping C variables to ASM symbolic names?

David Brown david@westcontrol.com
Fri Aug 21 13:56:00 GMT 2015


On 21/08/15 15:24, Jeffrey Walton wrote:
> I'm trying to compile some C code with inline assembly. I already have
> the ASM code, so I don't need anything generated. Effectively, all I
> need to do is map a C variable to an ASM symbolic name so I can use
> the variables directly in MASM-like fashion.

There are a number of issues here.  I am not a particular expert on
inline assembly, and the experience I have is all on embedded targets
rather than x86.  But maybe I can be of some help, so you know what to
look for in the gcc manuals or general web search.

First, gcc supports two inline assembly syntaxes for the x86.  The
default one (due to tradition on *nix and inertia) is AT&T, and it has a
number of differences from the Intel assembly syntax used by MASM.  You
have two options - learn (or copy from the web) the difference so that
you can use AT&T syntax in such inline assembly (this is the best
option, I think, since it is the default syntax).  Or learn the
settings, command-line options, pragmas, or whatever it takes to enable
MASM syntax in gcc.  I have no idea what these might be, since I don't
use them myself, but I bet the gcc documentation can give you a hint :-)

Second, you are trying to do pushes, pops, register allocations, etc.,
manually in your assembly.  Don't do that - let gcc's inline assembly do
it.  It is much safer (it will work regardless of other code, inlining,
optimisations, etc.), easier, and clearer.  It is also often faster,
though I doubt that matters here.  When you try to use registers or
variables like this behind the compiler's back, you will cause yourself
trouble - gcc does not know what you have done unless you tell it
clearly in the clobber lists.  In general assembly code, this lets gcc
pick the registers or memory modes to use - in cases like this where you
have specific register requirements for the assembly, you use
constraints that tell gcc to put variables into the specific registers.

<http://softpixel.com/~cwright/programming/simd/cpuid.php>

It is common for inline assembly in gcc to have nothing more than a
single instruction such as "cpuid" - all the "housekeeping" register and
variable manipulation is generated by the compiler.  Note that this is
in contrast to inferior compilers such as MSVC, where you are expected
to re-invent the wheel for inline assembly (with no guarantee that the
same wheel will fit on the next version of the compiler).

Thirdly, as far as I understand it gcc has better ways of detecting the
capabilities, such as builtins for checking for given capabilities that
you might want to use :

<https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html>

There is also the "cpuid.h" header that has a cpuid function - it is
better to use this than writing the inline assembly yourself.

mvh.,

David


> 
> I'd like to use a constraint that says, "this is a C variable", but
> there does not seem to be one. I'd also like to use a "no constraint"
> specifier because all I am doing is mapping C names to ASM symbolic
> names, but there does not seem to be one. An empty constraint string
> on outputs produces an error.
> 
> I think the next closet constraint is the "X" one, but its causing
> trouble. For example, with "X", the machinery is doing nonsensical
> things like (from --save-temps):
> 
>   /APP
>    # 155 "cpu.cpp" 1
>     .att_syntax
>     .att_syntax
>      pushl %ebx
>      movl $-2147483647, %eax
>      movl $0, %ecx
>      cpuid
>      movl %eax, %xmm0
>      movl %ebx, %xmm1
>      movl %ecx, %ebp
>      movl %edx, %xmm2
>      popl %ebx
> 
> How do I (1) map C variables to ASM symbolic names and (2) tell the
> machinery to *not* generate any code because I've already provided it.
> 
> **********
> 
> Here's the MASM-like code I am trying to use:
> 
>         "\t pushl %%ebx \n"
> 
>         "\t movl %[__FUNC], %%eax \n"
>         "\t movl %[__SUBFUNC], %%ecx \n"
> 
>         "\t cpuid \n"
> 
>         "\t movl %%eax, %[__EAX] \n"
>         "\t movl %%ebx, %[__EBX] \n"
>         "\t movl %%ecx, %[__ECX] \n"
>         "\t movl %%edx, %[__EDX] \n"
> 
>         "\t popl %%ebx \n"
> 
> __FUNC, __SUBFUNC, etc shadow a 32-bit C variable. That's all they do.
> 
> **********
> 
> Here's the stream of errors its producing:
> 
> g++: warning: -pipe ignored because -save-temps specified
> cpu.s: Assembler messages:
> cpu.s:129: Error: operand type mismatch for `mov'
> cpu.s:130: Error: operand type mismatch for `mov'
> cpu.s:131: Error: operand type mismatch for `mov'
> cpu.s:153: Error: operand type mismatch for `mov'
> cpu.s:154: Error: operand type mismatch for `mov'
> cpu.s:156: Error: operand type mismatch for `mov'
> cpu.s:342: Error: operand type mismatch for `mov'
> cpu.s:473: Error: operand type mismatch for `mov'
> cpu.s:474: Error: operand type mismatch for `mov'
> cpu.s:475: Error: operand type mismatch for `mov'
> cpu.s:497: Error: operand type mismatch for `mov'
> cpu.s:498: Error: operand type mismatch for `mov'
> cpu.s:500: Error: operand type mismatch for `mov'
> cpu.s:684: Error: operand type mismatch for `mov'
> 



More information about the Gcc-help mailing list