Undefined ref to memset

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
legic_1490776
Level 5
Level 5
25 likes received 10 likes received First like received

Using an array initializer in my code caused an undefined reference to memset().

Is there a change to the makefile that can link in the correct library? 

I'm also getting an undefined reference on abs().. is there a math library in the SDK?

0 Likes
1 Solution
asridharan
Employee
Employee
10 comments on KBA 5 comments on KBA First comment on KBA

The math library is not include in the SDK or the ROM. For abs, you should be able to define a macro that does the same.

Using initializers is a bit tricky. Standard functions like memset, memcopy, memmove are available in the ROM, linked in from the ARM tool chain libraries. memset in particular is a special case and unlike the ANSI memset, the ARM implementation has the second and third parameters swapped (see IHI0043C on the ARM website). So if you use spar_utils.h, memset is #defined to map to the ARM library implementation of memset. When you use initializers, the compiler does not know about this mapping and tries to use the standard memset, which is a bit different in the ROM (and the symbol name used the ARM tool chain is different).

You can continue to use memset, memcpy etc and the SDK will map it to the correct (ARM library) implementation in the ROM, but when you want to initialize an array with automatic initialization, I suggest you invoke memset instead of the = {0, } syntax.

View solution in original post

0 Likes
9 Replies
asridharan
Employee
Employee
10 comments on KBA 5 comments on KBA First comment on KBA

The math library is not include in the SDK or the ROM. For abs, you should be able to define a macro that does the same.

Using initializers is a bit tricky. Standard functions like memset, memcopy, memmove are available in the ROM, linked in from the ARM tool chain libraries. memset in particular is a special case and unlike the ANSI memset, the ARM implementation has the second and third parameters swapped (see IHI0043C on the ARM website). So if you use spar_utils.h, memset is #defined to map to the ARM library implementation of memset. When you use initializers, the compiler does not know about this mapping and tries to use the standard memset, which is a bit different in the ROM (and the symbol name used the ARM tool chain is different).

You can continue to use memset, memcpy etc and the SDK will map it to the correct (ARM library) implementation in the ROM, but when you want to initialize an array with automatic initialization, I suggest you invoke memset instead of the = {0, } syntax.

0 Likes

I tried to use const UINT8 array[]... and i am pretty sure it worked.

0 Likes

This issue only affects arrays that are initialized at runtime.

0 Likes
Anonymous
Not applicable

#include "spar_utils.h" will fix the issue.

roger_lu

Including "spar_utils.h" does not seem to fix the problem.

For reference, an example of runtime initialization I was referring to is something like this:

void foo()

{

     UINT8 x[10] = {1,2,3,4,5,6,7,8,9,0};

     ble_tracen(x,10);

}

I think including "spar_utils.h" does not help because the reference to memset or memcpy is created within the compiler itself, and not subject to macro expansion (as arvinds explained above).

Note that this issue does not apply to static or global initializers (i.e. initializers that apply to variables NOT allocated at runtime on the stack), because in these cases the initializer is coded directly into the variable's location in the image and no implicit memcpy is needed.

For example, these two examples work:

void foo()

{

     static UINT8 x[10] = {1,2,3,4,5,6,7,8,9,0};

     ble_tracen(x,10);

}

UINT8 x[10] = {1,2,3,4,5,6,7,8,9,0};

void foo()

{

     ble_tracen(x,10);

}

0 Likes
Anonymous
Not applicable

memset, memcpy needs an include of #include <string.h> (for the prototype).

CARM User's Guide: memset Library Routine
It should be possible to bind the memset, memcpy etc. from ARM Run Time Library again, no need to have it in ROM or linking these functions to ROM code. They should be added directly to your own code, even again, not reusing a memset sitting in ROM (you would need for this anyway a linker reference file, to tell the linker where this function is in ROM - much harder to reuse code from a ROM).
The only question: when linking your own FW code, running in SRAM (not using anything from ROM) - are there the right linker flags, to make sure the standard ARM runtime LIB is found and used? If not (linker command line options missing) - you have unresolved symbols. It should be already there, to have an ARM EABI runtime lib used on build: otherwise some intrinsic functions used by compiler (e.g. often also stuff for mult, some more complex and larger data types) would not work anyway.

ARM Information Center
But linking again memset, memcpy to your own code should work in general, not a problem with the standard ARM runtime LIB.
Option: if missing symbol, you can implement your own memset and make the linker happy.

I am not sure what happens if you do:

static UINT8 x[10] = {1,2,3,4,5,6,7,8,9,0};
If it is a local (auto) variable (on stack), executable code is needed to do. It might happen that the compiler generates code which uses memset. Some compilers don't do it, they iterate over a hidden list, executing code and write the values when entering the function. But potentially, an intrinsic function from a runtime lib is used and needed.
But:
Actually, if you use static in front of such variable - it is not a local (not auto, not on stack) anymore. It becomes a variable on the .bss data section. There is no need for memset. Such global or static variable is generated as a data array which is part of your image, part of your BIN file. If image is loaded, also such global and static data arrays are loaded by just writing all into memory, no runtime code needed (except on the startup, when booting from ROM: moving data from ROM to SRAM first).

And as mentioned already: ABS is just a macro.
You need also a H file, I think you need: #include <stdlib.h>

It should work, assuming the ARM standard H files such as <stdio.h>, <string.h>, <stdlib.h> are found by compiler (they should).

Otherwise, you can implement your own ABS, e.g. see here:

abs() - C Library Function Example

http://www.geeksforgeeks.org/compute-the-integer-absolute-value-abs-without-branching/

Optimized abs function - strchr.com

0 Likes

In my case, I solved the problem by writing explicit code to initialize the structure or array (using the ROM version of memset/memcpy etc.)  This works, although it is slightly more cumbersome.

If I understood what you are saying above, another alternative would be to add the arm memset/memcpy as an additional library to link on the command line?  I preferred not to do this however as my code space was very constrained and I did not want to include the extra function.

Anonymous
Not applicable

The following code works in my side. (WICED Smart 2.1.1)

void foo(void)

{

    UINT8 x[5] ={0, 1, 2, 3, 4};

    ble_tracen(x, 5);

0 Likes

Thanks.. I guess this bug was fixed in the 2.0 SDK.. Unfortunately I am stuck using the 1.x SDK because our device uses the 20732.

0 Likes