Undefined reference to memcpy in standalone program

R

Richard Hayden

Hi,

I've just upgraded my gcc and I'm currently trying to compile some code for
my own operating system kernel, but I am getting an error of "Undefined
reference to `memcpy`" when I try to link it using the GNU linker. I do not
reference the symbol memcpy explicitly anywhere in the offending function.
I have narrowed the offending code down to the initialisation of an array
of pointers to char (i.e. an array of strings), which is given below. It
seems that for some reason gcc is inserting calls to the standard library
in some attempt to optimise my code. How do I stop it from doing this? I'm
running version 3.3.1 and am compiling with the --freestanding flag, which
I thought should be enough to prevent this kind of behaviour (it certainly
was on previous versions; either that or gcc did not try and perform this
action then).

char* CPUstrings[] = {
"UNKNOWN Processor",
"Generic 386",
"NexGen 586",
"Cyrix M1 or IBM Bluelightning",
"Generic 486",
"Intel 386",
"Intel 486DX",
"Intel 486SX",
"Intel 486DX2",
"Intel 486SL",
"Intel 486SX2",
"Intel 486DX2 WB",
"Intel 486DX4",
"Intel 486DX4 WB",
"Intel 486",
"Intel Pentium Early P5",
"Intel Pentium 80501",
"Intel Pentium P54C 80502",
"Intel Pentium P24T (overdrive for 486 socket)",
"Intel Pentium MMX P55C",
"Intel Pentium P54C",
"Intel Pentium MMX P55",
"Intel Pentium P5",
"Intel Pentium Pro (Sample)",
"Intel Pentium Pro",
"Intel Pentium II (Klamath)",
"Intel Pentium II (Deschutes)/Xeon/Celeron",
"Intel Celeron A/Pentium II",
"Intel Pentium III (Katmai)",
"Intel Pentium III (Coppermine)",
"Intel Pentium III Xeon (Cascades)",
"Intel Pentium P6",
"Intel Pentium IV",
"UMC 486DX",
"UMC 486SX"
"UMC 486",
"AMD 486DX2, or DX4 in 2x WT mode",
"AMD 486DX2, or DX4 in 2x WB mode",
"AMD 486DX4, or 5x86 in 3x WT mode",
"AMD 486DX4 SV8B, 3x WB mode",
"AMD 5x86, 4x WT mode",
"AMD 5x86, 4x WB mode",
"AMD 486",
"AMD K5 Model 0",
"AMD K5 Model 1",
"AMD K5 Model 2",
"AMD K5 Model 3",
"AMD K6 Model 6",
"AMD K6 Model 7",
"AMD K6-II Model 8",
"AMD K6-III Model 9 (Sharptooth)",
"AMD K6-II+/K6-III+",
"AMD K5/K6",
"AMD Athlon 0.25u (external L2 cache)",
"AMD Athlon 0.18u (external L2 cache)",
"AMD Duron",
"AMD Athlon 0.18u (integrated L2 cache)",
"AMD K7 Athlon/Duron",
"Rise mP6 iDragon .25u",
"Rise mP6 iDragon .18u",
"Rise mP6 iDragon II .25u",
"Rise mP6 iDragon II .18u",
"Rise mP6",
"TransMeta Crusoe"
};

Thanks!

Richard Hayden.
 
A

Alexander Bartolich

begin followup to Richard Hayden:
No change in output I'm afraid...

Then the problem is something else.

$ const char* const CPUstrings[] = {
"UNKNOWN Processor",
"Generic 386"
};

void _start()
{
asm(
"mov $4,%eax\n"
"mov $1,%ebx\n"
"mov (CPUstrings),%ecx\n"
"mov $17,%edx\n"
"int $0x80\n"

"mov $1,%eax\n"
"mov $27,%ebx\n"
"int $0x80\n"
);
}

$ gcc -c -ffreestanding -Wall stand.c && ld stand.o -o stand
$ ./stand ; /bin/echo -e "\n$?"
UNKNOWN Processor
27

$ objdump -M intel -d stand

stand: file format elf32-i386

Disassembly of section .text:

08048074 <_start>:
8048074: 55 push ebp
8048075: 89 e5 mov ebp,esp
8048077: b8 04 00 00 00 mov eax,0x4
804807c: bb 01 00 00 00 mov ebx,0x1
8048081: 8b 0d 9c 80 04 08 mov ecx,ds:0x804809c
8048087: ba 11 00 00 00 mov edx,0x11
804808c: cd 80 int 0x80
804808e: b8 01 00 00 00 mov eax,0x1
8048093: bb 1b 00 00 00 mov ebx,0x1b
8048098: cd 80 int 0x80
804809a: 5d pop ebp
804809b: c3 ret

Obviously this thread has left the topic of comp.lang.c far behind...
Perhaps comp.lang.asm.x86, gnu.gcc or linux.dev.gcc is better suited.
 
