Author Topic: memcpy() missing when linking with GCC  (Read 6131 times)

Offline FAQ

  • Newbie
  • *
  • Posts: 27
    • View Profile
memcpy() missing when linking with GCC
« on: August 02, 2012, 10:38:11 PM »
Although memcpy() is not used in a project it sometimes is reported as being missing by the GCC linker. Why is this?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: memcpy() missing when linking with GCC
« Reply #1 on: August 02, 2012, 10:49:45 PM »
Hi

This is to do with the way that GCC (sometimes) works. It depends on settings and also targets whereby GCC sometimes compiles the following code

    case 1:
        {
            const unsigned char array1[] = {2, 1};     // fixed array
            ...
        }


to use memcpy() to put the values 2 and 1 into array1.


In fact the code would like the array array1 to be const (in Flash) but for some reason GCC sometimes still creates the array in SRAM - presumably because array1[] is local to the case (or sub-routine etc.) and so needs to copy the values from Flash to SRAM. The compiler seems to be allowed to use function calls to actually do this copy operation.


In the uTasker project libraries are avoided and there is a uMemcpy() which is generally used – depending on processor and settings it may do it with DMA for improved efficiency.




The first solution is to use a standard library to supply the missing memcpy(). How this is done depends on the environment but is generally fairly straight forward to do, but may cause the code to become a bit larger.

The second solution (in this case) is to add static to any const array (or structs) that are causing memcpy() to be used

Eg.
    case 1:
        {
            static const unsigned char array1[] = {2, 1};     // fixed array
            ...
        }



This avoids the compiler creating the array in SRAM and it simply uses the const array in Flash instead.




A similar problem can arise when the array (or struct) is not declared const but constructed at run time:

unsigned char ucArray[5] = {1,2,3,4,5};  // GCC sometimes uses memcpy to initialise this

This can be worked around by writing it as:

unsigned char ucArray[5];
ucArray[0] = 1;
ucArray[1] = 2;
ucArray[2] = 3;
ucArray[3] = 4;
ucArray[4] = 5; // initialise in code to avoid memcpy() use.


You may find such code in the project which has been written like this to avoid the possible problem.




The third possibility (when not using standard libraries) is to make uMemcpy() and memcpy() equivalent. To do this, the following can be added to types.h:


#define _NO_STANDARD_LIB
#define uMemcpy(x,y,z) memcpy(x,y,z)



In Driver.c the uMemcpy() function however needs to be made conditional on

#if !defined uMemcpy || defined _NO_STANDARD_LIB

rather than #ifndef uMemcpy

so that it is used.



Regards

Mark