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;
}

Parents Reply Children
  • Thanks Einar for your prompt reply!
    As I understood, the Code And Data Relocation example you provided is actually allocating the function in the Flash by the liner and calling it in the main file.

    I attempt to call the function directly from RAM buffers (copying the machine code of function) in the runtime without changing the Liner sections architecture. Do you think we have to use the position independent code for the compiler itself to specify the location where I copy the function in RAM on the basis of nRF5280 DK?

    Thanks again for your support!

  • Hi,

    I am sorry, the example I linked to was a bad one. You can refer to zephyr/tests/application_development/code_relocation. This demonstrates relocation in different wayt, includign to RAM. It runs out of the box on the nRF52840.

    There is no need for position independent code, the point is that you instruct the build system to place the function in RAM (it is then copied there automatically during startup).

  • Keep it simple, this code works without using a position independent code setting. Keep in mind the least significant bit of the address has a meaning regarding ARM Cortex-M4 Thumb instructions vs ARM and so that has to be handled in the copy. Often a manual copy makes code easier to debug.

    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 *pRAM  = 0UL;
    uint32_t *pCode = 0UL;
    
    static void RamFuncTest(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        // Copy the machine code of func into func_buffer
        pRAM=func_buffer;
        pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/4; i++) *pRAM++ = *pCode++;
        // Create a function pointer and cast the buffer address to it
        func_ptr fp = (func_ptr)func_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 thanks for your help and advice!

    Unfortunately it met the same reboot issue after I flashed it on the nRF52840 DK (code attached)
    Can you please tell me which device you have tested and flashed it on?

    #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 *pRAM  = 0UL;
    uint32_t *pCode = 0UL;
    
    static void RamFuncTest(void) {
        typedef uint8_t (*func_ptr)(uint8_t);
        // Copy the machine code of func into func_buffer
        pRAM=func_buffer;
        pCode=(uint32_t *)((uint32_t)&ram_func & 0xFFFFFFFEUL);
        for (uint32_t i=0UL; i<sizeof(func_buffer)/4; i++) 
        {
          *pRAM++ = *pCode++;
        }
        // Create a function pointer and cast the buffer address to it
        func_ptr fp = (func_ptr)func_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;
    }
    
    /*---------------------------------------------------------------*/
    int main() {
        printf("start\n\n");
        RamFuncTest();
        return 0;
    }

    Thanks again!

  • 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

Related