I have a c program that comes below:
int A[size][size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int B[size][size] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
int C[size][size];
int multiplication()
{
//using array A, B and C here
return 0;
}
I also wrote a startup file by myself and compile them using risc-v compiler by the following command:
riscv64-unknown-elf-gcc -ffreestanding -march=rv32im -mabi=ilp32 -nostartfiles -nodefaultlibs -mno-relax crt0.s Myprogram.c -o Myprogram
Then using riscv64-unknown-elf-objdump -t Myprogram
I can see that arrays A
and B
are in .data
segment and array C
is in .bss
segment that makes sense.
But when I change my code such that I declared arrays A
and B
as local arrays to the function:
int C[size][size];
int multiplication()
{
int A[size][size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int B[size][size] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
//using array A, B and C here
return 0;
}
I got the compilation error: undefined reference to `memcpy'
.
It seems that it uses memcpy
for allocating memory to the arrays while it's not the case when I declared the arrays as global.
Does anybody know why and what's the difference?
CodePudding user response:
Large constants needed by a program are stored in the program's text segment, and copied where needed. When the compiler chooses to initialize a large variable by copying the initializer from the text segment, it generates a call to memcpy
. There are other ways to compile this code, sure, but calling memcpy
is perfectly sensible and efficient.
This doesn't happen for a global variable because they are initialized from the program's data segment. Since they only need to be initialized when the program starts, the same memory that contains the initializer when the program starts is then used for the variable.
You might think of main
as a special function and of its local variables as essentially global variables, but they aren't. main
is a function, and it can be called recursively. The compiler could in theory detect that some programs doesn't call main
recursively and give it special treatment, but in practice, it doesn't, and it sure can't when it's linking some assembly code which could be finding its way to main
.
Normally you don't see this because the standard library provides memcpy
. But since you're using -nodefaultlibs
, you need to supply an alternative implementation of memcmp
, memset
, memcpy
and memmove
.
CodePudding user response:
GCC & clang require freestanding environments to provide
memcpy
, memmove
, memset
and memcmp
.
You need to implement them yourself it you do not want use the standard ones
You should also remember that there are more functions which can be required - for example, integer divisions and similar.
You can also see if your compiler provides libgcc
or you can take the function you require from here (or or your port libgcc repo): https://github.com/gcc-mirror/gcc/tree/master/libgcc