Search code examples
c++gccg++avravr-gcc

AVR G++: Executing a function that is past the 128 Kb ROM boundary


AVR g++ has a pointer size of 16 bits. However, my particular chip (the ATMega2560) has 256 KB of RAM. To support this, the compiler automatically generates trampoline sections in the same section of ROM as the current executing code that then contains the extended assembly code to jump into high memory or back. In order for trampolines to be generated, you must take the address of something that sits in high memory.

In my scenario, I have a bootloader that I have written sitting in high memory. The application code needs to be able to call a function in the bootloader. I know the address of this function and need to be able to directly address it by hard-coding the address in my code.

How can I get the compiler/linker to generate the appropriate trampoline for an arbitrary address?


Solution

  • Compiler and linker will only generate trampoline code when the far address is a symbolic address rather than a literal constant number already in code. something like (assuming the address you want to jump to is 0x20000).

    extern void (*farfun)() = 0x20000;
    
    farfun ();
    

    Will definitely not work, it doesn't cause the linker to do anything because the address is already resolved.

    You should be able to inject the symbol address in the linker command line like so:

    extern void farfun ();
    
    farfun ();
    

    compiling "normally" and linking with

    -Wl,--defsym,farfun=0x20000
    

    I think it's clear that you need to make sure yourself that something sensible sits at farfun.

    You will most probably also need --relax.

    EDIT

    Never tried this myself, but maybe:

    You could probably try to store the function address in a table in high memory and declare it like this:

    extern void (*farfunctable [10])();
    
    (farfunctable [0])();
    

    and use the very same linker command to resolve the external symbol (now your table at 0x20000 (in the bootloader) needs to look like this:

    extern void func1();
    extern void func2();
    
    void ((*farfunctab [10])() = {
       func1,
       func2,....
    };
    

    I would recommend to put func1() ... func10() in a different module from farfunctab in order to make the linker know it has to generate trampolins.