0

Im following this tutorial on how to make a simple bootable kernel: http://www.osdever.net/tutorials/view/writing-a-simple-c-kernel

there are the following required files in the tutorial:

kernel.c source code:

#define WHITE_TXT 0x07 // white on black text

void k_clear_screen();
unsigned int k_printf(char *message, unsigned int line);


k_main() // like main in a normal C program
{
    k_clear_screen();
    k_printf("Hi!\nHow's this for a starter OS?", 0);
};

void k_clear_screen() // clear the entire text screen
{
    char *vidmem = (char *) 0xb8000;
    unsigned int i=0;
    while(i < (80*25*2))
    {
        vidmem[i]=' ';
        i++;
        vidmem[i]=WHITE_TXT;
        i++;
    };
};

unsigned int k_printf(char *message, unsigned int line) // the message and then the line #
{
    char *vidmem = (char *) 0xb8000;
    unsigned int i=0;

    i=(line*80*2);

    while(*message!=0)
    {
        if(*message=='\n') // check for a new line
        {
            line++;
            i=(line*80*2);
            *message++;
        } else {
            vidmem[i]=*message;
            *message++;
            i++;
            vidmem[i]=WHITE_TXT;
            i++;
        };
    };

    return(1);
};

kernel_start.asm source code:

[BITS 32]

[global start]
[extern _k_main] ; this is in the c file

start:
  call _k_main

  cli  ; stop interrupts
  hlt ; halt the CPU

link.ld source code:

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
  .text  0x100000 : {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(4096);
  }
  .data  : {
    data = .; _data = .; __data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss  :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .; _end = .; __end = .;
}

The instructions to compile it are:

nasm -f aout kernel_start.asm -o ks.o
gcc -c kernel.c -o kernel.o
ld -T link.ld -o kernel.bin ks.o kernel.o

i am able to successfully execute the first two lines:

nasm -f aout kernel_start.asm -o ks.o
gcc -c kernel.c -o kernel.o

then when i try and run this line :

ld -T link.ld -o kernel.bin ks.o kernel.o

I get the error:

C:\basic_kernel>ld -T link.ld -o kernel.bin ks.o kernel.o
ks.o: file not recognized: File format not recognized

Does anyone know why this is and how I could fix this? I'm using windows 7 64 bit

P'sao
  • 2,946
  • 11
  • 39
  • 48

4 Answers4

4

You need to change -f aout to -f elf in order to link the produced object file.

Modern linkers will be expecting ELF and/or Windows PECOFF; yours clearly doesn't recognize the obsolete a.out object-file format.

NASM defaults to flat binary mode when not given a format with the -f option, so removing it entirely isn't what you want.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Rudster816
  • 41
  • 1
1

Your gcc and ld are probably expecting PECOFF or ELF object files, rather than a.out, which is old and obsolete. Try replacing the -f aout from your nasm invocation with -f elf for an ELF32 .o or -f win32 for a PECOFF .obj

(Removing -f entirely gives you the default -f bin flat binary, like for a .com executable or MBR bootsector, not a linker input.)


If that doesn't work, try naming this file ks.s, assembling it with gcc ks.s -c -o ks.o, and using it instead of the ks.o / kernel_start.asm you have:

    .text
    .code32
    .globl start
start:
    call _k_main
    cli
    hlt

Warning: It doesn't show up in this example, but the instruction syntax used when you write assembly this way is very different from what you might be expecting. This SO question links to a guide. Using GAS's .intel_syntax noprefix directive will give you different syntax than NASM; it's more like MASM.


Additional wrinkle to be aware of: there are excellent odds that you should not have an underscore at the beginning of the symbol _k_main in the assembly. Underscores at the beginning of all symbols defined in C is how it worked in a.out, but is not done in ELF. I don't know about PECOFF.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
zwol
  • 135,547
  • 38
  • 252
  • 361
  • 1
    If I remove the "-f aout" I get the error: "kernel_start.asm:21: error: binary output format does not support external references" – P'sao Mar 21 '12 at 20:09
  • Never mind the first comment. When i tried the linker line i get this: ld: cannot perform PE operations on non PE output file 'kernel.bin'. Any ideas? – P'sao Mar 21 '12 at 21:38
  • I'm running out of ideas here, I've never tried to do this myself. It *might* help if you ran the commands `gcc --version`, `as --version`, and `ld --version` and added the output to your question. – zwol Mar 22 '12 at 02:15
  • @P'sao: The default output format is `-f bin` (flat binary). You probably want `-f elf` for ELF or `-f win32` for PECOFF. Removing `-f` entirely can't work. – Peter Cordes Apr 10 '19 at 02:06
  • @PeterCordes Thanks for the update. I have never used NASM myself. I recall that when I wrote this question I tried to look up what its default output format was in its manual but didn't have any luck. – zwol Apr 10 '19 at 15:24
0

I don't use windows so I do not know how this would apply to your problem, but I once had the same issue while compiling my kernel (ld gave me the same error code). The problem was that my code was being compiled by clang instead of being compiled by my toolchain's GCC, so therefore when my toolchain's ld tried to link it, it couldn't read the object files because they weren't in the format it was expecting. If you are not using an x86 toolchain (cross-compiler) use one and make sure you are using the GCC included in that toolchain to compile your files.

Jacob Soffer
  • 304
  • 1
  • 2
  • 13
0

Replace _k_main by k_main in kernel.asm like this:

[BITS 32] 

[global start]
[extern k_main] ; include the c kernel

start:
    call k_main ; call the c kernel

    cli  ; stop interrupts
    hlt ; halt the CPU
Henry
  • 577
  • 4
  • 9
  • `BITS 32` doesn't inform the CPU, it informs the *assembler* which mode the CPU will be in. Putting `BITS 64` at the top of a file won't make the CPU switch to 64-bit mode when running the file, it will just make 64-bit machine code that decodes incorrectly in 32-bit mode (e.g. if you assemble it into a 32-bit executable.) – Peter Cordes Apr 10 '19 at 18:01