DOS 的 GCC 交叉编译器在 C 中产生简单的 "Hello world!"链接器错误

标签 gcc x86 linker dos djgpp

我尝试配置 GCC 9.3.0 来生成 DOS 的可执行文件。然而,对于一个简单的“Hello world!” C 程序,输出:

/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(crt1.o):crt1.c:(.text+0xd6): undefined reference to `_environ'
/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(crt1.o):crt1.c:(.text+0x10b): undefined reference to `_environ'
/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(crt1.o):crt1.c:(.text+0x131): undefined reference to `_environ'
/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(crt1.o):crt1.c:(.text+0x141): undefined reference to `_environ'
/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(crt1.o):crt1.c:(.text+0x3d4): undefined reference to `_environ'
/home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/bin/ld: /home/teo.samarzija/djgpp-9.3.0/lib/gcc/djgpp/9.3.0/../../../../djgpp/lib/libc.a(getenv.o):getenv.c:(.text+0x4): more undefined references to `_environ' follow
collect2: error: ld returned 1 exit status

djgpp-gcc -v 输出:

Using built-in specs.
COLLECT_GCC=djgpp-gcc
COLLECT_LTO_WRAPPER=/home/teo.samarzija/djgpp-9.3.0/libexec/gcc/djgpp/9.3.0/lto-wrapper
Target: djgpp
Configured with: ../gcc-9.3.0/configure --target=djgpp --prefix=/home/teo.samarzija/djgpp-9.3.0 --enable-languages=c,c++,objc,ada,fortran,go
Thread model: single
gcc version 9.3.0 (GCC) 

我还编译了最新版本的 GNU 链接器和 GNU 汇编器,它们输出为其版本:

GNU ld (GNU Binutils) 2.34
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.

GNU assembler (GNU Binutils) 2.34
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `djgpp'.

知道我做错了什么吗? GCC、GAS 或 GLD 是否已经停止支持 DOS?我想不会,因为它们将 DOS 作为目标进行编译,而没有对此发出警告。

最佳答案

我偶然发现这个问题是因为最近的一个Stackoverflow question您询问了一些在 NTVDM 虚拟 DOS session 内的 32 位 Windows 10 中无法正常运行的代码。

问题是您没有正确构建 DJGPP 交叉编译器和所有需要的组件。您没有向我们展示您在构建过程中使用了哪些命令以及使用了哪些版本的依赖项以及它们来自何处。

您需要做的第一件事是构建 DJGPP 交叉编译器。有些人维护脚本来做到这一点。我特别成功使用的一个构建环境/脚本来自用户 Andrew Wu on Github 。使用起来非常简单。根据您向我们展示的输出,您似乎正在使用 Unix 类型环境。由于您成功构建了 DJGPP(尽管不起作用),我假设您已经安装了所有必要的构建工具。首先使用以下命令检索脚本:

git clone https://github.com/andrewwutw/build-djgpp

更改为项目目录:

cd build-djgpp

查看README.md文件!它告诉您脚本支持哪些版本、您所使用的操作系统类型的构建要求等。目前它们支持的版本一直到 10.1.0。如果您拥有所需的一切,请选择要构建的版本(我将使用 9.3.0,因为它是您正在使用的版本),然后开始构建。您必须以 root 身份构建或使用 sudo,因为它安装到目录 /usr/local/djgpp

./build-djgpp.sh 9.3.0

这需要一段时间,但完成后应该已安装并可以使用。命名约定与在命令前添加 djgpp- 略有不同。该脚本使用更完整的目标前缀i58​​6-pc-msdosdjgpp-

构建内容

要将其添加到您的路径并设置其他环境变量,请使用:

. /usr/local/djgpp/setenv

如果您希望每次登录时都执行此操作,请将该行添加到您的 shell 登录脚本中。对于文件 ~/.bashrc

中的 BASH

创建一个名为 hello.c 的文件,其中包含:

#include<stdio.h>

int main()
{
    printf("Hello, world!\n");
}

将其编译为名为 hello.exe 的文件:

i586-pc-msdosdjgpp-gcc -O3 -Wall -Wextra hello.c -o hello.exe 

假设您安装了 DPMI 主机(例如 CWSDPMI.EXE),hello.exe 应该在 MS-DOS、FreeDOS、DOSBox、Windows NTVDM session 等中运行.运行时应该显示:

Hello, world!


如果您不想从头开始构建,Andrew Wu 有一些 pre-built packages了解许多最新的 DJGPP 版本。它们适用的平台有 MacOS、Linux 32、Linux 64、MinGW 以及不需要 MinGW 环境即可运行的 MinGW 独立版本。

关于DOS 的 GCC 交叉编译器在 C 中产生简单的 "Hello world!"链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62500891/

相关文章:

assembly - 在内存位置调用 `add` 是否比在寄存器上调用它然后移动值更快?

c++ - 为什么 visual studio 2010 寻找 __thiscall 而不是 __cdecl 调用约定?

c - 链接器可复制的含义

c++ - gcc 可以编译可变参数模板而 clang 不能

c++ - 在 G++ 4.8 中,typeof 仍然不能与 "::"一起使用

c++ - decltype 和隐藏外部名称的类成员名称之间的交互

assembly - 进位标志何时设置?

c++ - 带有 std::function 的通用 lambda 不捕获变量

linux-kernel - 进程堆栈和 CPU 堆栈之间有什么区别?

opencv - 如何在 gcc 上编译 Opencv API