Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign values to array requires memcpy

Tags:

arrays

c

linker

I've ran into a weird bug.

I'm writing code for a bootloader so I don't have many fancy libraries and all.

The code itself is pretty simple, it's

int array[32] = { 1, 2, 3, [...snip...], 31, 32 };

This code leads to an unresolved external problem regarding memcpy not being linked. However this code compiles and link fine

int array[12] = { 1, 2, 3, [...snip...], 11, 12 };

In fact, the error comes between

int array[12] = { 0 };
and
int array[13] = { 0 };

The first one links fine, but the second cannot link. I just don't get why at size 13, the compiler suddently decides to rely on memcpy for the thing. I tried with both -O0 and -O3. My compiler is a windows executable called cl470, not really sure where that comes from.

Another weird thing is that this is problematic when I put it inside a function, but if I declare the array globally, then there is no problem.

like image 751
Eric Avatar asked Jul 06 '26 02:07

Eric


2 Answers

Your compiler is performing a time-space tradeoff.

For the smaller array, the compiler is emitting individual instructions to initialise each array slot on the stack:

mov [ebp-4], 1
mov [ebp-8], 2
mov [ebp-12], 3
...

For the larger array, the compiler is placing the data in the program's read-only data segment and copying it onto the stack using memcpy:

.rodata:
    _array_initialiser = { 1, 2, 3, ... }

push ebp-4
push _array_initialiser
push 32
call memcpy

This is why making the array file-scope or static will eliminate the memcpy; the array can be placed directly in the data segment and initialised at compile time.

Using memcpy for larger arrays is more efficient because it reduces code size and so reduces instruction cache misses.

Some things you could try are moving the array to file scope or making it static yourself; if you need it reinitialised each time through the array you can copy it into a local array manually (although the compiler could also convert such a loop into a memcpy!)

static const int array_data[] = { 1, 2, 3, ... };
int array[sizeof(array_data) / sizeof(array_data[0]))];
for (size_t i = 0; i < sizeof(array_data) / sizeof(array_data[0])); ++i)
    array[i] = array_data[i];

Another option would be to generate the array programmatically; it looks like a simple for loop would work.

Third option would be to write and link in your own memcpy; it shouldn't require more than a few lines of code.

like image 70
ecatmur Avatar answered Jul 07 '26 17:07

ecatmur


The following code copies data stored in your executable to stack.

int array[12] = { blah };

I guess the optimizer uses memcpy when the array size is greater than a certain number.

You probably want to do this:

static int array[12] = { blah };

By using the static keyword you prevent the compiler from generating code which copies static data to stack.

like image 21
Mustafa Ozturk Avatar answered Jul 07 '26 16:07

Mustafa Ozturk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!