Linker problems, I think...

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Linker problems, I think...

Post by Thomac »

I wish I didn't have to join this forum asking questions, but I've been completely stuck for several days on this issue.

I've been working a bit on-and-off on my hobby kernel project, things are going great. I finished my bootloader a few days ago, managed to write some cool memory management routines, but nothing outside main.c worked, despite being compiled and linked without any kinds of error or warning messages.

I tried rewriting the routines, adding printlining, removing the code within them, absolutely nothing except what was in main.c worked.
After moving all my external code to main.c, everything suddenly started working fine.

Checking the assembly, I see that all my calls to functions outside main.c, jumps to JNBE instructions that in turn jump to themselves. :?

Does anyone know a possible cause for this? :(
I'm using LD 2.13, GCC 2.8.1, and NASM 0.98.39.

Edit:
The strangest thing just happened; if I declare a function pointer that points to a function outside main.c, and call that one, it works all of a sudden =S
Edit 2:
Nevermind the last edit, it worked a couple of times and then stopped working for no reason.
User avatar
carbonBased
Member
Member
Posts: 382
Joined: Sat Nov 20, 2004 12:00 am
Location: Wellesley, Ontario, Canada
Contact:

Post by carbonBased »

GCC 2.8.1!? Is that a typo? If not, that is a really old version of GCC.

I'd recommend upgrading (4.x exists now) first before going any further (admittedly, though, I can't see why GCC would do something like that...!).

Also, what command lines are you using to compile and link?

--Jeff
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Post by Thomac »

Thanks for your reply!

No it was not a typo =S
Using the newest GCC I get HUGE object files that do not work at all for some reason(Yes, I changed the bootloader to load the entire oversized image), -Os doesn't really help.

Anyway, here's my crummy batch makefile

Code: Select all

echo off
cls

nasm -f bin -o bootloader.bin bootloader.asm
nasm -f aout -o entry.o main.asm

gcc -v
gcc -Wall -O3 -fstrength-reduce -ffreestanding -nostdlib -nostartfiles -fomit-frame-pointer -nostdinc -fno-builtin -c -o main.o main.c
gcc -Wall -O3 -fstrength-reduce -ffreestanding -nostdlib -nostartfiles -fomit-frame-pointer -nostdinc -fno-builtin -c -o conio.o conio.c

ld -T link.ld -o kernel.bin entry.o main.o conio.o
del *.o

merge a.img bootloader.bin kernel.bin
(Merge simply merges the two bin files.)

To make matters worse, now there's another problem; if I put too much stuff in main.c, it simply hangs the same way it does when calling something from a different file.
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

you are doing this in 32bit right?
also I have had this problem before
assuming your bootloader doesn't do relocations(as almost none do) you must set where all the global data is(local vars work because they are on the stack) to do this you add this to your linker options/args

Code: Select all

-Ttext 0x100000
and then just replace 0x100000 with wherever your bootloader loads your kernel
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Post by Thomac »

Yes, I am doing this in 32 bit, with A20 enabled (If that makes any difference).

Here's the linker script I use to link all the stuff together, I'm not sure if it's correct in any way, but it seems to work.

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(entry)

phys_addr = 0x00100000;

