简体   繁体   中英

Unrecognised emulation mode: elf_i386 on MinGW32

I'm trying to make a kernel, and I cannot link the C output with the assembly. The ld . I'm getting the error:

unrecognized emulation mode: elf_i386

I'm using Windows 10 professional with the MinGW32 and MSYS. The code I am using:

link.ld

/*
*  link.ld
*/
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   .data : { *(.data) }
   .bss  : { *(.bss)  }
 }

kernel.c

/*
*  kernel.c
*/
void kmain(void)
{
    const char *str = "my first kernel";
    char *vidptr = (char*)0xb8000;  //video mem begins here.
    unsigned int i = 0;
    unsigned int j = 0;

    /* this loops clears the screen
    * there are 25 lines each of 80 columns; each element takes 2 bytes */
    while(j < 80 * 25 * 2) {
        /* blank character */
        vidptr[j] = ' ';
        /* attribute-byte - light grey on black screen */
        vidptr[j+1] = 0x07;         
        j = j + 2;
    }

    j = 0;

    /* this loop writes the string to video memory */
    while(str[j] != '\0') {
        /* the character's ascii */
        vidptr[i] = str[j];
        /* attribute-byte: give character black bg and light grey fg */
        vidptr[i+1] = 0x07;
        ++j;
        i = i + 2;
    }
    return;
}

kernel.asm

;;kernel.asm
bits 32         ;nasm directive - 32 bit
section .text

global start
extern kmain            ;kmain is defined in the c file

start:
  cli           ;block interrupts
  mov esp, stack_space  ;set stack pointer
  call kmain
  hlt           ;halt the CPU

section .bss
resb 8192       ;8KB for stack
stack_space:

To Compile and link I use:

nasm -f elf32 kernel.asm -o kasm.o
gcc -m32 -c kernel.c -o kc.o
ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o

I'm Using:

  • Gcc 4.8.1
  • Ld 2.25.1
  • Nasm 2.11.09rc1

Why am I getting this error, and how can I fix it?

The standard MinGW/32 LD linker doesn't output ELF binaries. Preferably you would be using an i686 cross-compiler, but if you're not you may be able to get away with the tips below.

It appears you are using Arjun's Let's Write a Kernel tutorial. If you are following that tutorial you have missed a step to make kernel.asm compatible with the GRUB boot loader and QEMU 's -kernel option. Before we start you should read the rest of the tutorial. The following code adds a Multiboot header to kernel.asm to make it GRUB compatible:

;;kernel.asm
bits 32         ;nasm directive - 32 bit
global entry
extern _kmain            ;kmain is defined in the c file

section .text
entry:  jmp start

        ;multiboot spec
        align 4
        dd 0x1BADB002            ;magic
        dd 0x00                  ;flags
        dd -(0x1BADB002 + 0x00)  ;checksum. m+f+c should be zero

start:
        cli           ;block interrupts
        mov esp, stack_space  ;set stack pointer
        call _kmain
        hlt           ;halt the CPU

section .bss
resb 8192       ;8KB for stack
stack_space:

Besides adding a header I've also put an entry label in the file and a jmp start to jump over the Multiboot header. I've done this to make it easy to set a breakpoint at 0x100000 in the future if you start debugging.

One other change is that on MinGW, GCC adds an underscore to function names by default. I've changed references to the C function kmain to _kmain . This differs from the Linux convention.

Since the entry point of our code is now entry instead of start I've modified link.ld to be:

/*
*  link.ld
*/
OUTPUT_FORMAT(pei-i386)    
ENTRY(entry)

SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   .data : { *(.data) }
   .bss  : { *(.bss)  }
 }

Another important change in the file above is the usage of OUTPUT_FORMAT(pei-i386) . This will output a Portable Executable Image (32-bit) rather than an ELF (which isn't supported).

In order to build the kernel and produce an ELF image from the PEI-I386 we can use these commands:

nasm -f elf32 kernel.asm -o kasm.o
gcc -m32 -c kernel.c -o kc.o -ffreestanding -nostdlib -nostdinc
ld -T link.ld -o kernel kasm.o kc.o -build-id=none
objcopy -O elf32-i386 kernel kernel.elf

The LD command has been modified to not write out the build-id to the executable to avoid the Multiboot header from being shifted outside the first 8k of the executable. The GCC options have been modified to produce freestanding code (without the standard library and includes) using the options -ffreestanding -nostdlib -nostdinc . We use objcopy to convert the PEI-I386 file ( kernel ) to an ELF32 image called kernel.elf . You will want to be using kernel.elf with GRUB and/or QEMU .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM