Linker: Multiple Definition Error

Programming, for all ages and all languages.
Post Reply
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Linker: Multiple Definition Error

Post by Puffy »

I've been following Bran's tutorial. At first I grouped all of my source files together in one directory (along with my make file and linker script) apart from a header file which is in the subdirectory "include". I used the following make file to build it, and it works:

Code: Select all

all: floppy.img

loader.o: loader.asm
	nasm -f aout -o loader.o loader.asm

main.o: main.c
	gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c

memory.o: memory.c
	gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o memory.o memory.c

string.o: string.c
	gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o string.o string.c

kernel.bin: loader.o main.o memory.o string.o
	ld -T link.ld -o kernel.bin loader.o main.o memory.o string.o
	
floppy.img: kernel.bin
	cat stage1 stage2 pad kernel.bin > floppy.img
Then I decided to start organizing my source files a little bit better. So, I placed each source file in it's own sub directory (makefile and linker script remain where they were). Then I tried using the following make file (based on the makefile tutorial in the wiki):

Code: Select all

COMPILER := gcc
ASSEMBLER := nasm

PRJDIRS := loader memory string

NASM_SOURCE_FILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.asm")
C_SOURCE_FILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.c")
C_HEADER_FILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.h")

ALL_SOURCE_FILES := $(NASM_SOURCE_FILES) $(C_SOURCE_FILES) $(C_HEADER_FILES)

OBJECT_FILES := $(patsubst %.c,%.o,$(C_SOURCE_FILES)) $(patsubst %.asm,%.o,$(NASM_SOURCE_FILES))

COMPILER_FLAGS :=  -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin

all: kernel.bin
	
kernel.bin: $(OBJECT_FILES)
	ld -T link.ld -o kernel.bin $(OBJECT_FILES)

%.o: %.c
	$(COMPILER) $(COMPILER_FLAGS) -I./include -c -o $@ $<
	
%.o: %.asm
	$(ASSEMBLER) -f aout -o $@ $<
BUT I get a "multiple definition error" from the linker despite not actually having changed my source code!

The error:

Code: Select all

make -k all 
ld -T link.ld -o kernel.bin ./string/string.o ./main.o ./memory/memory.o ./loader/loader.o
./main.o: In function `kmain':
main.c:(.text+0x0): multiple definition of `kmain'
./string/string.o:(.text+0x0): first defined here
./memory/memory.o: In function `memcpy':
memory.c:(.text+0x0): multiple definition of `memcpy'
./string/string.o:(.text+0x10): first defined here
./memory/memory.o: In function `memset':
memory.c:(.text+0x29): multiple definition of `memset'
./string/string.o:(.text+0x39): first defined here
./memory/memory.o: In function `memsetw':
memory.c:(.text+0x4b): multiple definition of `memsetw'
./string/string.o:(.text+0x5b): first defined here
./loader/loader.o:./loader/loader.o:(.text+0x20): multiple definition of `_loader'
./string/string.o:(.text+0xa0): first defined here
make: *** [kernel.bin] Error 1
make: Target `all' not remade because of errors.
Obviously I'm doing something wrong, but I have no idea what, any ideas?
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Re: Linker: Multiple Definition Error

Post by suthers »

Have you put any actual code in any of the headers?
(I did that by accident a week ago. accidentally put a function in my header got loads of multiple deef errors... :oops: )
Jules
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Linker: Multiple Definition Error

Post by Puffy »

I've only got one header file, and this is it:

Code: Select all

#ifndef SYSTEM_H_
#define SYSTEM_H_
extern unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count);
extern unsigned char *memset(unsigned char *dest, unsigned char val, int count);
extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int count);
#endif /*SYSTEM_H_*/
And it's only included in one file (memory.c which is in the sub directory memory).

I'm very confused :/
User avatar
kmcguire
Member
Member
Posts: 120
Joined: Tue Nov 09, 2004 12:00 am
Location: United States
Contact:

Re: Linker: Multiple Definition Error

Post by kmcguire »

The secondary problem is in the object files, and the primary problem _should_ be in the source files.
SOURCE->OBJECT

The source for those three files _must_ contain a function that is implemented multiple times. This function has the same name in two or more source files. When each source is compiled into an object file the function names are stored as textual symbols. The linker then get confused on which one to use so it tells you that there are multiple definitions of the same function in the object files.

One red flag is the fact that the function (symbol) kmain has been defined twice in two separate object/source files.
main.c:(.text+0x0): multiple definition of `kmain'
./string/string.o:(.text+0x0): first defined here


The problem in understanding this I have is why is kmain being implemented in string.c? Take a look at the actual source in string.c and see if you can find a implementation of the function kmain. If you are unable to find a implementation of it then delete the object file string.o. Actually, if you are unable to find duplicate function implementations between all your source files then just delete all the object files and do a fresh compile.

Either, you have somehow compiled main.c into main.o and string.o, or you have a duplication implementation for a function or defined the symbol twice.

You might have just accidentally produced two or more object files from the same source file when tinkering with your Makefile.
Image
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Linker: Multiple Definition Error

Post by Puffy »

The functions are not duplicated anywhere. When I compile the code with my original makefile (when the source files are all in the same directory apart from the headers) they compile fine.

This is the source for string.c:

Code: Select all

int strlen(const char *str)
{
    int retval = 0;
    while(*str++!='\0') retval++;
    return retval;
}

There isn't any duplication.

I'll have a look at the idea that I'm generating main.c and string.c into main.o - maybe my makefile is doing that?
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Linker: Multiple Definition Error

Post by Puffy »

I followed your advice and deleted all of my existing object files and now it works!

I'm still unsure as to what went wrong originally, but I'm glad it's been fixed now.

Cheers!
User avatar
kmcguire
Member
Member
Posts: 120
Joined: Tue Nov 09, 2004 12:00 am
Location: United States
Contact:

Re: Linker: Multiple Definition Error

Post by kmcguire »

I think it happened when you were scripting your Makefile system. Somehow during testing you likely produced the same object file in different names. The Make system is strange sometimes (to me since I am not an expert with it) in that it will not update existing (OLD) object files. For some reason it can not detect that they are old and need to be recompiled or updated.

So, I figure in some strange way this is what was happening. Maybe someone else who knows more about this could explain why the object files were not updated.
Image
Post Reply