user3387106
user3387106

Reputation: 33

non-ASM statement in naked function

I am trying to create a class containing custom prologue/epilogues that shall be used by methods of other "consumer" classes.

It should look like the following example. (Keep in mind that these example prologue/epilogue bodies are just placeholders for illustration purposes. Surely they are going to be written in pure assembly)

class foo
{
    public:

    static inline void prologue(void) __attribute__ ((always_inline))
    {
        asm("nop");
    }
    

    static inline void epilogue(void) __attribute__ ((always_inline))
    {
        asm("nop");
    }

};

Now, in "consumer" classes that contain methods using these custom prologue/epilogues, I use the naked attribute like bellow. (Keep in mind this example method body structure is what matters. More code shall be placed between the prologue/epilogue but is not necessary for this illustration)

class bar
{
    public:
    static void method()  __attribute__ ((naked))
    {
        foo::prologue();
        //more cpp instructions shall go here
        foo::epilogue();
    }
};

The problem I am facing is that clang compiler does not allow calling standard Cpp code like foo::prologue() in naked functions and returns the following error

<source>:23:9: error: non-ASM statement in naked function is not supported
   23 |         foo::prologue();
      |         ^

Interestingly enough GCC seems to allows this.

Am I missing something? Is there any alternative elegant way to do this?

godbolt test can be found here: https://godbolt.org/z/YfnvfEM3f

Upvotes: 1

Views: 123

Answers (1)

midekyy
midekyy

Reputation: 11

By nature, naked function doesn't allow C++ statement because you don't have any setups for stack, registers or addresses.

For a workaround, you can call function as extern C symbols for ARM instruction which you can pass in your ASM.inside of your naked function.

class foo {
public:
    static inline void prologue(void) __attribute__((always_inline)) {
        asm("nop");
    }

    static inline void epilogue(void) __attribute__((always_inline)) {
        asm("nop");
    }
};

extern "C" void foo_prologue_wrapper() {
    foo::prologue();
}

extern "C" void foo_epilogue_wrapper() {
    foo::epilogue();
}

extern "C" void foo_otherfunctioncall(){
    //code the rest here
    return;
}

class bar {
public:
    static void method() __attribute__((naked)) {
        asm volatile(
            "bl foo_prologue_wrapper\n"  
            "bl foo_otherfunctioncall\n"
            "bl foo_epilogue_wrapper\n"  
            "ret\n"                      
        );
    }
};

int main(void) {
    bar::method();
    return 0;
}

With this, you should be able to access your C++ inside of the "foo_otherfunctioncall" function.

#include <vector>

extern "C" void foo_otherfunctioncall(){
    std::vector<int> a;
    return;
}

It does compile into this :

foo_prologue_wrapper:
        nop
        ret

foo_epilogue_wrapper:
        nop
        ret

foo_otherfunctioncall:
        sub     sp, sp, #48
        stp     x29, x30, [sp, #32]
        add     x29, sp, #32
        add     x0, sp, #8
        str     x0, [sp]
        bl      std::vector<int, std::allocator<int>>::vector() [base object constructor]
        ldr     x0, [sp]
        bl      std::vector<int, std::allocator<int>>::~vector() [base object destructor]
        ldp     x29, x30, [sp, #32]
        add     sp, sp, #48
        ret

main:
        sub     sp, sp, #32
        stp     x29, x30, [sp, #16]
        add     x29, sp, #16
        mov     w8, wzr
        str     w8, [sp, #8]
        stur    wzr, [x29, #-4]
        bl      bar::method()
        ldr     w0, [sp, #8]
        ldp     x29, x30, [sp, #16]
        add     sp, sp, #32
        ret

bar::method():
        bl      foo_prologue_wrapper
        bl      foo_otherfunctioncall
        bl      foo_epilogue_wrapper
        ret

__clang_call_terminate:
        stp     x29, x30, [sp, #-16]!
        mov     x29, sp
        bl      __cxa_begin_catch
        bl      std::terminate()

DW.ref.__gxx_personality_v0:
        .xword  __gxx_personality_v0

Upvotes: 0

Related Questions