Page 1 of 2

[SOLVED] Linker and undefined function references

Posted: Tue Jul 28, 2009 4:09 pm
by luiscubal
Hello, I am new to OS development and I was coding based on OSDev's wiki and Bran's Kernel Development tutorial.
Everything went fine until I reached the part of GDT.
Although my Assembly code can call C functions, calling Assembly functions from C causes a linker error. Although both gcc and nasm compile properly, ld fails.

Code: Select all

out/gdt.o: In function `gdt_install':
gdt.c:(.text+0x102): undefined reference to `gdt_flush'
However, gdt.o *does* define a function gdt_flush(The "nm" command proves this)
I've tried messing with leading underscores, but with no luck...

My assembly "gdt_flush" function:

Code: Select all

global gdt_flush     ; Allows the C code to link to this
extern gp            ; Says that 'gp' is in another file
gdt_flush:
    lgdt [gp]        ; Load the GDT with our 'gp' which is a special pointer
    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:flush2   ; 0x08 is the offset to our code segment: Far jump!
flush2:
    ret               ; Returns back to the C code!
gdt_flush declaration in C:

Code: Select all

extern void gdt_flush();
Finally, here is my linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
What am I doing wrong?
(sorry if this is a duplicate. I've searched for quite some time now and I didn't find anything yet.)

EDIT: Ah, before I forget, I'm calling ld using this command:

Code: Select all

