[SOLVED] Error building project with nested function as parameter in GCC

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • [SOLVED] Error building project with nested function as parameter in GCC

    Good afternoon! I am developing a microcontroller project on ARM Cortex-M4, GCC compiler (Release 6.22a). The project includes a library that uses a nested function and is passed as a parameter to another function. When building, the project crashes on this function with the message:

    undefined reference to `__clear_cache'

    I wrote a pseudo-program with a similar implementation, it is built on GCC under Windows, it works, but on GCC ARM the same problem.


    C Source Code

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int func_cb(int (*taskFunc)(int))
    4. {
    5. return taskFunc(5);
    6. }
    7. int func(void) //Error: undefined reference to `__clear_cache'
    8. {
    9. int square (int b) { return b * b; }
    10. return func_cb(square);
    11. }
    12. int main(void)
    13. {
    14. func();
    15. //printf("%d", func());
    16. while (1);
    17. }
    Display All
    Tell me, where could be the problem?
  • You may need to specify that libgcc gets linked in.


    tl;dr details:


    Nested functions (or rather pointers to nested functions) use a technique called "trampolines" which allocate a small bit of code and data that allows a call through a nested function pointer to do some dynamic fixup (in essence set up the local data for the function) before jumping to the actual function's code. See gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html where it says "GCC implements taking the address of a nested function using a technique called trampolines. This technique was described in Lexical Closures for C++ (Thomas M. Breuel, USENIX C++ Conference Proceedings, October 17-21, 1988)"


    Also see fpl.cs.depaul.edu/jriely/447/assets/articles/lexic.pdf


    Anyway, since trampolines are dynamic code, they can require that the instruction cache be flushed, which is handled by the libgcc function `__clear_cache()` (gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html)


    All that said, I'd suggest avoiding nested functions if possible. They are non-standard, easy to misuse, and rarely necessary.
  • Good afternoon!
    I completely agree that it is better not to use nested functions, unfortunately this is part of the library.
    Please tell me which Linker Options is needed to connect libgcc?
  • From gcc.gnu.org/onlinedocs/gcc/Link-Options.html:


    Source Code

    1. -shared-libgcc
    2. -static-libgcc
    3. On systems that provide libgcc as a shared library, these options force the use of either the shared or static version, respectively. If no shared version of libgcc was built when the compiler was configured, these options have no effect.
    4. There are several situations in which an application should use the shared libgcc instead of the static version. The most common of these is when the application wishes to throw and catch exceptions across different shared libraries. In that case, each of the libraries as well as the application itself should use the shared libgcc.
    5. Therefore, the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable, because C++ programs typically use exceptions, so this is the right thing to do.
    6. If, instead, you use the GCC driver to create shared libraries, you may find that they are not always linked with the shared libgcc. If GCC finds, at its configuration time, that you have a non-GNU linker or a GNU linker that does not support option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version of libgcc, linking with the static version of libgcc by default. This allows exceptions to propagate through such shared libraries, without incurring relocation costs at library load time.
    7. However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using the option -shared-libgcc, such that it is linked with the shared libgcc.
    Display All

    You might want to post the details of the options you are currently using (copy/paste the linker command line being used by the IDE) as there might be interactions.

    Do a search for "libgcc" on the linked web page for other details that might be important.

    This information might also be helpful in understanding what the GNU linker is doing:

    stackoverflow.com/a/11481258/12711

    > The `-v` option to `gcc` will cause it to dump information about the default options it will use including the library paths and default libraries and object files that will be linked in.
    >
    > If you give the `-Wl,--verbose` option, gcc will pass the `--verbose` to the linker which will dump exactly where it's looking for libraries, including both failed and successful searches.
    >
    > Combine both options, and you'll see exactly what libraries are linked in, and why they're being linked in.
    >
    > gcc -v foo.c -Wl,--verbose

    The post was edited 1 time, last by mwb1100 ().