Search code examples
gccx86linkerdosdjgpp

GCC cross compiler for DOS produces linker errors for simple "Hello world!" in C


I've tried to configure GCC 9.3.0 to produce executable files for DOS. However, for a simple "Hello world!" program in C, it outputs:

/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 outputs:

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) 

I've also compiled the newest version of the GNU linker and GNU Assembler, they output as their versions:

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.

and

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'.

Any idea what I am doing wrong? Have GCC or GAS or GLD stopped supporting DOS some time in the past? I suppose not, because they compile for DOS as a target without warning about that.


Solution

  • I only stumbled on this question because of a more recent Stackoverflow question you asked about some code that didn't run properly in 32-bit Windows 10 inside an NTVDM virtual DOS session.

    The problem is that you have not properly built a DJGPP cross compiler and all the needed components. You do not show us what commands you use for the build process and which versions of the dependencies were used and where they came from.

    1st thing you need to do is build a DJGPP cross compiler. There are some people who maintain scripts to do just that. One build environment/script in particular I have used successfully is from the user Andrew Wu on Github. It is very simple to use. It appears you are using a Unix type environment based on the output you have shown us. Since you managed to build DJGPP (albeit one that doesn't work) I will assume you have all the necessary build tools installed already. First retrieve the scripts with:

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

    Change into the project directory with:

    cd build-djgpp
    

    Review the README.md file! It tells you what versions are supported by the script, build requirements for the type of OS you are on etc. At present they support versions all the way to 10.1.0. If you have everything needed choose a version to build (I'll use 9.3.0 since it is the version you are using) and then start the build. You will have to build as root or use sudo as it installs to directory /usr/local/djgpp

    ./build-djgpp.sh 9.3.0
    

    It will take a while but when finished it should be installed and ready to use. The naming convention is a bit different than prefixing the commands with djgpp-. This script builds things with a more complete target prefix i586-pc-msdosdjgpp-

    To add it to your path and set up other environment variables use:

    . /usr/local/djgpp/setenv
    

    If you wish it to be done each time you are logged in add that line to your shell login script. For BASH that is in the file ~/.bashrc

    Create a file called hello.c containing:

    #include<stdio.h>
    
    int main()
    {
        printf("Hello, world!\n");
    }
    

    Compile it to a file called hello.exe:

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

    Assuming you have a DPMI host installed (like CWSDPMI.EXE), hello.exe should run in MS-DOS, FreeDOS, DOSBox, a Windows NTVDM session etc. When run it should display:

    Hello, world!


    If you don't wish to build from scratch, Andrew Wu has a number of pre-built packages for a number of the latest DJGPP releases. Platforms they are available for are MacOS, Linux 32, Linux 64, MinGW, and a MinGW standalone version that doesn't need the MinGW environment to run.