SECTIONS
{
  .text phys_addr : AT(phys_addr) {
    code_loc = .;
    *(.text)
    . = ALIGN(8192);
  }
  .data : AT(phys_addr  + (data_loc - code_loc))
  {
    data_loc = .;
    *(.data)
    . = ALIGN(8192);
  }
  .bss : AT(phys_addr + (bss_loc - code_loc))
  {
    bss_loc = .;
    *(.bss)
    . = ALIGN(8192);
  }
  end = .;
}
I am rather certain that my kernel is located at code_seg + 0x100000, because it does jump to the correct instructions at first (jmp code_sel:0x100000).
I have noticed that I cannot do anything worthwhile where I jump though, loading a new GDT simply crashes the thing. :(
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Post by Thomac »

I think I've found a probable cause for all this.
The location of the main kernel entry is 0x20000, and not 0x100000 as I told it to be.
If I tell it to put things on 0x200000, the entry point is located at 0x40000.

No idea on how to fix this though =S
User avatar
carbonBased
Member
Member
Posts: 382
Joined: Sat Nov 20, 2004 12:00 am
Location: Wellesley, Ontario, Canada
Contact:

Post by carbonBased »

Thomac wrote: No it was not a typo =S
Using the newest GCC I get HUGE object files that do not work at all for some reason(Yes, I changed the bootloader to load the entire oversized image), -Os doesn't really help.
What's your .asm look like? Have you made sure that everything is encapsulated inside a .text or .data section (ie, will it be positioned correctly via your linker script?).

Usually when I see large object files it's because something hasn't been put into an actual section, and so starts at address 0, while .text is at 1MB... inbetween there's a million nops, or 0's.

--Jeff
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Post by Thomac »

Edit: I've been able to isolate the problem; it is the linker allright.
If I use "ld -T link.ld -o kernel.bin entry.o conio.o" instead of "ld -T link.ld -o kernel.bin entry.o main.o conio.o", all the stuff in conio.o works.
If I use "ld -T link.ld -o kernel.bin entry.o conio.o main.o", it doesn't work, as usual. :(

Could it be the linker script, or perhaps the linker itself?

Bootloader:

Code: Select all

[BITS 16]
[ORG 7C00h]

jmp boot
 
;-------------------Variables-------------------;
	drive	db 0
 
;-----------------End Variables-----------------;
 
;----------------------GDT----------------------;
gdtr:
	dw gdt_end-gdt-1
	dd gdt
gdt:
null_sel	equ	$-gdt
	dd	0x0
	dd	0x0
 
code_sel	equ	$-gdt
	dw	0xFFFF
	dw	0x0
	db	0x0
	db	0x9A
	db	0xCF
	db	0x0
 
data_sel	equ	$-gdt
	dw	0xFFFF
	dw	0x0
	db	0x0
	db	0x92
	db	0xCF
	db	0x0
gdt_end:
;--------------------End GDT--------------------;
 
;-------------------Functions-------------------;
panic:
	mov	byte [gs:0],al
	mov	byte [gs:1],0x04
	cli
	hlt
 
try_enable_a20:
	cli
	call	enable_A20_primary
	call	kbdc_status
	test	al, 2
	jnz	.success
	call	enable_A20_secondary
	call	kbdc_status
	test	al, 2
	jnz	.success	
 
	xor ax, ax
	ret
 
	.success:
	mov ax, -1	
	ret
 
enable_A20_secondary:
	call	kbdc_command
	mov	al, 0xDF
	out	0x64, al
	ret
 
 
enable_A20_primary:
	call	kbdc_status
	push	ax
	call	kbdc_command
	mov	al, 0xD1
	out	0x64, al
	call	kbdc_command
	pop	ax
	or	al, 00000010b
	out	0x60, al
	ret
 
 
kbdc_command:
	xor	ax, ax
	in	al, 0x64
	test	ax, 2
	jnz	kbdc_command
	ret
 
kbdc_data:
	xor	ax, ax
	in	al, 0x64
	test	al, 1
	jz	kbdc_data
	ret
 
kbdc_status:
	call	kbdc_command
	mov	al, 0xD0
	out	0x64, al
	call	kbdc_data
	xor	ax, ax
	in	al, 0x60
	ret
;-----------------End Functions-----------------;
 
boot:
	mov	[drive], dl
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
        mov     al, 17
        mov     ah, 02h
	mov	ss, ax
	mov	sp, 0x200
	mov	ax, 0xB800
	mov	gs, ax
 
	call	try_enable_a20
	or	ax, ax
	jnz	.a20_enabled
	mov	al, 'P'
	call	panic
 
.a20_enabled:
	sti
	mov	cx, 0x3
 
.try_load_kernel:
	push	cx
	mov	ah, 0x2
	mov	al, 0x2
	mov	ch, 0x0
	mov	cl, 0x2
	mov	dh, 0x0
	mov	dl, [drive]
	mov	bx, 0xFFFF
	mov	es, bx
	mov	bx, 0x10
	int 13h
	jnc	.kernel_loaded
	pop	cx
	loop	.try_load_kernel
	mov	al, 'L'
	call	panic
 
.kernel_loaded:
	cli
 
	lgdt	[gdtr]
 
	mov	eax, cr0
	or	al, 0x1
	mov	cr0, eax
 
	jmp	code_sel:flush
 
[BITS 32]
flush:
	mov	eax, data_sel
	mov	ds, eax
	mov	es, eax
	mov	fs, eax
	mov	gs, eax
	mov	ss, eax
	mov	esp, 0xFFFF
	
	mov eax, gdtr

	jmp	code_sel:0x100000
 
	hlt
 
times 510-($-$$) db 0
	dw	0xAA55
Startup stuff:

Code: Select all

SECTION .text

[BITS 32]

[EXTERN _kernel_entry]
[GLOBAL entry]
entry:
[GLOBAL _entry]
_entry:

mov esp, _sys_stack

push eax              

call _kernel_entry    ;Calls the C kernel entry

cli
hlt
jmp $
    
SECTION .bss
   resb 16384
_sys_stack:
Thomac
Posts: 11
Joined: Sat Sep 16, 2006 2:23 am

Post by Thomac »

Okay, I rewrote the entire thing in ASM, and changed the object file format to ELF, but I still can't do things the way I want.
For some reason I cannot modify or access anything in .data or .bss, the only thing that works is .text(Which fails once I reach a critical size).
I believe there must be some problem with the linker, I've tried using a newer version of LD, but the newer versions whine about non-pe operations being executed on a non-pe file.
:(
Post Reply