简体   繁体   English

无法识别的仿真模式:MinGW32上的elf_i386

[英]Unrecognised emulation mode: elf_i386 on MinGW32

I'm trying to make a kernel, and I cannot link the C output with the assembly. 我正在尝试创建一个内核,我无法将C输出与程序集链接起来。 The ld . ld I'm getting the error: 我收到错误:

unrecognized emulation mode: elf_i386 无法识别的仿真模式:elf_i386

I'm using Windows 10 professional with the MinGW32 and MSYS. 我正在使用Windows 10专业版与MinGW32和MSYS。 The code I am using: 我正在使用的代码:

link.ld link.ld

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

kernel.c 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

;;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 Gcc 4.8.1
  • Ld 2.25.1 Ld 2.25.1
  • Nasm 2.11.09rc1 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. 标准MinGW / 32 LD链接器不输出ELF二进制文件。 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. 您最好使用i686交叉编译器,但如果不是,您可以使用下面的提示。

It appears you are using Arjun's Let's Write a Kernel tutorial. 看来你正在使用Arjun的Let's Write a Kernel教程。 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. 如果你正在跟踪该教程你已经错过了一步,使kernel.asm使用GRUB引导加载程序和QEMU的兼容-kernel选项。 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标头添加到kernel.asm以使其与GRUB兼容:

;;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. 除了添加标题之外,我还在文件中放入了一个entry标签,并且jmp start跳过Multiboot标头。 I've done this to make it easy to set a breakpoint at 0x100000 in the future if you start debugging. 我已经这样做了,如果你开始调试,将来很容易设置一个断点在0x100000。

One other change is that on MinGW, GCC adds an underscore to function names by default. 另一个变化是,在MinGW上, GCC默认为函数名添加下划线。 I've changed references to the C function kmain to _kmain . 我已经将对C函数kmain引用更改为_kmain This differs from the Linux convention. 这与Linux惯例不同。

Since the entry point of our code is now entry instead of start I've modified link.ld to be: 由于我们的代码的入口点现在是entry而不是start我已经修改了link.ld

/*
*  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) . 上面文件中的另一个重要变化是使用OUTPUT_FORMAT(pei-i386) This will output a Portable Executable Image (32-bit) rather than an ELF (which isn't supported). 这将输出可移植可执行映像(32位)而不是ELF (不支持)。

In order to build the kernel and produce an ELF image from the PEI-I386 we can use these commands: 为了构建内核并从PEI-I386生成ELF图像,我们可以使用以下命令:

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. 已修改LD命令,以便不将build-id写入可执行文件,以避免Multiboot标头移出可执行文件的前8k。 The GCC options have been modified to produce freestanding code (without the standard library and includes) using the options -ffreestanding -nostdlib -nostdinc . 已修改GCC选项以使用-ffreestanding -nostdlib -nostdinc选项生成独立代码(没有标准库和包含)。 We use objcopy to convert the PEI-I386 file ( kernel ) to an ELF32 image called kernel.elf . 我们使用objcopyPEI-I386文件( kernel )转换为名为kernel.elfELF32映像。 You will want to be using kernel.elf with GRUB and/or QEMU . 您将希望将kernel.elfGRUB和/或QEMU一起使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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