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
  • Hi,

    We do not use position independent code, so copying out a function to a different location will not work. If you want a function to reside in RAM, you need to tell the compiler to place it there (and then all offsets and jumps etc. will be correct for that position). You can read more about how ths is done under Code And Data Relocation.

  • 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!

  • 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.

  • Thanks!

    Please check my debugging at your code, it didn't return the data_out2 value, seems that the program didn't execute the "uint8_t data_out2 = fp(3);"

    That's weird, do you think it results from the different device we used?

  • I just tested same code on a nRF52840 Feather, doesn't work with optimisation set to High but works fine with optimisation none. Your capture shows too much optimisation :-)

  • I just give the code on the adafruit feather nrf52840 by the platform io.
    FW didn't load correctly that we can't see the COM port if RamFuncTestSub() executes the uint8_t data_out2 = fp(3);
    It gives the right answer if I comment the uint8_t data_out2 = fp(3); and return data_out1.

    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_out1;
    }
    
    void setup() {
      Serial.begin(115200);
    }
    
    void loop() {
      uint8_t result = RamFuncTestSub();
      Serial.printf("result = %d\n", result);
      delay(100);
    }

    Can you please let me know what IDE and env you used on feather nrf52840?

Reply
  • I just give the code on the adafruit feather nrf52840 by the platform io.
    FW didn't load correctly that we can't see the COM port if RamFuncTestSub() executes the uint8_t data_out2 = fp(3);
    It gives the right answer if I comment the uint8_t data_out2 = fp(3); and return data_out1.

    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_out1;
    }
    
    void setup() {
      Serial.begin(115200);
    }
    
    void loop() {
      uint8_t result = RamFuncTestSub();
      Serial.printf("result = %d\n", result);
      delay(100);
    }

    Can you please let me know what IDE and env you used on feather nrf52840?

Children
Related