Problem
I want to execute the exit system call in ARM using inline assembly on a Linux Android device, and I want the exit value to be read from a location in memory.
Example
Without giving this extra argument, a macro for the call looks like:
#define ASM_EXIT() __asm__("mov %r0, #1\n\t" \
"mov %r7, #1\n\t" \
"swi #0")
This works well. To accept an argument, I adjust it to:
#define ASM_EXIT(var) __asm__("mov %r0, %0\n\t" \
"mov %r7, #1\n\t" \
"swi #0" \
: \
: "r"(var))
and I call it using:
#define GET_STATUS() (*(int*)(some_address)) //gets an integer from an address
ASM_EXIT(GET_STATUS());
Error
invalid 'asm': operand number out of range
I can't explain why I get this error, as I use one input variable in the above snippet (%0/var). Also, I have tried with a regular variable, and still got the same error.
Extended-asm syntax requires writing
%%
to get a single%
in the asm output. e.g. for x86:%r7
is treatingr7
as an operand number. As commenters have pointed out, just omit the%
s, because you don't need them for ARM, even with GNUas
.Unfortunately, there doesn't seem to be a way to request input operands in specific registers on ARM, the way you can for x86. (e.g.
"a"
constraint meanseax
specifically).You can use
register int var asm ("r7")
to force a var to use a specific register, and then use an"r"
constraint and assume it will be in that register. I'm not sure this is always safe, or a good idea, but it appears to work even after inlining. @Jeremy comments that this technique was recommended by the GCC team.I did get some efficient code generated, which avoids wasting an instruction on a reg-reg move:
See it on the Godbolt Compiler Explorer:
Since you always want the value read from memory, you could use an
"m"
constraint and include aldr
in your inline asm. Then you wouldn't need theregister int var asm("r0")
trick to avoid a wastedmov
for that operand.The
mov r7, #1
might not always be needed either, which is why I used theregister asm()
syntax for it, too. If gcc wants a1
constant in a register somewhere else in a function, it can do it inr7
so it's already there for the ASM_EXIT.Any time the first or last instructions of a GNU C inline asm statement are
mov
instructions, there's probably a way to remove them with better constraints.