Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide an implementation of memcpy

Tags:

c

gcc

memset

I am trying to write some bare metal code with a memset-style loop in it:

for (int i = 0; i < N; ++i) {
  arr[i] = 0;
}

It is compiled with GCC and GCC is smart enough to turn that into a call to memset(). Unfortunately because it's bare metal I have no memset() (normally in libc) so I get a link error.

 undefined reference to `memset'

It seems like the optimisation that does this transformation is -ftree-loop-distribute-patterns:

Perform loop distribution of patterns that can be code generated with calls to a library. This flag is enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile.

So one person's solution was to just lower the optimisation level. Not very satisfying.

I also found this really helpful page that explains that -ffreestanding is not enough to get GCC not to do this, and there's basically no option but to provide your own implementations of memcpy, memmove, memset and memcmp. I'm happy to do that, but how?

If I just write memset the compiler will detect the loop inside it and transform it into a call to memset! In fact in the code provided by the CPU vendor I'm using I actually found this comment:

/*
// This is commented out because the assembly code that the compiler generates appears to be
// wrong.  The code would recursively call the memset function and eventually overruns the
// stack space.
void * memset(void *dest, int ch, size_t count)
...

So I assume that is the issue they ran into.

How do I supply a C implementation of memset without the compiler optimising it to a call to itself and without disabling that optimisation?

like image 807
Timmmm Avatar asked Apr 22 '21 09:04

Timmmm


People also ask

How do you declare memcpy in C++?

The prototype of memcpy() as defined in the cstring header file is: void* memcpy(void* dest, const void* src,size_t count); When we call this function, it copies count bytes from the memory location pointed to by src to the memory location pointed to by dest .

How memcpy function works?

memcpy() function in C/C++ The function memcpy() is used to copy a memory block from one location to another. One is source and another is destination pointed by the pointer. This is declared in “string. h” header file in C language.

How is Memmove implemented?

The memmove function copies n characters from the source to the destination object. In memmove before copying the characters from source to destination object first copied the n character from source to the temporary array, after that copy the n character from the temporary array to the destination object.

Which library must you include to use the memcpy function?

C library function - memcpy() The C library function void *memcpy(void *dest, const void *src, size_t n) copies n characters from memory area src to memory area dest.

How to implement memcpy () function in C?

Here we will see how to implement memcpy () function in C. The memcpy () function is used to copy a block of data from one location to another. The syntax of the memcpy () is like below − To make our own memcpy, we have to typecast the given address to char*, then copy data from source to destination byte by byte.

What is the difference between memcpy () and SRC ()?

Following is the declaration for memcpy () function. dest − This is pointer to the destination array where the content is to be copied, type-casted to a pointer of type void*. src − This is pointer to the source of data to be copied, type-casted to a pointer of type void*.

Why does glibc use memcpy?

But glibc usually uses some clever implementations in assembly code. memcpy calls are usually inlined. On x86, the code checks if the size parameter is a literal multiple of 2 or a multiple of 4 (using gcc builtins functions) and uses a loop with movl instruction (copy 4 bytes) otherwise it calls the general case.

What happens if the source and destination objects overlap in memcpy?

If the source and destination objects overlap, the behavior of memcpy is undefined. In memcpy, we need to pass the address of the source and destination buffer and the number of bytes (n) that you want to copy. Sometimes peoples require to create a custom memcpy function for their project.


Video Answer


2 Answers

Aha I checked in the glibc code and there's a inhibit_loop_to_libcall modifier which sounds like it should do this. It is defined like this:

/* Add the compiler optimization to inhibit loop transformation to library
   calls.  This is used to avoid recursive calls in memset and memmove
   default implementations.  */
#ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL
# define inhibit_loop_to_libcall \
    __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
#else
# define inhibit_loop_to_libcall
#endif
like image 92
Timmmm Avatar answered Oct 19 '22 04:10

Timmmm


You mention in your question:

It seems like the optimisation that does this transformation is -ftree-loop-distribute-patterns

all you need to do to turn off this optimization is pass -fno-tree-loop-distribute-patterns to the compiler. This turns off the optimization globally.

like image 31
S.S. Anne Avatar answered Oct 19 '22 03:10

S.S. Anne