C

Chris Torek

... I am getting an error of "Undefined reference to `memcpy`"
[even though he never calls memcpy() himself].
I have narrowed the offending code down to the initialisation of an array
of pointers to char (i.e. an array of strings), which is given below.

This is probably not it.

More likely you have some function like:

void fn(void) {
char buf[] = "some initialization";
...
}

and gcc is doing the initialization via memcpy(); or you have a
struct-to-struct assignment that the compiler implements via a
call to memcpy() (although under various optimizations gcc will
subsequently inline this on x86 CPUs).
It seems that for some reason gcc is inserting calls to the
standard library in some attempt to optimise my code. How do
I stop it from doing this? I'm running version 3.3.1 and am
compiling with the --freestanding flag ...

("-ffreestanding", I presume.)

Unfortunately, hosted compilers are allowed to "know" all about
the entire C standard library and make arbitrary changes to your
source, and freestanding compilers are sufficiently difficult to
talk about to be mostly off-topic in comp.lang.c (freestanding
systems may not even have a main() function, as no doubt you already
know, having no doubt had to write your own startup code -- you can
then pick your own name for the entry point for your program).

GCC in particular may still use memcpy(), memset(), and a whole
host of generic 64-bit function calls (__muldi2, __divdi2, etc.),
even under -ffreestanding, depending on the machine in question
and sometimes on optimization levels. It may also need machine-
specific functions for other "ordinary" operations, such as
integer multiply and divide (.mul, .urem, etc., on pre-V8 sparc).

With GCC in particular, once you know which .o file(s) refer to
the unwanted function, you can compile to assembly code and read
this to pin down precisely where and why it wants some particular
function. It usually only takes a little "thinking like a
compiler-writer", at that point, to come up with ways to change
the generated code. (Or of course -- as in this case -- you can
simply write a little standalone memcpy()...)
 
T

Tauno Voipio

Richard Hayden said:
Hi,

I've just upgraded my gcc and I'm currently trying to compile some code for
my own operating system kernel, but I am getting an error of "Undefined
reference to `memcpy`" when I try to link it using the GNU linker. I do not
reference the symbol memcpy explicitly anywhere in the offending function.
I have narrowed the offending code down to the initialisation of an array
of pointers to char (i.e. an array of strings), which is given below. It
seems that for some reason gcc is inserting calls to the standard library
in some attempt to optimise my code. How do I stop it from doing this? I'm
running version 3.3.1 and am compiling with the --freestanding flag, which
I thought should be enough to prevent this kind of behaviour (it certainly
was on previous versions; either that or gcc did not try and perform this
action then).

char* CPUstrings[] = {
"UNKNOWN Processor",
"Generic 386",
"NexGen 586",
"Cyrix M1 or IBM Bluelightning",
"Generic 486",
"Intel 386",
"Intel 486DX",
"Intel 486SX",
"Intel 486DX2",
"Intel 486SL",
"Intel 486SX2",
"Intel 486DX2 WB",
"Intel 486DX4",
"Intel 486DX4 WB",
"Intel 486",
"Intel Pentium Early P5",
"Intel Pentium 80501",
"Intel Pentium P54C 80502",
"Intel Pentium P24T (overdrive for 486 socket)",
"Intel Pentium MMX P55C",
"Intel Pentium P54C",
"Intel Pentium MMX P55",
"Intel Pentium P5",
"Intel Pentium Pro (Sample)",
"Intel Pentium Pro",
"Intel Pentium II (Klamath)",
"Intel Pentium II (Deschutes)/Xeon/Celeron",
"Intel Celeron A/Pentium II",
"Intel Pentium III (Katmai)",
"Intel Pentium III (Coppermine)",
"Intel Pentium III Xeon (Cascades)",
"Intel Pentium P6",
"Intel Pentium IV",
"UMC 486DX",
"UMC 486SX"
"UMC 486",
"AMD 486DX2, or DX4 in 2x WT mode",
"AMD 486DX2, or DX4 in 2x WB mode",
"AMD 486DX4, or 5x86 in 3x WT mode",
"AMD 486DX4 SV8B, 3x WB mode",
"AMD 5x86, 4x WT mode",
"AMD 5x86, 4x WB mode",
"AMD 486",
"AMD K5 Model 0",
"AMD K5 Model 1",
"AMD K5 Model 2",
"AMD K5 Model 3",
"AMD K6 Model 6",
"AMD K6 Model 7",
"AMD K6-II Model 8",
"AMD K6-III Model 9 (Sharptooth)",
"AMD K6-II+/K6-III+",
"AMD K5/K6",
"AMD Athlon 0.25u (external L2 cache)",
"AMD Athlon 0.18u (external L2 cache)",
"AMD Duron",
"AMD Athlon 0.18u (integrated L2 cache)",
"AMD K7 Athlon/Duron",
"Rise mP6 iDragon .25u",
"Rise mP6 iDragon .18u",
"Rise mP6 iDragon II .25u",
"Rise mP6 iDragon II .18u",
"Rise mP6",
"TransMeta Crusoe"
};

