Hello gurus:

I have been playing with AT&T syntax for a bit, trying to make a bootloader. The only problem is that when I test it out, it doesn't appear to be bootable.  I figured that it was the syntax, but when I checked it again, GAS didn't complain, and the syntax looked alright.  The problem is, the file output file is HUGE.  I don't know what is causing this (probably a n00b mistake), but here is the code:


/*XIX System 19 Bootsector - Version 1.00*/
/**/
/*The Purpose of this bootsector is to load the second stage of the XIX Bootloader*/
/*into memory.*/
/**/
/*This is the case, in order to circumvent the now-restricting 512 (actuall ~440)*/
/*byte limit of the MBR, and to allow future implementations of error handling,*/
/*error logging, hardware diagnostics/portability, and multi-boot support.*/
/**/
/*For ful documentation, read the source-enclosed bootsector.img.doc file*/

.code16 #tell the assembler that this code is in 16-bit real mode
.org 0x7C00 #tell the assembler that this code will be in 0x7C00 in memory

begin:
jmp boot #jump over the data section into the code


/*Section for Functions*/
prntstr:
movb $0x0E, %ah #tell int 0x10 that we want to print a character

movb $0x00, %bh #tell int 0x10 to print on first page
movb $0x000A, %bl #tell int 0x10 to print in Green Text, Black Background, non-flashing

prntstr.nxtchar: #label to jump to in AL is not equal to 'null'
lodsb #will load string in SI into AL for printing

or %al, %al #will check for 'null' character
jz prntstr.rtrn #if zero flag is set, will jump to .return

int $0x10 #call int 0x10 to print the string on-screen
jmp prntstr.nxtchar #jump to .nxtchar if job not done

prntstr.rtrn: #label to jump to if 'null' character detected
ret #return to main program

readsk:
readsk.rst: #label for the reset portion of the function, to reset the floppy drive
movb $0x00, %ah #indicate that the drive is to be reset
movb $0x00, %dl #the drive to be reset is a floppy

int $0x13 #call int 0x13 to reset floppy
jc readks.rst #jump if carry flag is reset (if the reset failed)

movw $0x7E00, %ax #the position that the second-stage will be loaded into memory at
movw %ax, %es #load memory position into ES
xor %bx, %bx #clear BX (which indicates offset to int 0x13 (we don't want any))

readsk.read: #label for the reading portion of the function
movb $0x02, %ah #indicate that the drive is to be read
movb $0x01, %al #read 1 sector
movb $0x01, %ch #track 1
movb $0x02, %cl #sector 2
movb $0x00, %dh #head 0 (first head)
movb $0x00, %dl #the drive to be read from is a floppy

int $0x13 #call int 0x13 to read from floppy
jc readks.read #try to read again if error occurs (if carry flag is 1)
ret


/*Section for Strings*/
sysmess: .asciz "XIX System 19 Bootsector - Version 1.00 \n \n Will Now load the Bootloader" #system information string (\n is newline)


/*Main Programm*/
boot:
movw $sysmess, %ax #load the string to be printed into AX register and then load into SI
movw %ax, %si #we need to do this because it cannot be done directly
call prntstr #call the printing function

#call readsk #call the disk reading function

#jmp $0x7C00:$0x0200 #jump to instruction residing in 0x7E00

cli #REMOVE AFTER TEST
hlt #REMOVE AFTER TEST


/*Bootloader Code*/
.org 0x7DFE #move to 0x7C00:0x1FE
.word 0xAA55 #append the bootsector signature


I am in need of this simple code, and would really appreciate help.
Posted on 2009-10-01 21:22:06 by XeonX369
bump
Posted on 2009-10-02 09:23:58 by XeonX369
how did you assemble this?
Posted on 2009-10-02 12:43:28 by lone_samurai5
I assembled this like so:

as -o

