Copy function to RAM and call it with function pointer

Hello,

I am trying to copy the function to RAM and then call it using a function pointer like below:

It forced a system restart and it should have encountered an error.

Can you please help me deal with it? Thanks in advance!

uint8_t ram_func(uint8_t data_in)
{
  data_in++;
  return data_in;
}
/*---------------------------------------------------------------*/
int main() {
    typedef uint8_t (*func_ptr)(uint8_t);
    uint8_t func_buffer[256];
    memset(func_buffer, 0, 256);
    // Copy the machine code of func into func_buffer
    memcpy(&func_buffer, (uint8_t*)ram_func, 255);

    // Create a function pointer and cast the buffer address to it
    func_ptr fp = (func_ptr)func_buffer;

    // Call the function through the function pointer
    uint8_t data_out = fp(3);

    printf("Result = %d\n", data_out);
    return 0;
}

  • I put a breakpoint on the call to fp() on line 31 then clicked the ASM window and single-stepped through the assembler using "into" button and it works ok with data_out2 set to 4 on return. This is on a nRF52832 with no other code such as bootloader or softdevice. Maybe try using the debugger in the same way; if I get time I'll try this on an nRF52840.

    Edit: Works fine single-stepping through asm window but running to a breakpoint placed after the fp() call generates a hard fault, not sure what the difference is. I'll try to find time to look at this

  • Ah, I forgot to use the lsbit Thumb Mode on the return; here's the fixed code which runs even without stepping:

    uint8_t ram_func(uint8_t data_in)
    {
      data_in++;
      return data_in;
    }
    uint8_t data_out1 = 0;
    uint8_t data_out2 = 0;
    uint32_t func_buffer[64];
    
    static void RamFuncTest(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        // Copy the machine code of func into func_buffer
        uint32_t *pRAM=func_buffer;
        uint32_t *pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/sizeof(func_buffer[0]); i++)
        {
          *pRAM++ = *pCode++;
        }
        // Create a function pointer and cast the buffer address to it, remember Thumb Mode
        uint32_t *pfunc_buffer = (uint32_t*)(((uint32_t)func_buffer) | 0x00000001UL);
        func_ptr fp = (func_ptr)(pfunc_buffer);
        // Test code function to verify that works
        data_out1 = ram_func(2);
        // Call the function through the function pointer
        data_out2 = fp(3);
        printf("Result = %d\n", data_out2);
        return 0;
    }

  • Really appreciate your code and support!
    Same reboot for the code below:

    #include <stdint.h>
    #include <stddef.h>
    #include <string.h>
    
    uint8_t ram_func(uint8_t data_in)
    {
      data_in++;
      return data_in;
    }
    uint8_t data_out1 = 0;
    uint8_t data_out2 = 0;
    uint32_t func_buffer[64];
    uint32_t *pfunc_buffer = func_buffer;
    
    static void RamFuncTest(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        // Copy the machine code of func into func_buffer
        uint32_t *pRAM=func_buffer;
        uint32_t *pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/sizeof(func_buffer[0]); i++)
        {
          *pRAM++ = *pCode++;
        }
        // Create a function pointer and cast the buffer address to it, remember Thumb Mode
        pfunc_buffer = (uint32_t*)(((uint32_t)pfunc_buffer) | 0x00000001UL);
        func_ptr fp = (func_ptr)(pfunc_buffer);
        // Test code function to verify that works
        data_out1 = ram_func(2);
        // Call the function through the function pointer
        data_out2 = fp(3);
        printf("Result = %d\n", data_out2);
    }
    
    /*---------------------------------------------------------------*/
    int main() {
        printf("start\n\n");
        RamFuncTest();
        return 0;
    }

    Did I miss something?

  • Just loaded your code, works ok here but I comment out the printf(). I moved some of the definitions back into the function, edited above, but it works with or without that. Try a breakpoint on the printf() and see if you can get there with data_out2 correct

    This is what runs ok:

    uint8_t ram_func(uint8_t data_in)
    {
      data_in++;
      return data_in;
    }
    uint8_t data_out1 = 0;
    uint8_t data_out2 = 0;
    uint32_t func_buffer[64];
    static void RamFuncTestSub(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        // Copy the machine code of func into func_buffer
        uint32_t *pRAM=func_buffer;
        uint32_t *pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/sizeof(func_buffer[0]); i++)
        {
          *pRAM++ = *pCode++;
        }
        // Create a function pointer and cast the buffer address to it, remember Thumb Mode
        uint32_t *pfunc_buffer = (uint32_t*)(((uint32_t)func_buffer) | 0x00000001UL);
        func_ptr fp = (func_ptr)pfunc_buffer;
        // Test code function to verify that works
        data_out1 = ram_func(2);
        // Call the function through the function pointer
        data_out2 = fp(3);
    //    while(1) ;
    //    printf("Result = %d\n", data_out2);
    //    return 0;
    }
    static void RamFuncTest(void) {
        //printf("start\n\n");
        RamFuncTestSub();
        while(1) ;
    }

  • Same code, but also returning a value on stack in case something was amiss there; seems ok:

    uint8_t ram_func(uint8_t data_in)
    {
      data_in++;
      return data_in;
    }
    static uint8_t RamFuncTestSub(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        uint32_t func_buffer[64];
        // Copy the machine code of func into func_buffer
        uint32_t *pRAM=func_buffer;
        uint32_t *pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/sizeof(func_buffer[0]); i++)
        {
          *pRAM++ = *pCode++;
        }
        // Create a function pointer and cast the buffer address to it, remember Thumb Mode
        uint32_t *pfunc_buffer = (uint32_t*)(((uint32_t)func_buffer) | 0x00000001UL);
        func_ptr fp = (func_ptr)pfunc_buffer;
        // Test code function to verify that works
        uint8_t data_out1 = ram_func(2);
        // Call the function through the function pointer
        uint8_t data_out2 = fp(3);
        return data_out2;
    }
    static void RamFuncTest(void) {
        //printf("start\n\n");
        uint8_t result = RamFuncTestSub();
        //printf("Result = %d\n", result);
        while(1) ;
    }

    I even tested with buffer on stack; all ok.

Related