0

I am trying to create wrapper functions around functions provided by the RTOS. In the wrapper function I use inline assembly in order to call software interrupt instruction (SVC) so that processor jumps to the SWI handler which further calls the actual OS function by first extracting the SWI number and then indexing into the SWI table using that number.

The prototype of wrapper function is exactly same as OS function so that all the arguments passed to the wrapper function are forwarded to the OS function exactly in the same order. This is all simple when function has less than or equal to four arguments and hence are passed through registers R0-R3. Something like this :

std::uint32_t wrapper_function(std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, std::uint32_t a4)
{
    std::uint32_t ret {};

    __asm volatile(
        "SVC 0x05"
        : "=r" (ret)
        : "r" (a1), "r" (a2), "r" (a3), "r" (a4)
        : "r14");

    return ret;
}

But when function has more than 4 arguments and since all arguments after the fourth are passed through stack, how to forward those arguments?

I am using ARM Compiler 6.6 (ARM Clang 6.6) and the system I am working on has ARM Cortex R5 processor.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Related: https://stackoverflow.com/questions/37358451/arm-inline-asm-exit-system-call-with-value-read-from-memory – Nate Eldredge Nov 08 '20 at 22:43
  • 1
    It's a bit trickier than that. What you have is not even safe because the compiler does not promise to leave the arguments in the registers where they arrived. I think the only way to force the compiler to put certain values into certain registers is with local register variables as in the link above. – Nate Eldredge Nov 08 '20 at 23:15
  • Also, I presume the system call leaves its return value in a particular register, but you haven't said which one, and you can't be assured that the compiler will assign `ret` to that register. – Nate Eldredge Nov 09 '20 at 00:25
  • Something like [this](https://godbolt.org/z/9fnh37) seems to work. – Nate Eldredge Nov 09 '20 at 00:34
  • @NateEldredge Thanks for suggesting some ways. The solution you provided in the last comment wouldn't work because as per the [AAPCS](https://web.eecs.umich.edu/~prabal/teaching/resources/eecs373/ARM-AAPCS-EABI-v2.08.pdf) (ARM Architecture Procedure Call Standard) only first four arguments can be passed through registers (R0-R3). The remaining arguments have to be passed through stack. – Aniruddha Patel Nov 09 '20 at 19:27
  • Yes you are right about return value being passed to the caller through registers. As per AAPCS, return value is always passed back to the caller through register R0 (and R1, if size of return value is more than 32 bits). Compiler doesn't need to assign value of `R0` to variable `ret` here. It is just to tell compiler to assign value of `R0` later to the variable where the return value of `wrapper_function` is stored. e.g. `std::uint32_t x {wrapper_function(a, b, c, d)};` (Here value in register `R0` will be stored in x). – Aniruddha Patel Nov 09 '20 at 19:36
  • So, are you saying your system call also follows AAPCS, with arguments beyond 4 passed on the stack? This is not the case for all OS's, e.g. Linux passes all 6 arguments in registers. If that's really the case, and the registers and stack for the system call should be exactly as passed to the function, then maybe you don't want extended asm at all, but rather a "naked" assembly function consisting only of `svc 0x05 ; bx lr`. – Nate Eldredge Nov 09 '20 at 23:25
  • Yes, my system call also follows the AAPCS standard and that is the reason I want to pass first four arguments through registers r0 to r3 and the remaining through stack. The reason I am writing function using inline assembly is actually to avoid part of passing arguments through stack by myself and rather let the compiler handle that. – Aniruddha Patel Nov 10 '20 at 07:23

0 Answers0