just as simple as that, with the braces being replaced with filenames, ofcourse
Posted on 2009-10-05 09:22:41 by XeonX369
its probably outputting to elf format.. try making a flat binary..
Posted on 2009-10-05 21:47:45 by lone_samurai5
Sorry for the extended absence, I had temporarily 'given-up' this small portion of my project.  I feel need to revisit it, as I am re-writing my bootsector.  Truth be told,  I cannot find any information on the web or in the GNU AS manual about outputting to Flat Binary format.
Posted on 2010-01-07 09:30:14 by XeonX369
I thought the trick was "as -o myboot.o myboot.S"/"ld -o myboot.bin --oformat binary myboot.o". However (after fixing some typos in your code that prevented it from assembling at all), I get a message from ld about "relocation truncated to 16-bit" - as it should be (I think) - and no output at all! No idea what the problem is.

I wouldn't want to influence your choice of assembler (much), but this is a whole lot easier with Nasm. :)

Best,
Frank

Posted on 2010-01-07 22:35:16 by fbkotler
Yes, I am beginning to believe that NASM is indeed better than GAS AT&T syntax.  To me, this whole GAS idea was a product of me wanting to 'code in a distinct syntax,' an opinion which I now rebuke as I see indeed than NASM is close to (if not THE) Intel Syntax defined in the Intel Manuals.  I would rather code in Intel Syntax for an Intel processor, and have access to the wide variety of documents and tutorials utilizing Intel Syntax, instead of having to 'translate' to GAS AT&T.

Thank you for your detail about what commands you used;  I too cannot get this to work.  In short, I am sticking with NASM.

Thank's once again for your opinion and all help.  Happy Coding.
Posted on 2010-01-08 09:36:57 by XeonX369

To me, this whole GAS idea was a product of me wanting to 'code in a distinct syntax,' an opinion which I now rebuke as I see indeed than NASM is close to (if not THE) Intel Syntax defined in the Intel Manuals.


The problem is that GAS is meant to be a back-end to GCC and wasn't really designed to be used outside of that toolchain. You can attempt to use it in unintended ways, and it may work at times, but don't be surprised when it fails to produce expected or desirable results.

NASM was developed to resemble more like MASM/TASM (Intel) than GAS (AT&T), obviously, but more with instruction unambiguity in mind. Short of defines/macros, you should be able to take a line of NASM compatible code and tell precisely what it going on.

If you still want to use AT&T syntax, but perhaps use an assembler that is more like NASM, then take a look at YASM. I can't vouch for how well YASM supports AT&T syntax, but it might fit your needs.
Posted on 2010-01-08 11:06:01 by SpooK
Yeah, Gas was originally 32-bit only. Early versions of Linux used "as86" and "ld86" for the bootsector (and other 16-bit? if any?). The 16-bit capability of Gas is an "extension". Gas also got the ".intel_syntax" directive - which wasn't for gcc's convenience, so the binutils guys are thinking at least a little about human users.

But this isn't really a "syntax" issue, it's a "command line" issue. We just don't know how to do it in Gas. Nasm was designed to output multiple formats, including flat binary - we even do as86-style objects for ld86! Rod Pemberton posted this link the other day:

http://www.ludd.luth.se/~ams/gnu_dos_com/

It's about .com files, but might be useful. Speaks about "linker script" files needed to make it work. Perhaps that's the answer...

I observed, by disassembling the large .o file that (G)as produces, that it has exactly the code we want, needing no further work from ld. There's just a lot of stuff before and after. Unix utilities "head" and "tail" to the rescue!




/*XIX System 19 Bootsector - Version 1.00*/
/**/
/*The Purpose of this bootsector is to load the second stage of the XIX Bootloader*/
/*into memory.*/
/**/
/*This is the case, in order to circumvent the now-restricting 512 (actuall ~440)*/
/*byte limit of the MBR, and to allow future implementations of error handling,*/
/*error logging, hardware diagnostics/portability, and multi-boot support.*/
/**/
/*For ful documentation, read the source-enclosed bootsector.img.doc file*/


# as -o myboot.o myboot.S
# tail --bytes=1208 myboot.o>myboot.t1
# head --bytes=512 myboot.t1>myboot.bin
# dd if=myboot.bin of=/dev/fd0


