首页 > 解决方案 > 用于 DOS 的 GCC 交叉编译器会为简单的“Hello world!”生成链接器错误。在 C 中

问题描述

我尝试将 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 编译为目标。

标签: gccx86linkerdosdjgpp

解决方案


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

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

您需要做的第一件事是构建一个 DJGPP 交叉编译器。有些人维护脚本就是为了做到这一点。我成功使用的一个构建环境/脚本来自Github 上的用户 Andrew Wu。使用起来非常简单。根据您向我们展示的输出,您似乎正在使用 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-。该脚本使用更完整的目标前缀构建事物i586-pc-msdosdjgpp-

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

. /usr/local/djgpp/setenv

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

创建一个名为的文件,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 会话等中运行。运行时应显示:

你好世界!


如果您不想从头开始构建,Andrew Wu 为许多最新的 DJGPP 版本提供了许多预构建包。它们可用的平台是 MacOS、Linux 32、Linux 64、MinGW 和不需要 MinGW 环境运行的 MinGW 独立版本。


推荐阅读