4

I am trying to let the inline assembler copy some values into specific registers but it only complains. This is a short version of the code that will trigger the error:

asm("" :: "r0" (value));
asm("" :: "a1" (value));

Both lines will trigger:

Error: matching constraint references invalid operand number

So how do I specify the register to take directly? I know i could introduce names for the values and then copy them by my own but I would like to avoid this as this code would be shorter and more readable.

Why I am asking Currently I am working on some syscalls. I want to use a syscall macro like this:

#define SYSCALL0(NUMBER) asm("swi #" STRINGIFY(NUMBER));
#define SYSCALL1(NUMBER, A) asm("swi #" STRINGIFY(NUMBER) :: "r0"(A));
#define SYSCALL2(NUMBER, A, B) asm("swi #" STRINGIFY(NUMBER) :: "r0"(A), "r1"(B));
...

As you can see this fits neatly on on line. Of course I could do something like:

#define SYSCALL1(NUMBER, A) register type R0 asm("r0") = A;
                            SYSCALL0(NUMBER)

but then I would have to convert A to type to get no type errors or give type correctly everytime I use the macro in different functions.

  • Possible duplicate of [How to specify an individual register as constraint in ARM GCC inline assembly?](https://stackoverflow.com/questions/3929442/how-to-specify-an-individual-register-as-constraint-in-arm-gcc-inline-assembly) – Ciro Santilli Feb 23 '19 at 19:00

1 Answers1

2

With GCC, there is a shortcut:

register long r0 asm ("r0");

Then r0 "aliases" that register.

Combine that with a statement expression, and you can even get r0 as a "return value".

#define SYSCALL1(NUMBER,A) ({\
  register long r0 asm("r0") = (long) (A); \
  asm("swi #" STRINGIFY(NUMBER) : "=r"(r0) : "r"(r0) : "memory"); \
  r0; })

(I have no idea if the clobber is legitimate or not, the uClibc syscall implementation has that though.)

See extended assembly and local reg vars.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • Yes that one I knew but I do not like the long syntax. I will update my question to show my motivation. – Nobody moving away from SE May 31 '12 at 10:36
  • Aren't all the registers you deal with of the same "C type" (long)? – Mat May 31 '12 at 10:48
  • The registers are of this type but the variables that come in can have arbitrary types (e.g. int, char*, void(fn*)(void), ...) so I would have to do a cast every time. It is not that it is impossible but it is really ugly. – Nobody moving away from SE May 31 '12 at 11:08
  • Do the cast in the macro if you really want that. Updated. – Mat May 31 '12 at 11:21
  • Well I meant the cast in the macro but I see that there is no way around it. Thank your for your advices, I did not know about those statement expressions, so I will have a look at them. – Nobody moving away from SE May 31 '12 at 11:28
  • You could also just use a static inline function to get the arguments into the right registers. – R.. GitHub STOP HELPING ICE May 31 '12 at 12:20
  • @R.. In this case the advantage of the inline function over the macro (type safetiness) is overkill. I **need** to cast away the types, so using an inline function would result in more casts that I would have to write. – Nobody moving away from SE May 31 '12 at 18:14
  • You can wrap the inline function in a macro that casts away the types. I mention this because that's (roughly) how my syscall macros on musl work. There's an outer variadic macro `__syscall` that calls the right `__syscallN` function (static inline) with all of the arguments cast to `long`, and then the static inline function is responsible for putting the arguments in the right registers and making the syscall. – R.. GitHub STOP HELPING ICE Jun 01 '12 at 00:01
  • See http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=blob;f=src/internal/syscall.h and http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=blob;f=arch/x86_64/bits/syscall.h for an example of what I'm talking about. – R.. GitHub STOP HELPING ICE Jun 01 '12 at 00:03