GCC wrong .data addresses

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.
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

GCC wrong .data addresses

Post by AlexKuz »

Hi,

I'm working on the second stage loader(in C).
When I switch to the protected mode, an initialized global variables don't work (.data section).
This code doesn't work:

Code: Select all

unsigned short* vmem = (unsigned short*)0xb8000;

void lmain()
{
	for (unsigned int i = 0; i < 80 * 24; i++)
		vmem[i] = 0;

	while (1);
}
But this code works perfectly:

Code: Select all

unsigned short* vmem;

void lmain()
{
	vmem = (unsigned short*)0xb8000;

	for (unsigned int i = 0; i < 80 * 24; i++)
		vmem[i] = 0;

	while (1);
}
I'm compiling using x86_64-elf cross-compiler with these flags:

Code: Select all

-Wall -std=gnu99 -mcmodel=large -ffreestanding -fno-builtin -mno-red-zone -g -fno-stack-protector -fomit-frame-pointer
.
Here's my linker script:

Code: Select all

OUTPUT_FORMAT("binary")

ENTRY(start)

SECTIONS
{
	. = 0x7c00;

	.text : ALIGN(0x200)
	{
		*(.entry)
		*(.text)
	}

	.rodata : ALIGN(0x200)
	{
		*(.rodata)
	}

	.data : ALIGN(0x200)
	{
		*(.data)
	}

	.bss : ALIGN(0x200)
	{
		*(.bss)
	}

	loader_end = .;
}
Help me please! Thanks in advance.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

And what is the first stage loader? BIOS? MBR? Judging from your linker script it is one of these. If it is then you should know that BIOS and MBR loader only loads one sector of data (512 bytes). Since your sections are 512 byte aligned only first section (.text) gets loaded. That would explain why initialized data is not there. Change your section alignment to 1 and see if it helps. BTW. I don't think C is a good language choice for this.

EDIT: Ohh… and when do you switch to protected mode? Custom MBR or something?
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

pvc wrote:And what is the first stage loader? BIOS? MBR? Judging from your linker script it is one of these. If it is then you should know that BIOS and MBR loader only loads one sector of data (512 bytes). Since your sections are 512 byte aligned only first section (.text) gets loaded. That would explain why initialized data is not there. Change your section alignment to 1 and see if it helps. BTW. I don't think C is a good language choice for this.
The first stage loader is an MBR. It reads first sector from the active partition and jumps to the VBR.
The VBR is loading remaining sectors and switches to protected mode.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

Ok. That changes things a little bit. But I would still suggest that you change section alignment to 1 byte to see what happens. Also, are you sure your start address (0x7C00) is right? If your code is linked for that address and you load it somewhere else it may not work since absolute adresses are simply wrong.
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

pvc wrote:Ok. That changes things a little bit. But I would still suggest that you change section alignment to 1 byte to see what happens. Also, are you sure your start address (0x7C00) is right? If your code is linked for that address and you load it somewhere else it may not work since absolute adresses are simply wrong.
Changed section alignment to 1 and start address to 0x8000 but nothing changed.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

It would help to see your loader code.
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

Here it is:

Code: Select all

extern loader_end
extern lmain

section .entry
bits 16

global start
start:
	mov ecx, [bx + 8]

	cli
	xor ax, ax
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov fs, ax
	mov gs, ax

	mov eax, [loader_size]
	shr eax, 9
	inc eax
	mov [dap.sectors], ax

	mov eax, ecx
	inc eax
	mov [dap.lba], eax

	mov [driveid], dl

	mov sp, 0x8000

	mov ah, 0x42
	mov si, dap
	int 0x13
	jc .error

	in al, 0x92
	or al, 2
	out 0x92, al

	cli
	lgdt [GDT32.Pointer]

	mov eax, cr0
	or eax, 1
	mov cr0, eax

	jmp 0x08:start32
.error:
	mov si, disk_error
	call print
	jmp $

print:
	lodsb
	or al, al
	jz .print_done
	mov ah, 0x0e
	int 0x10
	jmp print
.print_done:
	ret

loader_size dd loader_end - 0x8000
driveid db 0

dap:
	.size db 0x10
	.reserved db 0
	.sectors dw 1
	.offset dw 0x8200
	.segment dw 0
	.lba dd 0, 0

disk_error db 'Error: disk read failure!', 13, 10, 0

