1

I've run into a problem while compiling a package around, I am not really a good coder, but I tried fixing it for my self, and it still won't compile. This is the original bit of code.:

#ifdef __GNUC__
asm("and $3, %%ecx;"
"shl $3 ,%%ecx;"
"ror %%cl, %0"
: "=r" (value)
: "r" (value), "c" (address));
#else

The error is .:

GBAinline.h:139: error: impossible register constraint in 'asm' ( ifdef line is 138 )

And this is how I tried to make it look.:

#ifdef __GNUC__
asm ("and $3 %%ecx,shl $3 %%ecx,ror %%cl, %0" : "=r" (value): "r" (value), "c" (address));

#else

Still, it would not work. It's a gba emulator before anyone ask, VBA, and this is part of GBAinline.h . This assembler is making me crazy already.

Edit.: The problem above was handled fine, I just was not paying attention to which compiler I was using. But now I get this error on this bit of code from a header file, I've put it on pastebin, to keep things here a bit more tidy... ( Sorry if this is wrong, i can change that later )

This is the header that has the lines that results in errors.: http://pastebin.com/k3D4cg0d

And this is the C file it refers to.: http://pastebin.com/Ymg1X5dg

This is giving an error like this.:

/var/tmp/cc3zA0lH.s: Assembler messages: /var/tmp/cc3zA0lH.s:69: Error: bad instruction `sw $3,0(r3)',

And so on for the rest of those lines.

Luis
  • 123
  • 1
  • 3
  • 18
  • The original code looks OK to me. What copiler and platform are you on, e.g. what does `gcc -v` output? You need to deal with x86 assembly and [gcc inline assembly constraints](http://gcc.gnu.org/onlinedocs/gcc/Constraints.html) to fully understand this code. – Mackie Messer Dec 07 '11 at 14:15
  • Thanks for the answer Mackie, my gcc is arm-linux, maybe this is the problem, this code is designed for x86, and I didn't notice it. Also, thanks for the link, I will give it a good look. – Luis Dec 07 '11 at 14:30
  • So, I used a x86 compiler, and it worked as a charm! Thanks Mackie, I hadn't paid attention to that. – Luis Dec 07 '11 at 14:37
  • You are welcome. If you really want to dive into inline assembly with gcc and x86 [this guide](http://www.ibm.com/developerworks/linux/library/l-ia/index.html) is a more gentle introduction. – Mackie Messer Dec 07 '11 at 14:58

1 Answers1

1

That inline assembly is buggy:

  1. It uses multi-line strings which effectively concatenate. Without \n all appears on one line. Whether your assembler accepts statements separated by semicolons makes all the difference there ... some may not.
  2. It specifies the same variable as input/output constraint instead of using "+r"(value) as ordinarily suggested for this situation.

Without seeing the rest of the code it's not quite clear why the inline assembly statement looks the way it does; Personally, I'd suggest to write it like:

asm("ror %%cl, %0" : "+r"(value) : "c"((((uintptr_t)address) & 3) << 3)));

because there's little need to do the calculation itself in assembly. The uintptr_t (from <stdint.h>) cast makes this 32/64bit agnostic as well.

Edit:

If you want it for a different CPU but x86 / x64, then it obviously needs to be different ... For ARM (not Thumb2), it'd be:

asm("ROR %0, %0, %1" : "+r"(value) : "r"((((uintptr_t)address) & 3) << 3)));

since that's how the rotate instruction there behaves.

Edit (add reference):

Regarding the operation performed here as such, this blog post gives an interesting perspective - namely, that the compiler is quite likely to create the same output for:

(a >> shift | a << (8 * sizeof(a) - shift))

as for the x86 inline

asm("ror %%cl, %0" : "+r"(a) : "c"(shift))

Testing this:

#include <stdint.h>

int main(int argc, char **argv)
{
    unsigned int shift = (int)((((uintptr_t)argv) & 3) << 3);
    unsigned int a = argc;
#ifdef USE_ASM
    /*
     * Mark the assembly version with a "nop" instruction in output
     */
    asm("nop\n\t"
        "ror        %%cl, %0" : "+r"(a) : "c"(shift));
    return a;
#else
    return (a >> shift | a << (8 * sizeof(a) - shift));
#endif
}

Compile / disassemble it:

$ gcc -DUSE_ASM -O8 -c tf.c; objdump -d tf.o

tf.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 :
   0:   83 e6 03                and    $0x3,%esi
   3:   8d 0c f5 00 00 00 00    lea    0x0(,%rsi,8),%ecx
   a:   90                      nop
   b:   d3 cf                   ror    %cl,%edi
   d:   89 f8                   mov    %edi,%eax
   f:   c3                      retq
$ gcc -O8 -c tf.c; objdump -d tf.o

tf.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 :
   0:   83 e6 03                and    $0x3,%esi
   3:   8d 0c f5 00 00 00 00    lea    0x0(,%rsi,8),%ecx
   a:   d3 cf                   ror    %cl,%edi
   c:   89 f8                   mov    %edi,%eax
   e:   c3                      retq

Ergo, this inline assembly is unnecessary.

FrankH.
  • 17,675
  • 3
  • 44
  • 63
  • 1
    Thanks Frank, but I got other files that were supposed to work under arm. Still it's giving me trouble, with these errors /var/tmp/cc3zA0lH.s: Assembler messages: /var/tmp/cc3zA0lH.s:69: Error: bad instruction `sw $3,0(r3)', what I still believe it's a gcc problem, and not the file's, and it's about 25 lines of errors, my guess it's useless to post all since they are all alike. Sorry for my mess here, I am still trying to understand how posting comments work around, but I am trying. Again, thanks for the answers – Luis Dec 07 '11 at 15:15
  • @Luis: `sw $3,0(r3)` looks like a MIPS instruction, not x86 or ARM. You need to configure your environment correctly... – Mackie Messer Dec 07 '11 at 17:51
  • @Mackie: ack, looks like a cross compile setup problem; Luis, how have you set up your cross environment ? – FrankH. Dec 07 '11 at 18:13
  • @Frank, you mean, on the makefile? it's CC=$(CROSS_COMPILE)gcc ( with proper spaces of course ) Sorry for the delay on answer. @ Mackie, I still need to configure the environment? Thanks both of you, I added more informations on my OP. – Luis Dec 08 '11 at 20:33