.section .text
.code16      #tell the assembler that this code is in 16-bit real mode
.org 0x7C00  #tell the assembler that this code will be in 0x7C00 in memory

.globl _start

_start:
begin:
  jmp boot  #jump over the data section into the code


/*Section for Functions*/
prntstr:
  movb $0x0E, %ah      #tell int 0x10 that we want to print a character

  movb $0x00, %bh      #tell int 0x10 to print on first page
  movb $0x000A, %bl  #tell int 0x10 to print in Green Text, Black Background, non-flashing

  prntstr.nxtchar:  #label to jump to in AL is not equal to 'null'
  lodsb        #will load string in SI into AL for printing

  or %al, %al      #will check for 'null' character
  jz prntstr.rtrn      #if zero flag is set, will jump to .return

  int $0x10      #call int 0x10 to print the string on-screen
  jmp prntstr.nxtchar  #jump to .nxtchar if job not done

  prntstr.rtrn:      #label to jump to if 'null' character detected
ret            #return to main program

readsk:
  readsk.rst:      #label for the reset portion of the function, to reset the floppy drive
  movb $0x00, %ah      #indicate that the drive is to be reset
  movb $0x00, %dl      #the drive to be reset is a floppy

  int $0x13      #call int 0x13 to reset floppy
  jc readsk.rst      #jump if carry flag is reset (if the reset failed)

  movw $0x7E00, %ax  #the position that the second-stage will be loaded into memory at
  movw %ax, %es      #load memory position into ES
  xor %bx, %bx      #clear BX (which indicates offset to int 0x13 (we don't want any))

  readsk.read:      #label for the reading portion of the function
  movb $0x02, %ah      #indicate that the drive is to be read
  movb $0x01, %al      #read 1 sector
  movb $0x01, %ch      #track 1
  movb $0x02, %cl      #sector 2
  movb $0x00, %dh      #head 0 (first head)
  movb $0x00, %dl      #the drive to be read from is a floppy

  int $0x13      #call int 0x13 to read from floppy
  jc readsk.read      #try to read again if error occurs (if carry flag is 1)
ret


/*Section for Strings*/
sysmess: .asciz "XIX System 19 Bootsector - Version 1.00 \n \n Will Now load the Bootloader"  #system information string (\n is newline)


/*Main Programm*/
boot:
# set %ds to where we are - bios may not have done this!
  movw $0, %ax
  movw %ax, %ds

#  movw $sysmess, %ax      #load the string to be printed into AX register and then load into SI
#  movw %ax, %si        #we need to do this because it cannot be done directly
# yes, it can...
  movw $sysmess, %si

  call prntstr        #call the printing function

  #call readsk        #call the disk reading function

  #jmp $0x7C00:$0x0200      #jump to instruction residing in 0x7E00
#wrong! $0x07C0:$0x0200 (or 0x0:0x7E00)

  cli            #REMOVE AFTER TEST
  hlt            #REMOVE AFTER TEST


/*Bootloader Code*/
.org 0x7DFE        #move to 0x7C00:0x1FE
# comment is wrong.

.word 0xAA55        #append the bootsector signature



This "works for me". The only "important" change I made was to explicitly load ds with zero. Without that, it'll work on some machines - if the bios leaves zero in ds, which is fairly common... but not on other machines, which is not *that* uncommon.

There's gotta be a better way than "head" and "tail", but... it works...

If you want help translating this to Nasmese, just ask. The command "nasm myfile.asm" will produce just "myfile". You might want "nasm -f bin myboot.asm -o myboot.bin"... or ".img", whatever...

Happy bootin'
Frank

Posted on 2010-01-09 05:18:11 by fbkotler

Speaks about "linker script" files needed to make it work. Perhaps that's the answer...


Yeah, the general trick in getting GCC/GAS to output a binary lies with the link stage... although that should not be all too surprising.

A linker script can be useful for multiple sections, e.g. for a kernel, but when a simple MBR is involved the following should suffice:


as -o boot.o boot.s
ld --oformat binary -static -Ttext 0x7C00 -o boot.bin boot.o
Posted on 2010-01-09 12:17:55 by SpooK