3

I was following these tutorials to make a simple kernel that I would then load using GRUB. The instructions for compiling didn't work (ld couldn't find the -T option) and when I finally got a compiled file it was in Macho format. What are the correct steps to take when compiling these files on Mac.
Edit:
I compiled the code on an Ubuntu virtual machine and I so I have the kernel.bin file. Now how can I make a bootable image that runs the kernel?

None
  • 3,875
  • 7
  • 43
  • 67

3 Answers3

4

There are a few things you'll need to do for this to work.

First, you need to make sure that nasm, gcc, and ld are creating macho i386 binaries. This means passing -f macho to nasm, -m32 to gcc, and -arch i386 to ld or else you'll get x86_64 macho binaries.

Second, GRUB doesn't support macho binaries - it only comes with out-of-the-box support for ELF binary formats. But that's not a problem - you can tell GRUB exactly what to do in order to boot your macho kernel by using the multiboot header.

In particular, you need to set the 16th bit of FLAGS in the multiboot header:

FLAGS 1<<16 | whateverelse

This will tell GRUB to take info about where to load the kernel from you instead of trying to figure this out automatically.

Now you need to tell GRUB this information. In particular, there are 4 fields that GRUB (or any multiboot-compatible bootloader) needs in order to load a kernel in any binary format:

  • header_addr: The physically memory location your kernel expects to be located at. Set it equal to the address of the .text section. (Hint: Place a label right after .text and simply refer to it here)
  • load_addr: The address that GRUB should start loading from disk. In macho's case, .text is the first address, so we also set this to .text's location
  • load_end_addr: Where GRUB should stop loading. Usually, something like stack+STACKSIZE would work.
  • bss_end_addr: Where the end of the BSS section is located. In macho, it's right there at the end, so setting it equal to load_end_addr will work.
  • entry_addr: The entry point for your kernel code. On OS X, this defaults to start though according that guide it is loader.

My sample code for this:

global start           ; making entry point visible to linker
extern _kmain            ; kmain is defined elsewhere

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
MACHO       equ  1<<16
FLAGS       equ  MODULEALIGN | MEMINFO | MACHO  ; this is the Multiboot 'flag' field
MAGIC       equ  0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text
align 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM
   dd MultiBootHeader
   dd MultiBootHeader
   dd stack+STACKSIZE
   dd stack+STACKSIZE
   dd start

; reserve initial kernel stack space
STACKSIZE equ 0x4000                  ; that's 16k.

start:
   mov esp, stack+STACKSIZE           ; set up the stack
   push eax                           ; pass Multiboot magic number
   push ebx                           ; pass Multiboot info structure

   call  _kmain                       ; call kernel proper

   cli
hang:
   hlt                                ; halt machine should kernel return
   jmp   hang

section .bss
align 4
stack:
   resb STACKSIZE                     ; reserve 16k stack on a doubleword boundary

Having done so, when you tell GRUB to load your kernel with the kernel 200+x command, you'll see a "multiboot-kludge" message pop up on the screen with information about where everything will be loaded from. Typing in boot will load your macho kernel and you'll be set!

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
3

You can't do this on a Mac directly, because Macs use EFI as their bootloader (kind of). Your best bet for this kind of stuff is to go download Sun VirtualBox and make a Linux VM - this has the additional advantage that you can take snapshots so if things go pear-shaped you can always roll back (easy to corrupt the HD when you get to writing the I/O routines).

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
0

I've used rEFIt to make bootloaders for Windows and Linux compatible (or not so nasty) with the Mac bootloader.

If you want a Mac VM environment, I've heard Q is good and I've used VMWare's Fusion personally.

adam_0
  • 6,920
  • 6
  • 40
  • 52
  • 1
    How does the bootloader not allow me to use linker scripts? I think it has something to do with Mac's using the BSD linker instead of the GNU linker. I don't want to burn and run the OS on my Mac, I just want to compile it into a bootable image. – None Aug 06 '10 at 03:25