bits 32
GDT32:
.Null: equ $ - GDT32
	dw 0
	dw 0
	db 0
	db 0
	db 0
	db 0
.Code: equ $ - GDT32
	dw 0xFFFF
	dw 0
	db 0
	db 10011010b
	db 11001111b
	db 0
.Data: equ $ - GDT32
	dw 0xFFFF
	dw 0
	db 0
	db 10010010b
	db 11001111b
	db 0
.Code16: equ $ - GDT32
	dw 0xFFFF
	dw 0
	db 0
	db 10011010b
	db 10001111b
	db 0
.Data16: equ $ - GDT32
	dw 0xFFFF
	dw 0
	db 0
	db 10010010b
	db 00001111b
	db 0
.Pointer:
	dw $ - GDT32 - 1
	dd GDT32

section .text
start32:
	xor eax, eax
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	mov esp, 0x8000

	call lmain
	jmp $
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

I am trying to test your code and I ran into something like this:

Code: Select all

cc1: error: code model ‘large’ not supported in the 32 bit mode
when compiling the .c file with options you provided. I've added -m32 option because my compiler generates 64 bit code by default. Also -mno-red-zone is used for x86-64.
Are you sure you are generating 32 bit code?
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

pvc wrote:I am trying to test your code and I ran into something like this:

Code: Select all

cc1: error: code model ‘large’ not supported in the 32 bit mode
when compiling the .c file with options you provided. I've added -m32 option because my compiler generates 64 bit code by default. Also -mno-red-zone is used for x86-64.
Are you sure you are generating 32 bit code?
Should I generate exactly 32-bit code?
I'm planning to load a 64-bit kernel.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

Yes. You should be generating 32 bit protected mode code for now. You have to get this working before you can switch to 64 bit long mode.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: GCC wrong .data addresses

Post by Schol-R-LEA »

AlexKuz wrote:
pvc wrote:I am trying to test your code and I ran into something like this:

Code: Select all

cc1: error: code model ‘large’ not supported in the 32 bit mode
when compiling the .c file with options you provided. I've added -m32 option because my compiler generates 64 bit code by default. Also -mno-red-zone is used for x86-64.
Are you sure you are generating 32 bit code?
Should I generate exactly 32-bit code?
I'm planning to load a 64-bit kernel.
That depends on just what mode you are in at this point of the loader. It sounds as if you have already switched to protected mode, but you would still need to switch again into long mode to run a 64-bit kernel. To the best of my knowledge, you cannot go directly from real mode to long mode; you need to switch to 32-bit protected mode first, then bump to long mode.

Comments and corrections welcome.

EDIT: hanzo'ed. Oh well.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

@Schol-R-LEA It is possible to do 16->64 bit switch but it's a little bit tricky. It's easier to go 16->32->64.
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

pvc wrote:@Schol-R-LEA It is possible to do 16->64 bit switch but it's a little bit tricky. It's easier to go 16->32->64.
Before switching to long mode, I need to do some things(e.g. load initrd, setup paging, set videomode).
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: GCC wrong .data addresses

Post by pvc »

Actually setting up paging is mandatory for long mode to work.

Personally, I would suggest you to use GRUB. It gets you to stable protected mode environment, allows to load initird, changes video mode for you if you want to and what's most important… allows you to use multiboot image (which is plain old ELF with some extra header in it). What I do myself for testing is to use grub-mkrescue to make .iso image of my OS using files stored in a single directory.

EDIT: Here is a little something for you. You can use it if you want to.
Attachments
long_mode_barebones.tar.gz
Template project files.
(1.58 KiB) Downloaded 118 times
AlexKuz
Posts: 8
Joined: Thu Mar 22, 2018 7:16 am

Re: GCC wrong .data addresses

Post by AlexKuz »

pvc wrote:Actually setting up paging is mandatory for long mode to work.

Personally, I would suggest you to use GRUB. It gets you to stable protected mode environment, allows to load initird, changes video mode for you if you want to and what's most important… allows you to use multiboot image (which is plain old ELF with some extra header in it). What I do myself for testing is to use grub-mkrescue to make .iso image of my OS using files stored in a single directory.

EDIT: Here is a little something for you. You can use it if you want to.
Thank you, but I want to write my own bootloader.
Maybe better to look aside UEFI?
Post Reply