Page 1 of 1

Basic boot loader using GAS

Posted: Sun Sep 29, 2013 3:29 pm
by Adel
Hey,

I am working to get a very basic(hello-world thing) boot-loader running; I read some examples online, followed their steps and got it working.
Using

Code: Select all

nasm -f bin
, then copy it to a floppy and use qemu to load it.

What I am trying to do now is simply re-do that but using GAS (my brain's convinced me I am more familiar with AT&T syntax, somehow).

So here's my code, I added some comments as I was trying to understand each step.
Please let me know if these indicate any problem with my understanding of what's going on:

Code: Select all

	.code16			# 16-bit assembly 
	.org 0x7C00		# We MUST be loaded here 


	#	L0 is loop-begining and L1 is loop exit
	#	BIOS INT 10H: (Video)
	#	AH: 0EH (the type of the printing - here Teletype)
	#	AL: The character I will print
	#	BH: 00H (The video page number)
	#	BL: 02H (Color of the text - 0/black back , 2/green front)
	
	movw $my_hello, %si	#Put the &my_hello[0] in the %si
	call print_string
	jmp .			#Jump to self - loop forever
	
print_string:
L0:
	movb (%si), %al		#Move the character to AL for printing
	cmpb $0, %al		#Did we reach the \0 terminator?
	je   L1			#Yes? Jump to end
	call print_char		#No?  Print the character
	inc  %si		#Increment to the next character
	jmp  L0			#Repeat
L1:
	ret

print_char:
	#CAREFUL: I am assuming the char is in the AL already
	movb $0x0E, %ah		#Teletype
	movb $0x00, %bh		#Page No: 0
	movb $0x02, %bl		#black|green
	int  $0x10		#Calling the bios
	ret
	
	#My Data
	my_hello:
		.asciz "Hello, world!"
	.org .+510, 0		#Move the location counter to current+510
				#and pad in between with 0s
	.word 0xAA55		#end with the bootloader marker
Next, I assembled it with as; that produces an ELF so I used

Code: Select all

objcopy -O
binary and then copied it using

Code: Select all

dd
and loaded it with

Code: Select all

qemu-system-i386
; it complained that the floppy is not bootable.

In what step have I erred here? Any tips where I should be looking for the error?
I used hexdump to compare the binary outputs of both my NASM and GAS attempts, they seem to differ but I am not sure why; is it something related to the

Code: Select all

.org
instruction?

Another question:
The same assembly in nasm syntax worked; how did it work properly when I didn't set the stack segment, considering that I have used the call and the ret instructions? Am I missing something here?

Thanks,

Re: Basic boot loader using GAS

Posted: Mon Sep 30, 2013 12:20 am
by iansjack
You are moving the program counter too far when writing the boot signature. .+510 moves it 510 bytes from the current location; you want 510 bytes from the start of the program.

Re: Basic boot loader using GAS

Posted: Mon Sep 30, 2013 9:00 am
by Adel
Ouch :oops:
Thanks for pointing that out.

The problem persists, though; I noticed that when copying the binary file using dd I somehow copy 32KBs.
(When I was following the many examples online using NASM, dd reported copying exactly 512 bytes)

Do you suggest any place of where I should be looking?

Re: Basic boot loader using GAS

Posted: Mon Sep 30, 2013 9:23 am
by Combuster
Start by looking where everything you wanted actually ended up in those 32kb. I'm guessing you start off with either platform-specific garbage or 0x7C00 bytes worth of zeroes. Then you can check each of the intermediated to see where it came from.

You'll probably be going to end up with a linker script to get the actual placement for a flat binary right.

Or... *drumroll* NASM :wink:

Re: Basic boot loader using GAS

Posted: Tue Oct 01, 2013 2:26 pm
by Adel
Just so others can avoid such a mistake, let me explain what was going on and what's the fix:

The problem:
The ".org" directive at the beginning actually says: Move the location counter from 0x0 to 0x7C00 and padd the in-between area with 0s.
Hence why dd was reporting a large block being copied.

The fix:
What I did is that I removed the .org directive; how would I then make sure that the binary will be loaded at the correct place in memory?
"ld --Ttext 0x7C00" does it, it says that the text section starts there; and while we are at it, there's no point in using objcopy, just add the flag "--oformat binary" to the ld to convert the ELF file "as" gave us into a flat binary file and it's all done.


The next thing that I am still missing is:
How is the routine calling working when I am not setting the stack segment? As far as I read, nothing guarantee that it has some default value all the time, maybe I missed something?

Re: Basic boot loader using GAS

Posted: Tue Oct 01, 2013 3:16 pm
by iansjack
The BIOS initialization will have set SS and SP to some values (offhand, without looking, I've no idea what these values are or whether they are the same for different BIOS implementations). It just so happens that in your case these values correspond to valid memory locations that you are not otherwise using. So you have a stack that is enough to make at least one level of subroutine/interrupt call - it's just that you don't know where that stack is or how much stack you can safely use (if any).

Clearly this is very bad practice and is liable to lead to tears before bedtime. Do the decent thing and set up a stack that is under your control before you start using it.

Re: Basic boot loader using GAS

Posted: Wed Oct 02, 2013 1:57 am
by Combuster
Basic sanity says that the bios does leave a "working" stack for its own use because the timer interrupt would have to run, and you can assume it's not overlapping 0x7C00-0x7E00 because then timer interrupts would mess up the bootsector - possibly before your code would even get run.

That said, anything but the most trivial bootsectors access something outside this safe range, and might potentially even perform enough nested calls to overflow the stack, so not setting SS/SP is always listed as a bug upon code review for good reason. It just so happens that by means of probability, quite a few unknowing people are lucky enough get away without it :wink:

And to be honest, I've never caught someone actually getting hit by that stack issue, because when both symptoms do happen there's always something else wrong as well. :-k