Page 1 of 1

Undefined reference to

Posted: Sun Dec 21, 2014 4:40 am
by Modestas
Hello. I'm beginner to operating system development, and got problem calling function that is defined in assembly, from kernel that is programmed in C. When I try to link all compiled C sources to one binary file I get this error:
tables.o: In function `init_gdt':
tables.c:(.text+0x10b): undefined reference to `gdt_flush'
But it's actually defined.

Here is the line in tables.c:

Code: Select all

extern void gdt_flush(unsigned int);
And in assembly I have this code in the bootloader sector:

Code: Select all

[GLOBAL gdt_flush]
gdt_flush:
	mov eax, [esp+4]
	lgdt [eax]
	
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	jmp 0x08:.flush
.flush:
	ret
This is how I link them:

Code: Select all

ld -o kernel_l.bin -Ttext 0x7e00 kernel_l.o console.o tables.o -m elf_i386 --oformat binary
I had same problem when I've been linking those 3 files separately. So I should somehow link bootloader together with compiled C sources?

Re: Undefined reference to

Posted: Sun Dec 21, 2014 4:45 am
by Combuster
ld
Posting Checklist

Apart from using a dodgy linker and a dodgy reference, which file that you pass contains the implementation of gdt_flush?

Re: Undefined reference to

Posted: Sun Dec 21, 2014 5:14 am
by Modestas
Combuster wrote:
ld
Posting Checklist

Apart from using a dodgy linker and a dodgy reference, which file that you pass contains the implementation of gdt_flush?
It is declared in tables.c and defined in boot.asm

Re: Undefined reference to

Posted: Sun Dec 21, 2014 1:23 pm
by Combuster
which file that you pass (...)

Re: Undefined reference to

Posted: Mon Dec 22, 2014 6:09 am
by Modestas
Combuster wrote:
which file that you pass (...)
None. It's in boot.bin and I think I know my problem. I do not link boot.bin (which has implementation of gdt_flush) together with tables.o and this is the problem. But how I could link them if linker gives me this error when I add boot.bin to ld line?
boot.bin: file not recognized: File format not recognized
And if I compile my boot.asm to elf format instead of bin (so I could link it) using this:
nasm boot.asm -f elf -o boot.elf
Again I'm getting error:
boot.asm:1: error: unrecognised directive [ORG]
So the solution is to rewrite boot.asm, so it would compile to elf format? Or there is any other solutions?

Re: Undefined reference to

Posted: Mon Dec 22, 2014 10:35 am
by Bender
'boot.bin' sounds like a binary file to me, you need an object file to be compiled as ELF32/64 (or other but I'd just assume ELF) to be passed to the linker. Also, you would have to use a linker script instead of an ORG, to define your start address.
And the most important part,
Please use a cross compiler, as Combuster previously pointed out, even if you'd somehow get it to compile, chances are you are going to have a lot of trouble afterwards.
Follow the instructions here: http://wiki.osdev.org/GCC_Cross-Compiler
It takes a bit of work and time to build but it's worth it.

Along with that I see you're probably using code from JamesM tutorials (judging from the names of symbols), be sure to check out (if you're): http://wiki.osdev.org/James_Molloy%27s_ ... Known_Bugs

Re: Undefined reference to

Posted: Tue Dec 23, 2014 2:53 am
by Combuster
-Ttext 0x7e00
Definitely not JamesM's, although it's most likely a mix and match of everything in which case it's especially not going to work considering the OP has no clue as to how a linker actually works.
So the solution is to rewrite boot.asm, so it would compile to elf format? Or there is any other solutions?
The bootsector runs in 16-bit mode (and should not be using anything like a 32-bit stack. Homework for the OP: explain why this is wrong). C code (in your apparent case) runs in 32-bit mode, and you can not share code between the two modes.

Re: Undefined reference to

Posted: Wed Dec 24, 2014 7:24 am
by Modestas
Bender wrote:Also, you would have to use a linker script instead of an ORG, to define your start address.
How the hell I can do this? I've tried few hours to do it, tried to google some info, but still nothing.

