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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Aug 21, 2015 at 9:56 AM, David Brown <david@xxxxxxxxxxxxxxx> wrote:
> 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 :-)

We have to be careful here. Clang has its own integrated assembler,
and it does not fully support Intel assembly.

But AT&T syntax is easy enough: ".att_syntax \n".

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

Actually, in a multi-line extended ASM block, it may not.

There's no way to tell the assembler when the reading and writing of
operands should occur. For example, suppose you want to save a
register, modify the register, save the modified register, and then
restore the register. What you will find is the C variable takes the
result of the `popl <register>` rather than the result of the
calculation/modification because there's no way to express the write
to the C Variable should occur after the calculation but before the
restore (this is the problem I am facing).

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

Yes, we've tried with and without clobbers. But in this case, I
*think* the underlying rule is that of Input Operands
(https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands)
and Output Operands
(https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands).
We have to inform the machinery what we are doing according to the
online manual.

(There's nothing I'd like to do more right now than avoid them
altogether since they are creating a lot of trouble).

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

OK, that page is wrong under some use cases. The cases involve the
memory model and the use of PIC. Depending on the memory model and
PIC, the caller owns `EBX/RBX`, so you have to preserve it before
destroying it. A simple clobber doesn't help.

(The page is also incomplete in that you have to test for OS support
for SSE in addition to CPU support for SSE. That's because SSE
requires the OS to save MMX register state during context switches.
See, for example, http://wiki.osdev.org/SSE#Checking_for_SSE).

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

Well, there's a lot to be said about those inferior compilers that
"just work" :)

I was done in under 15 minutes on that inferior compiler. That was
write the code, compile the code, verify code generation by examining
listing and verifying the code under the debugger with a live target.
Under GCC, I'm into my second day because I can't directly use a C
variable from an ASM block, and I can't seem to accurately express my
intentions with the multi-line extended ASM.

(I try to avoid the OS and Tool wars because I use a lot of them, but
I am frustrated with the Linux tools in this case).

> 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 :

What should be done for earlier versions of GCC that don't provide
cpuid.h? And what if its a different compiler that's not fully
compatible with GCC (Clang comes to mind because it defines __GNUC__,
but it can't consume the same set of programs GCC can). Finally, minor
hair splitting, but what do we do when it does not provide an accurate
result, like __builtin_cpu_supports
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55307).

Jeff



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux