"Higher Half x86 Bare Bones" from the Wiki triple faults

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.
ForceBru
Posts: 9
Joined: Thu Aug 20, 2020 2:02 pm

Re: "Higher Half x86 Bare Bones" from the Wiki triple faults

Post by ForceBru »

Looks like "kernel_start" and "kernel_end" are both zero using this linker script:

Code: Select all

ENTRY (_start)

SECTIONS
{
    . = 0x00100000;
	/* The kernel will live at 3GB + 1MB in the virtual address space, */
	/* which will be mapped to 1MB in the physical address space. */
	/* Note that we page-align the sections. */

    .multiboot.data : {
        *(.multiboot.data)
    }

    .multiboot.text : {
        *(.multiboot.text)
    }

	. += 0xC0100000;
	/* Add a symbol that indicates the start address of the kernel. */
	kernel_start = .;
	.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
	{
		*(.text)
	}
	.rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC0000000)
	{
		*(.rodata)
	}
	.data ALIGN (4K) : AT (ADDR (.data) - 0xC0000000)
	{
		*(.data)
	}
	.bss ALIGN (4K) : AT (ADDR (.bss) - 0xC0000000)
	{
		*(COMMON)
		*(.bss)
		*(.bootstrap_stack)
	}
	/* Add a symbol that indicates the end address of the kernel. */
	kernel_end = .;
}
I then use these symbols in C code like this:

Code: Select all

// Defined in `linker.ld`
extern const void * const kernel_start, * const kernel_end;

void whatever_function(void) {
    printf("Kernel is at %u-%u\n", kernel_start, kernel_end);
}
Linking it with this command:

Code: Select all

i386-elf-gcc -T linker.ld -ffreestanding -O2 -nostdlib -o kernel.elf boot.o obj/kernel/ACPI.o obj/kernel/RSDP.o obj/kernel/SDT.o obj/kernel/VGA.o obj/kernel/display.o obj/kernel/gdt.o obj/kernel/interrupt_handlers.o obj/kernel/kernel.o obj/kernel/keyboard.o obj/kernel/memory.o obj/kernel/paging.o obj/kernel/serial.o obj/libc/libc.o obj/libc/qsort.o -lgcc
Paging is set up like shown in my previous post:

Code: Select all

mov ebx, physical_address(boot_page_table1)
add ebx, 0x03 ; Set "present" and other flags

; Identity map (virtual 0xbeef -> physical 0xbeef)
mov [physical_address(boot_page_directory) + 0], ebx

; Map for virtual address 0xC0000000 (virtual 0xC0000000 -> physical 0x00)
mov [physical_address(boot_page_directory) + 768 * 4], ebx
...so I skipped the code in the Wiki that was checking "kernel_start" and "kernel_end".

And this prints "Kernel is at 0-0"! But it clearly can't occupy zero bytes!

Why is that?
nullplan
Member
Member
Posts: 1791
Joined: Wed Aug 30, 2017 8:24 am

Re: "Higher Half x86 Bare Bones" from the Wiki triple faults

Post by nullplan »

False syntax. That should have read

Code: Select all

extern const char kernel_start[], kernel_end[];
The important thing is that the value at those symbols does not matter, only the address of those symbol. You might as well just declare them to be normal chars, and always take their addresses, but that has C language connotations that you don't want. Really easy to create undefined behavior this way.

What I wrote means "there is an array of char somewhere under the name kernel_start, and if I just write the name, I want the address of that". What you wrote means "there is a pointer to char somewhere under the name kernel_start, and if I just write the name, I want the content of that". Important difference.
Carpe diem!
ForceBru
Posts: 9
Joined: Thu Aug 20, 2020 2:02 pm

Re: "Higher Half x86 Bare Bones" from the Wiki triple faults

Post by ForceBru »

nullplan wrote: The important thing is that the value at those symbols does not matter, only the address of those symbol. You might as well just declare them to be normal chars, and always take their addresses, but that has C language connotations that you don't want.
I was assuming these symbols themselves contained the address, like pointers, but apparently only their address matters, indeed:

This documentation https://sourceware.org/binutils/docs/ld ... -Reference says:
Accessing a linker script defined variable from source code is not intuitive. In particular a linker script symbol is not equivalent to a variable declaration in a high level language, it is instead a symbol that does not have a value.

<...>

Linker scripts symbol declarations, by contrast, create an entry in the symbol table but do not assign any memory to them. Thus they are an address without a value. So for example the linker script definition:

Code: Select all

foo = 1000;
creates an entry in the symbol table called `foo' which holds the address of memory location 1000, but nothing special is stored at address 1000. This means that you cannot access the value of a linker script defined symbol - it has no value - all you can do is access the address of a linker script defined symbol.
Thanks, didn't know that
Post Reply