如何在 Windows 上为我的操作系统编译和链接 C 和 ASM

Posted

技术标签:

【中文标题】如何在 Windows 上为我的操作系统编译和链接 C 和 ASM【英文标题】:How to compile and link C and ASM together on Windows for my OS 【发布时间】:2015-08-28 20:52:24 【问题描述】:

我的 32 位保护模式操作系统项目 Sinatra 有问题。我可以将源代码编译为目标文件,但我不知道如何将它们链接在一起。我在 Windows 上使用 NASMTDM-GCC。我已经修复了我的代码的问题,因此它可以编译。为简洁起见,我删除了 cmets。

我的档案boot.asm

[BITS 32]
[global start]
[extern _JlMain]
start: 
    cli
    call _JlMain
    hlt

我的档案JSinatra.h

#ifndef __SINATRA_H__
#define __SINATRA_H__

#define JWhiteText 0x07
void JlMain();
void JlClearScreen();
unsigned int JlPrintF(char * message, unsigned int line);

#endif

我的档案JSinatra.c

#include "JSinatra.h"

void JlClearScreen() // clear entire screen

    char * vidmem = (char * ) 0xb8000;
    unsigned int i = 0;
    while (i < (80 * 25 * 2)) 
        vidmem[i] = ' ';
        i += 1;
        vidmem[i] = JWhiteText;
        i += 1;
    

unsigned int JlPrintF(char * message, unsigned int line) 
    char * vidmem = (char * ) 0xb8000;
    unsigned int i = 0;
    i = line * 80 * 2;
    while ( * message != 0) 
        if ( * message == '\n') 
            line += 1;
            i = (line * 80 * 2); * message += 1;
         else 
            vidmem[i] = * message; * message += 1;
            i += 1;
            vidmem[i] = JWhiteText;
            i += 1;
        
    
    return (1);

void JlMain() 
    JlClearScreen();
    JlPrintF("Sinatra v0 Virgin/Kernel Mode\n", 0);

我需要从绝对地址0x100000 开始加载我的操作系统。如何正确编译和链接我的代码以创建二进制图像?

【问题讨论】:

您使用的是什么编译器和链接器工具链?使用 GCC 和 GNU binutils,这是微不足道的。 C 和汇编文件都会生成 ld 知道如何链接的 ELF 文件。抱歉,您的问题非常含糊,我认为您需要先了解一些基础知识,然后再询问我们如何帮助您的操作系统项目。 我正在使用 GCC/G++(在我看来,它们是相同的)和 Netw。 Windows 中的汇编程序。正如我所说,我有源文件,但我不明白 ld 也不知道应该如何使用链接器脚本。 什么“Windows 中的汇编程序”?听起来很糟糕。 很抱歉,这对于 Stack Overflow 来说太宽泛了。我们不可能在一个问题中教你所有你需要知道的关于编译器、汇编器、链接器、链接器脚本等的知识。我强烈建议您自己进行研究,通过查找教程和示例代码,您可以从中学习。 对不起,宽泛。正如我所说,我不知道链接器脚本,我正在在线添加其中一个 ld 脚本。 【参考方案1】:

首先,如果您要编译为 ELF,那么您不能在汇编中的函数之前添加初始下划线。

现在,为了将不同的源文件链接在一起,您显然必须让它们有共同点,在这种情况下,就是目标代码。

那么,你要做的是:

    将汇编源文件组装成目标代码。 编译但不将 C 源文件链接到目标代码。在 gcc 中:gcc -c file.c -o file.o 将这些链接在一起。在 gcc 中:gcc cfile.o asfile.o -o app

【讨论】:

asfile.o:文件无法识别:文件格式无法识别 -- collect2.exe:错误:ld 返回 1 退出状态@amr-ayman 尝试 32 位的 -m32 选项。 -m64 用于 64 位。【参考方案2】:

在 Windows 上使用 GCC-TDM 和 NASM

因为您的目标是在没有 C 运行时的绝对地址加载操作系统,所以您需要确保编译为独立代码;您的 asmC 文件以相同类型的对象 (win32/PECOFF) 为目标;最后一步是将 PECOFF 文件转换为二进制图像。

要编译 C 文件,你会使用类似的东西:

gcc -m32 -ffreestanding -c JSinatra.c -o JSinatra.o

要组装 asm 文件,您可以使用以下内容:

nasm -f win32 boot.asm -o boot.o

要将它们链接在一起,您必须分两步完成:

ld -m i386pe -T NUL -o sinatra.tmp -Ttext 0x100000 boot.o JSinatra.o

上面的ld 命令将创建一个临时文件sinatra.tmp,它是一个32 位PECOFF 可执行文件。然后,您需要使用以下命令将sinatra.tmp 转换为二进制图像:

objcopy -O binary sinatra.tmp sinatra.img

你应该在文件sinatra.img中有一个二进制图像

【讨论】:

ld:无法识别的仿真模式:elf_i386,支持的仿真:i386pe @MichaelPetch ld: 无法对非 PE 输出文件 'sinatra' 执行 PE 操作。 @MichaelPetch 它说的一样! (而且我使用 TDM-GCC、Cygwin 或 MinGW 需要几个世纪才能安装......)@MichaelPetch 你来的时候请通知我。 @MichaelPetch @AraneaSerket6848 :我刚刚更新了答案。我原来的ld 命令出错了,因为我无意中删除了.text 部分,这意味着最终图像中不存在要显示的字符串

以上是关于如何在 Windows 上为我的操作系统编译和链接 C 和 ASM的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Windows 上为 CUDA 链接库(例如 CUBLAS、CUSPARSE)

如何在 Windows 上为 CUDA 链接库(例如 CUBLAS、CUSPARSE)

Qt - 在 Windows 上为 Linux 交叉编译

如何从多台机器上为我的 django 网站提供服务,即如何使其分布式?

我无法在 Windows 7 上为我的 arduino-uno 执行我的 js 文件。(我遇到了端口问题)

使用动态链接在 Linux 上为 Windows 交叉编译 Qt 应用程序