So here it is, my first blog post!
What is it going to be about? (drum roll….) inline assembly!
Why would you ever need that? Because it can be handy, for performance or security reasons, to write code at the assembly level. But it can also be quite cumbersome if you want to write whole functions in separate assembly code files (.S). That’s why I’m going to give you a few useful references and examples for writing inline assembly in C or C++.
First, here is some documentation from GCC about it: https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html#Using-Assembly-Language-with-C.
I used it today on an Android project compiled with clang, so my examples will be for both ARM (EABI, 32bits) and i386 on that platform.
To illustrate the subject, our goal will be to write assembly code equivalent to the _exit(int) function. This function uses a system call behind the scene.
System calls are handled by the kernel, and work either with dedicated opcodes or with interrupts. You can find details about the different opcodes and the registers that should be used to pass the parameters and retrieve the return value here (or from man syscall).
Now, we have to know which syscall to make to exit our program. This usually depends on the platform, and you can find here a list of values for Android. For exit, that will be “1” and we can see that it takes one parameter: the exit code.
Here is how to write it in asm:
register int sys_type asm("r7") = 1; register int res asm("r0") = 0; register int arg asm("r0") = 0; asm volatile ("swi 0x0\n" : "=r"(res) : "r"(arg), "r"(sys_type) : "r0", "r7");
- register [variable type] [variable name] asm(“[register]“) = [value] is used to assign values to a specific register
- “=r”(res) is not really useful for the exit syscall, but for other ones, it would be where the return value is stored. “r” is to tell GCC/clang that the result is stored in a regular register, “=” means it is writable only. This first group of registers after the first colon is where we list outputs.
- the “r”(arg), “r” (sys_type) (after the second colon) is the list of input variables. Again, “r” means it’s using regular registers.
- the last part, after the last colon, is the list of clobbered registers, to tell GCC/clang that they may have been modified by the assembly code.
And now, the equivalent for x86:
register int sys_type asm("eax") = 1; register int res asm("eax") = 0; register int arg asm("ebx") = 0; asm volatile ("int $0x80" : "=a"(res) : "b"(arg), "a"(sys_type) : "eax", "ebx");
On x86 processors, syscall is sent using an interrupt with value 0x80, but everything else is quite similar. You can note that in both cases, the assembly is equivalent to calling exit(0) because the arg variable is set to 0.
That’s about it for today 🙂 Enjoy!