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

我的 32 位保护模式操作系统项目 Sinatra 有问题。我可以将源代码编译为目标文件,但我不知道如何将它们链接在一起。我在 Windows 上使用 NASM 和 TDM-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 脚本。

标签: c assembly x86 nasm tdm-gcc


【解决方案1】:

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

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

那么,你要做的是:

  1. 将汇编源文件组装成目标代码。
  2. 编译但不将 C 源文件链接到目标代码。在 gcc 中:gcc -c file.c -o file.o
  3. 将这些链接在一起。在 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 运行时的绝对地址加载操作系统,所以您需要确保编译为独立代码;您的 asm 和 C 文件以相同类型的对象 (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 部分,这意味着最终图像中不存在要显示的字符串
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
  • 2012-04-24
  • 2013-08-16
  • 2011-06-01
  • 1970-01-01
  • 2015-05-06
相关资源
最近更新 更多