You have specified that the strings and the pointer table to them have to be
initialised read/write data. Make the pointer table and target data
constants using the 'const' keyword twice to avoid the initialisation (const
char * const CPUstrings[] ...). This has the side effect that you have to
use the table and strings in such context that const data is allowed there.

HTH

Tauno Voipio
tauno voipio @ iki fi
 
D

Dave Thompson

Hi,

I've just upgraded my gcc and I'm currently trying to compile some code for
my own operating system kernel, but I am getting an error of "Undefined
reference to `memcpy`" when I try to link it using the GNU linker. I do not
reference the symbol memcpy explicitly anywhere in the offending function.
I have narrowed the offending code down to the initialisation of an array
of pointers to char (i.e. an array of strings), which is given below. <snip>
char* CPUstrings[] = { <snipped>

In addition to the other answers, especially (as usual) Chris Torek,
is there a reason you actually need it initialized at runtime and
can't just make it static? Doesn't your OS/boot support init data? Do
you want to make changes one time through the function and have them
gone (restored) the next time through (doesn't seem likely to me)?

- David.Thompson1 at worldnet.att.net
 
L

lambda

Eric said:
Hi,

I've just upgraded my gcc and I'm currently trying to compile some code for
my own operating system kernel, but I am getting an error of "Undefined
reference to `memcpy`" when I try to link it using the GNU linker. I do not
reference the symbol memcpy explicitly anywhere in the offending function.
I have narrowed the offending code down to the initialisation of an array
of pointers to char (i.e. an array of strings), which is given below. It
seems that for some reason gcc is inserting calls to the standard library
in some attempt to optimise my code. How do I stop it from doing this? I'm
running version 3.3.1 and am compiling with the --freestanding flag, which
I thought should be enough to prevent this kind of behaviour (it certainly
was on previous versions; either that or gcc did not try and perform this
action then).

char* CPUstrings[] = {
"UNKNOWN Processor",
"Generic 386",
"NexGen 586",
"Cyrix M1 or IBM Bluelightning",
"Generic 486",
"Intel 386",
"Intel 486DX",
"Intel 486SX",
"Intel 486DX2",
"Intel 486SL",
"Intel 486SX2",
"Intel 486DX2 WB",
"Intel 486DX4",
"Intel 486DX4 WB",
"Intel 486",
"Intel Pentium Early P5",
"Intel Pentium 80501",
"Intel Pentium P54C 80502",
"Intel Pentium P24T (overdrive for 486 socket)",
"Intel Pentium MMX P55C",
"Intel Pentium P54C",
"Intel Pentium MMX P55",
"Intel Pentium P5",
"Intel Pentium Pro (Sample)",
"Intel Pentium Pro",
"Intel Pentium II (Klamath)",
"Intel Pentium II (Deschutes)/Xeon/Celeron",
"Intel Celeron A/Pentium II",
"Intel Pentium III (Katmai)",
"Intel Pentium III (Coppermine)",
"Intel Pentium III Xeon (Cascades)",
"Intel Pentium P6",
"Intel Pentium IV",
"UMC 486DX",
"UMC 486SX"
"UMC 486",
"AMD 486DX2, or DX4 in 2x WT mode",
"AMD 486DX2, or DX4 in 2x WB mode",
"AMD 486DX4, or 5x86 in 3x WT mode",
"AMD 486DX4 SV8B, 3x WB mode",
"AMD 5x86, 4x WT mode",
"AMD 5x86, 4x WB mode",
"AMD 486",
"AMD K5 Model 0",
"AMD K5 Model 1",
"AMD K5 Model 2",
"AMD K5 Model 3",
"AMD K6 Model 6",
"AMD K6 Model 7",
"AMD K6-II Model 8",
"AMD K6-III Model 9 (Sharptooth)",
"AMD K6-II+/K6-III+",
"AMD K5/K6",
"AMD Athlon 0.25u (external L2 cache)",
"AMD Athlon 0.18u (external L2 cache)",
"AMD Duron",
"AMD Athlon 0.18u (integrated L2 cache)",
"AMD K7 Athlon/Duron",
"Rise mP6 iDragon .25u",
"Rise mP6 iDragon .18u",
"Rise mP6 iDragon II .25u",
"Rise mP6 iDragon II .18u",
"Rise mP6",
"TransMeta Crusoe"
};

Thanks!

Richard Hayden.

A while ago I read that memcpy was the one function reference
gcc-compiled code cannot do without.

Why not implement it yourself, or link it in from some gcc-provided
library for your target platform? You don't buy any unnecessary code
when doing this.

greetings,
Thomas
 

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top