I have this assembly code:

Code: Select all

[org 0x7c00]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
If I do:

Code: Select all

nasm boot.asm -f bin -o boot.bin
qemu boot.bin
It prints 'A' character. But how to do it with linker script?
I've tried this:

Code: Select all

ENTRY(Start)
INPUT(boot.o)
OUTPUT_FORMAT(elf32-i386)
OUTPUT(boot.bin)
SECTIONS
{
	. = 0x7c00;
	.text : { *(.text) }
}
Assembly code:

Code: Select all

section .text
	[global Start]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
But nothing happens, qemu won't find bootable floppy drive.

And with linker script boot.bin is not 512 bytes as it should be, it's greater than 3kb.

Re: Undefined reference to

Posted: Wed Dec 24, 2014 7:38 am
by seuti
Modestas wrote:
Bender wrote:Also, you would have to use a linker script instead of an ORG, to define your start address.
How the hell I can do this? I've tried few hours to do it, tried to google some info, but still nothing.

I have this assembly code:

Code: Select all

[org 0x7c00]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
If I do:

Code: Select all

nasm boot.asm -f bin -o boot.bin
qemu boot.bin
It prints 'A' character. But how to do it with linker script?
I've tried this:

Code: Select all

ENTRY(Start)
INPUT(boot.o)
OUTPUT_FORMAT(elf32-i386)
OUTPUT(boot.bin)
SECTIONS
{
	. = 0x7c00;
	.text : { *(.text) }
}
Assembly code:

Code: Select all

section .text
	[global Start]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
But nothing happens, qemu won't find bootable floppy drive.

And with linker script boot.bin is not 512 bytes as it should be, it's greater than 3kb.
Maybe it is because you are telling the linker you want the elf format and I think the MBR has to be a flat binary.

Re: Undefined reference to

Posted: Wed Dec 24, 2014 7:44 am
by Combuster
So you're still trying to use the exact same code for both the bootsector and whatever comes after that, even though you have already been told you can't mix code assembled for 16-bit mode with code assembled for 32-bit mode?

Re: Undefined reference to

Posted: Wed Dec 24, 2014 8:04 am
by Modestas
seuti wrote:
Modestas wrote:
Bender wrote:Also, you would have to use a linker script instead of an ORG, to define your start address.
How the hell I can do this? I've tried few hours to do it, tried to google some info, but still nothing.

I have this assembly code:

Code: Select all

[org 0x7c00]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
If I do:

Code: Select all

nasm boot.asm -f bin -o boot.bin
qemu boot.bin
It prints 'A' character. But how to do it with linker script?
I've tried this:

Code: Select all

ENTRY(Start)
INPUT(boot.o)
OUTPUT_FORMAT(elf32-i386)
OUTPUT(boot.bin)
SECTIONS
{
	. = 0x7c00;
	.text : { *(.text) }
}
Assembly code:

Code: Select all

section .text
	[global Start]
[bits 16]

Start:
	mov al, 'A'
	mov ah, 0eh
	int 10h
	
	jmp $
	
times 510 - ($ - $$) db 0
dw 0xAA55
But nothing happens, qemu won't find bootable floppy drive.

And with linker script boot.bin is not 512 bytes as it should be, it's greater than 3kb.
Maybe it is because you are telling the linker you want the elf format and I think the MBR has to be a flat binary.
Oh god, thanks, now it runs good in qemu.

And, Combuster, in the latest post assembly code I'm not mixing 16 and 32 bit code, it's only 16 bits.

Re: Undefined reference to

Posted: Wed Dec 24, 2014 8:23 am
by sortie
May I recommend you take a look at http://wiki.osdev.org/Bare_Bones and consider discarding your current boot method? This approach is verified, community edited and well supported by the osdev community. Feel free to continue doing things your way, but if you're having trouble like this (or the many other trouble I expect you to have in the future, unless you're more skilled than I estimate), I only suggest developing in this manner if you are absolutely certain you can do it and it's the best way for you.

Re: Undefined reference to

