无法识别的仿真模式:MinGW32上的elf_i386 [英] Unrecognised emulation mode: elf_i386 on MinGW32
问题描述
我正在尝试制作内核,并且无法将 C 输出与程序集链接. ld
.我遇到了错误:
I'm trying to make a kernel, and I cannot link the C output with the assembly. The ld
. I'm getting the error:
无法识别的仿真模式:elf_i386
unrecognized emulation mode: elf_i386
我将Windows 10 Professional与MinGW32和MSYS结合使用.我正在使用的代码:
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
我正在使用:
- Gcc 4.8.1
- Ld 2.25.1
- Nasm 2.11.09rc1
为什么会出现此错误,该如何解决?
Why am I getting this error, and how can I fix it?
推荐答案
标准的MinGW/32 LD 链接器不会输出 ELF 二进制文件.最好使用i686交叉编译器,但如果不使用交叉编译器,则可以摆脱下面的提示.
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:
除了添加标题之外,我还在文件中放置了entry
标签,并在jmp start
中放置了跳过Multiboot标题的位置.我这样做是为了便于将来在开始调试时将断点设置为0x100000.
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.
另一个变化是,在MinGW上, GCC 默认情况下在函数名称上添加了下划线.我已将对 C 函数kmain
的引用更改为_kmain
.这与Linux约定不同.
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.
因为我们代码的入口点现在是entry
而不是start
,所以我将link.ld
修改为:
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) }
}
上面文件中的另一个重要更改是OUTPUT_FORMAT(pei-i386)
的用法.这将输出可移植的可执行映像(32位),而不是 ELF (不受支持).
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).
为了构建内核并从 PEI-I386 中生成 ELF 图像,我们可以使用以下命令:
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
LD 命令已被修改为不将build-id写出到可执行文件中,以避免Multiboot标头移到可执行文件的前8k之外. GCC 选项已经过修改,可以使用选项-ffreestanding -nostdlib -nostdinc
生成独立代码(不包含标准库和包含项).我们使用objcopy
将 PEI-I386 文件(kernel
)转换为名为kernel.elf
的 ELF32 图像.您将要在 GRUB 和/或 QEMU 中使用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.
这篇关于无法识别的仿真模式:MinGW32上的elf_i386的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!