8

I am trying to write a small piece of my code in GCC style extended asm (x86-64 target) and am having trouble encoding struct offsets.

I have a struct s with a member size_t a[], a pointer to such a struct and an index both of which are generated within the asm block.

Now I need to address that element in asm

asm (
    "mov %[displ](%[s], %[index], 8), %%rbx"
    : [s] "+r" (s)
    , [index] "+r" (i)
    : "memory", "cc", "rax", "rbx"
);

How can I encode displ into the asm block? Passing offsetof(struct s, a) as an immediate prefixes it with $ and generates invalid assembly.

asm (
    "mov %[displ](%[s], %[index], 8), %%rbx"
    : [s] "+r" (s)
    , [index] "+r" (i)
    : [displ] "i" (offsetof(struct s, a))
    : "memory", "cc", "rax", "rbx"
);
Sergey L.
  • 21,822
  • 5
  • 49
  • 75
  • 1
    Why? What's wrong with `s.a[index]` in the C code? – Bo Persson Nov 06 '12 at 19:16
  • 2
    Because the above is a smaller example and in reality the asm block is large, contains far more instructions around and several jumps. And because this isn't the first occasion where I have needed that effect. – Sergey L. Nov 07 '12 at 01:11
  • Ok, if it is a large block of assembly, I would consider putting that in a separate .asm file and let the C code compute and pass the parameters needed. There is no way you can get the address calculations more efficient in assembly, so to me it seems like a complication we could live without. – Bo Persson Nov 07 '12 at 08:55
  • 1
    Well, the struct is used in both C and asm code, so I need to have the same offsets across both. – Sergey L. Nov 07 '12 at 11:25

2 Answers2

12

It actually is possible, using the %c... operand modifier:

#include <stddef.h>
#include <stdint.h>

struct s
{
  int a, b;
};

int foo (struct s *s, int i)
{
  int r;
  asm (
       "movl %c[displ](%[s],%[index],8), %[r]\n\t"
       : [r] "=r" (r)
       : [s] "r" (s) , [index] "r" ((uintptr_t)i),
         [displ] "e" (offsetof(struct s, b))
       :
       );

  return r;
}

Thanks where thanks is due - found that here. There's a gcc mailing list posting referring to this as well; the keywords there are "output substitution".
The stackoverflow posting What does %c mean in GCC inline assembly code? also has an explanation about %c in particular.

Community
  • 1
  • 1
FrankH.
  • 17,675
  • 3
  • 44
  • 63
2

Your only option is to use Intel syntax. GCC, of course, can generate insn like mov off(base, index, scale), but does this on the level of whole MEM RTL expressions, i.e. not having offset, base, etc like individual operands.

So, Intel syntax, compile the following with gcc -c -masm=intel x.c:

#include <stddef.h>

struct s
{
  int a, b;
};

int foo (struct s *s, int i)
{
  int r;
  asm (
       "mov %[r], dword ptr [%[s]+%[index]*8 + %[displ]] "
       : [r] "=r" (r)
       : [s] "r" (s) , [index] "r" (i),
         [displ] "e" (offsetof(struct s, b))
       :
       );

  return r;
}
chill
  • 16,470
  • 2
  • 40
  • 44
  • I knew about that, but it makes my code incompatible with some device driver includes (which have AT&T style inline asm) that I have in the same file. Yes, I know I can split them thus forfeiting the point of optimised code. – Sergey L. Nov 20 '12 at 18:16
  • 1
    You can switch back and forth between syntax types using `.intel_syntax` and `.att_syntax`. – demonkoryu May 20 '13 at 22:01