Posted: Wed Dec 24, 2014 8:25 am
by Brendan
Hi,

Let's go back to the start...

A kernel needs different boot loaders for different cases:
  • for floppy (unpartitioned, with BPB, with old "int 0x13")
  • for BIOS MBR partitioned hard disk (MBR partitioned, without BPB, with "int 0x13 extensions")
  • for BIOS GPT/hybrid hard disk (GPT partitioned, without BPB, with "int 0x13 extensions")
  • for BIOS network boot/PXE (completely different, no disk IO at all)
  • for BIOS "no emulation El Torito" CDs
  • for 32-bit UEFI
  • for 64-bit UEFI
Building a boot loader into the kernel itself is silly. The boot loader and the kernel need to be completely separate; where (hopefully) all the different boot loaders start the same kernel, and where the OS installer is responsible for installing the appropriate boot loader/s onto whatever the boot device is. Note: For some cases it does make sense to have multiple boot loaders on the same device - e.g. a single CD that contains a UEFI system partition with both 32-bit and 64-bit UEFI boot loaders, plus the BIOS "no emulation El Torito" boot loader, where the firmware auto-selects the boot loader it needs.

Now; given that the boot loader and kernel are completely separate binaries, you can not expect the kernel to be able to call anything in the boot loader directly. You either avoid this (e.g. build "gdt_flush" into your kernel so that kernel doesn't need to call a function in the boot loader); or you need to define some sort of interface/API (e.g. maybe boot loader provides a software interrupt that kernel can use, or maybe boot loader passes a table of function pointers to kernel when it starts the kernel, etc). If the boot loader does provide some sort of interface/API the linker isn't involved (either the kernel doesn't need to know the address of the function in the boot loader, or the kernel is told the address of the function in the boot loader at run-time and not at compile/link time).

Finally; I recommend documenting the requirements for the state of the computer when the boot loader passes control to the kernel. This should be a formal specification; and should include things like:
  • what the physical and/or virtual address space will look like when the kernel is started
  • which data (memory map, video buffer details, etc) is passed to the kernel and how
  • what can the kernel assume about the CPU's state - which mode will the CPU be in, what will registers contain, can the kernel assume FPU has been initialised, is there a GDT or IDT, will caches be enabled, will MTRRs be configured, will IRQs be enabled, etc.
  • the state/s of all other hardware - e.g. is A20 guaranteed to be enabled, what state are other CPUs in, are PCI devices guaranteed to be correctly preconfigured (and how) or in an undefined state, what about PIC/IO APIC (and local APIC), etc.
  • if the boot loader has to provide some sort of interface/API, then that has to be included too. What CPU mode is used for the interface/API and which calling conventions. For each function the interface/API provides; what do they do, what are the input and output parameters, what are the limitations.
In general, someone should be able to download your specification and implement a boot loader that works with your kernel/s; without ever talking to you and without ever downloading or seeing any of your source code.


Cheers,

Brendan

Re: Undefined reference to

Posted: Wed Dec 24, 2014 8:33 am
by Bender
I don't know what you are actually trying to achieve. I'm sorry but this thread is getting a bit confusing, you first link your program with "elf_i386" flags, looking like you're compiling 32-bit code, and then you show 16-bit code.

I think what you actually intend to accomplish is a 32-bit kernel which needs to be loaded by another bootloader, GRUB (or other), you don't need to have 16-bit code with the kernel, if you really want to do it "that" way, you'd have to switch from 16-bit to 32-bit protected mode.

You must write 32-bit code only, for a 32-bit executable, it's not a good idea to mix 16-bit and 32-bit code. (unless in a bootloader, of course).

(ninja'd by Brendan, his post explains this better)

Re: Undefined reference to

Posted: Thu Dec 25, 2014 4:46 am
by Modestas
Brendan wrote:The boot loader and the kernel need to be completely separate;
I thought everything should be in one file.. But anyway, I made it working. Now I compile bootloader to binary file, then another assembly file which one have function that must be called from C (kernel.c) compiled to elf format and linked together with kernel, now it works good.

Thank you everyone for helping.