ld -Ttext 0x100000 -T src/link.ld out/*.o -o iso/$COREFOLDER/kernel.bin
the out folder includes the start.o(gdt_flush is defined in start.asm)

Re: Linker and undefined function references

Posted: Tue Jul 28, 2009 9:12 pm
by kop99

Code: Select all

global gdt_flush     ; Allows the C code to link to this
extern gp            ; Says that 'gp' is in another file
gdt_flush:
take place following.

Code: Select all

_global gdt_flush     ; Allows the C code to link to this
extern gp            ; Says that 'gp' is in another file
_gdt_flush:

Re: Linker and undefined function references

Posted: Wed Jul 29, 2009 4:02 pm
by luiscubal
I'm not calling both files gdt.
If I replace extern by extern "C", I get this:

Code: Select all

../src/gdt.c:30: error: expected identifier or ‘(’ before string constant
(I am using C, not C++)

Re: Linker and undefined function references

Posted: Wed Jul 29, 2009 5:22 pm
by pcmattman
berkus wrote:First, use extern "C" instead of just extern, this will turn off any name mangling.
extern "C" is a C++ thing, not an assembly or C thing. extern in the assembly code specifies that the symbol is available, but not within the object. The OP specified C :)

Code: Select all

_global gdt_flush     ; Allows the C code to link to this
extern gp            ; Says that 'gp' is in another file
_gdt_flush:
Code examples should be correct :). The _ belongs on gdt_flush, not global! Really though, you should be using -fno-leading-underscores (as berkus said).

Re: Linker and undefined function references

Posted: Wed Jul 29, 2009 5:46 pm
by luiscubal
Even when I add -fno_leading_underscores, nothing changes.

Re: Linker and undefined function references

Posted: Wed Jul 29, 2009 5:52 pm
by pcmattman
Are you certain that the assembly file is actually assembled and linked? Keep in mind that often the location of a file on the ld command line can directly impact the visibility of symbols (ie, make sure the assembly file is on the command line first, then the C file).

Re: Linker and undefined function references

Posted: Wed Jul 29, 2009 7:33 pm
by luiscubal
I've modified some things, but it still doesn't work...

Code: Select all

ld $LDFLAGS -T src/link.ld out/start.o out/gdt.o out/main.o out/srcn.o -o iso/$COREFOLDER/kernel.bin >>log.txt
(start is the assembly file, the remaining are written in C)

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 1:43 am
by Solar
objdump -t <objectfile>

Lists the symbols defined.

Toolchain FTW.

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 1:46 am
by pcmattman
nm <object file> can also show you the missing references (and help you name your assembly correctly, without guessing) in your compiled C object file too, IIRC.

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 2:02 am
by Solar
Heh, nice. There I was chanting "toolchain FTW" and didn't know about nm (since objdump does all I need, including full disassembly).

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 8:00 am
by luiscubal
nm start.o
00010000 a MULTIBOOT_AOUT_KLUDGE
e4514ffb a MULTIBOOT_CHECKSUM
00010003 a MULTIBOOT_HEADER_FLAGS
1badb002 a MULTIBOOT_HEADER_MAGIC
00000002 a MULTIBOOT_MEMORY_INFO
00000001 a MULTIBOOT_PAGE_ALIGN
U _entrypoint
00002000 b _sys_stack
U bss
U code
U end
U flush2
U gdt_flush
U gp
U mboot
U start
U stublet
So gdt_flush does exist. As I mentioned before, adding and removing leading underscores does not change anything.
Meanwhile, I've changed my build script a bit, so here's the whole updated sh script:

Code: Select all

#!/bin/sh
#Dependencies:
#gcc
#ld
#nasm
#qemu

SCRIPT_DIR_RELATIVE=$(dirname $0)
SCRIPT_DIR_ABSOLUTE=$(cd $SCRIPT_DIR_RELATIVE; pwd)
COREFOLDER=Core
BOOTFOLDER=boot/grub
CHARSET=ascii
NAME=Ovar

CFLAGS=$(echo -Wall -Wextra -m32 -O -fno-leading-underscore -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -nostdlib -nostartfiles -fno-builtin -nodefaultlibs)
LDFLAGS=$(echo -Ttext 0x100000 -melf_i386)

cd $SCRIPT_DIR_ABSOLUTE

if [ ! -d iso ]
then
	mkdir iso>>log.txt
fi

if [ ! -d out ]
then
	mkdir out>>log.txt
fi

if [ ! -d bin ]
then
	mkdir bin>>log.txt
fi

if [ ! -d bin/x86 ]
then
	mkdir bin/x86>>log.txt
fi

if [ ! -d iso/boot ]
then
	mkdir iso/boot>>log.txt
fi

if [ ! -d iso/$COREFOLDER ]
then
	mkdir iso/$COREFOLDER>>log.txt
fi

if [ ! -d iso/$BOOTFOLDER ]
then
	mkdir iso/$BOOTFOLDER>>log.txt
fi

echo "Compilation started">log.txt
nasm -f elf -o out/start.o src/start.asm >>log.txt

echo "GCC tasks starting">>log.txt
cd ./out #Make sure output files end up in the right folder
gcc $CFLAGS -I../headers -c ../src/*.c >>../log.txt
cd ../

echo "Linker starting">>log.txt
ld $LDFLAGS -T src/link.ld out/start.o out/gdt.o out/main.o out/srcn.o -o iso/$COREFOLDER/kernel.bin >>log.txt

echo "Finished compilation">>log.txt

if [ ! -d iso/$BOOTFOLDER ]
then
	mkdir iso/$BOOTFOLDER>>log.txt
fi

cp res/stage2_eltorito iso/$BOOTFOLDER>>log.txt
cp res/menu.lst iso/$BOOTFOLDER>>log.txt

if [ ! -d bin/x86 ]
then
	mkdir bin/x86>>log.txt
fi

cd iso/
mkisofs -input-charset $CHARSET -R -b $BOOTFOLDER/stage2_eltorito -A $NAME -no-emul-boot -boot-load-size 4 -boot-info-table -o ../bin/x86/os.iso .>>../log.txt
cd ..
qemu-img create -f qcow2 bin/x86/disk.img 3G
log.txt has only a few entries and ld errors seem to be going directly to the command line.

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 8:51 am
by torshie
luiscubal wrote:
nm start.o
00010000 a MULTIBOOT_AOUT_KLUDGE
e4514ffb a MULTIBOOT_CHECKSUM
00010003 a MULTIBOOT_HEADER_FLAGS
1badb002 a MULTIBOOT_HEADER_MAGIC
00000002 a MULTIBOOT_MEMORY_INFO
00000001 a MULTIBOOT_PAGE_ALIGN
U _entrypoint
00002000 b _sys_stack
U bss
U code
U end
U flush2
U gdt_flush
U gp
U mboot
U start
U stublet
So gdt_flush does exist. As I mentioned before, adding and removing leading underscores does not change anything.
Meanwhile, I've changed my build script a bit, so here's the whole updated sh script:

Code: Select all

#!/bin/sh
#Dependencies:
#gcc
#ld
#nasm
#qemu

SCRIPT_DIR_RELATIVE=$(dirname $0)
SCRIPT_DIR_ABSOLUTE=$(cd $SCRIPT_DIR_RELATIVE; pwd)
COREFOLDER=Core
BOOTFOLDER=boot/grub
CHARSET=ascii
NAME=Ovar

CFLAGS=$(echo -Wall -Wextra -m32 -O -fno-leading-underscore -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -nostdlib -nostartfiles -fno-builtin -nodefaultlibs)
LDFLAGS=$(echo -Ttext 0x100000 -melf_i386)

cd $SCRIPT_DIR_ABSOLUTE

if [ ! -d iso ]
then
	mkdir iso>>log.txt
fi

if [ ! -d out ]
then
	mkdir out>>log.txt
fi

if [ ! -d bin ]
then
	mkdir bin>>log.txt
fi

if [ ! -d bin/x86 ]
then
	mkdir bin/x86>>log.txt
fi

if [ ! -d iso/boot ]
then
	mkdir iso/boot>>log.txt
fi

if [ ! -d iso/$COREFOLDER ]
then
	mkdir iso/$COREFOLDER>>log.txt
fi

if [ ! -d iso/$BOOTFOLDER ]
then
	mkdir iso/$BOOTFOLDER>>log.txt
fi

echo "Compilation started">log.txt
nasm -f elf -o out/start.o src/start.asm >>log.txt

echo "GCC tasks starting">>log.txt
cd ./out #Make sure output files end up in the right folder
gcc $CFLAGS -I../headers -c ../src/*.c >>../log.txt
cd ../

echo "Linker starting">>log.txt
ld $LDFLAGS -T src/link.ld out/start.o out/gdt.o out/main.o out/srcn.o -o iso/$COREFOLDER/kernel.bin >>log.txt

echo "Finished compilation">>log.txt

if [ ! -d iso/$BOOTFOLDER ]
then
	mkdir iso/$BOOTFOLDER>>log.txt
fi

cp res/stage2_eltorito iso/$BOOTFOLDER>>log.txt
cp res/menu.lst iso/$BOOTFOLDER>>log.txt

if [ ! -d bin/x86 ]
then
	mkdir bin/x86>>log.txt
fi

cd iso/
mkisofs -input-charset $CHARSET -R -b $BOOTFOLDER/stage2_eltorito -A $NAME -no-emul-boot -boot-load-size 4 -boot-info-table -o ../bin/x86/os.iso .>>../log.txt
cd ..
qemu-img create -f qcow2 bin/x86/disk.img 3G
log.txt has only a few entries and ld errors seem to be going directly to the command line.
It seems that you are using *nix, why don't you use makefile ?

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 9:10 am
by luiscubal
Because I prefer shell scripts(I know them better so I can use them to do much more).
If makefiles solved my linker errors, I'd gladly use them, but I just don't see that happening. Should I at least try?

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 9:35 am
by Solar
No, a Makefile won't solve a linker error, but:
luiscubal wrote:I know them better so I can use them to do much more.
"Make" is the right tool for the job. If you don't know it, learn it.

Hitting nails with a screwdriver works in a pinch, but the results will always be sub-par, so you should go and buy a hammer. ;-)

Re: Linker and undefined function references

Posted: Thu Jul 30, 2009 12:37 pm
by luiscubal
I may switch to make later, but right now I'm more concerned about getting it to link...