Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

inline assembly causes ICC to generate invalid instruction

I-Ting_L_
Beginner
592 Views

Hi,

I am trying to compile a piece of code that uses GCC style inline assembly using Intel C++ compiler (ICC 13.0.0).

It seems that the following inline assembly causes ICC to output invalid assembly:

asm volatile (
"movq %0, %%rax\n\t"
"movq %%rbp, 16(%%rax)\n\t"
"movq %%rsp, 8(%%rax)\n\t"
"leaq 4(%%rip), %%rbx\n\t"
"movq %%rbx, 24(%%rax)\n\t"
: : "g" (frame) : "rax", "rbx" );

which produces the assembly code as expected, but after the sequence, a "lea 0" is generated.

Strangely, if I were to split this sequence into two pieces:

asm volatile (
"movq %0, %%rax\n\t"
"movq %%rbp, 16(%%rax)\n\t"
"movq %%rsp, 8(%%rax)\n\t"
: : "g" (frame) : "rax", "rbx" );
asm volatile (
"leaq 4(%%rip), %%rbx\n\t"
"movq %%rbx, 24(%%rax)\n\t"
: : : "rbx" );

then it compiles just fine, outputting expected code.  

When I used gcc to compile either piece, things compile just fine.
I am wondering if I am doing something invalid in my inline assembly, or is the code triggering a bug in the compiler.
I have attached a small piece of C code that triggers this behavior.  Any help is greatly appreciated.

Thanks,
Angelina 

0 Kudos
4 Replies
TimP
Honored Contributor III
592 Views

If you can support the importance of this usage, and verify a problem in a current compiler release, a problem report would be indicated, when the problem report system comes back on line.

0 Kudos
I-Ting_L_
Beginner
592 Views

The sequence of assembly essentially captures the stack pointer, base pointer, and program counter value of a function instance, and store those values into a struct.

asm volatile (
"movq %0, %%rax\n\t"
"movq %%rbp, 16(%%rax)\n\t"
"movq %%rsp, 8(%%rax)\n\t"
"leaq 4(%%rip), %%rbx\n\t"
"movq %%rbx, 24(%%rax)\n\t"
: : "g" (frame) : "rax", "rbx" );

The program counter is used by another thread to resume the function instance, at the program point right after the assembly sequence.  (Hence it's storing %rip + 4).  A possible work-around is to write the assembly sequence as the following:

asm volatile (
"movq %0, %%rax\n\t"
"movq %%rbp, 16(%%rax)\n\t"
"movq %%rsp, 8(%%rax)\n\t"
: : "g" (frame) : "rax", "rbx" );

asm volatile ("leaq 4(%%rip), %%rbx\n\t"
"movq %%rbx, %0\n\t" : "=g"(frame->rip) : : "rax", "rbx");

but the problem is, it's no longer clear that %rip+4 is the right value to store in the frame, because I don't know for sure how many instructions this sequence ends up generating.  I can look at the assembly output (right now it's just one instruction), but it's rather fragile.  If the compiler version changes or different set of compiler flags are used, there is no guarantee that the as the last instruction "movq %%rbx, %0" will be generated the same way.

Is there another work-around that you can suggest?

Thanks,
Angelina

0 Kudos
jimdempseyatthecove
Honored Contributor III
592 Views

Untested code:

[cpp]
asm volatile (
            "movq %0, %%rax\n\t"
            "movq %%rbp, 16(%%rax)\n\t"
            "movq %%rsp, 8(%%rax)\n\t"
            "movq %%rip, %%rbx\n\t"
            "leaq 8(%%rbx), %%rbx\n\t"
            "movq %%rbx, 24(%%rax)\n\t"
            : : "g" (frame) : "rax", "rbx" );
[/cpp]

Jim Dempsey

0 Kudos
I-Ting_L_
Beginner
592 Views

Thanks!  That seems to work (compiles correct at least).
I don't know why I had the impression that one can't simply do a movq on %rip, but apparently I was mistaken.

Thanks,
Angelina 

0 Kudos
Reply