This is the DJGPP Frequently-Asked Questions List. Copyright (C) 1994, 1995, 1996, 1997, 1998 Eli Zaretskii.
This is the second edition of the FAQ list, and is consistent with version 2.01 of DJGPP.
This FAQ list may be freely distributed with the DJGPP package or any part thereof, provided that this copyright notice is left intact on all copies.
But because the DJGPP project is run by a group of volunteers on their free time, there isn't always enough time (or patience, or money ;-) to produce documentation which will describe all the subtle features and pitfalls a user should know about. The documentation of DJGPP-specific utilities and features is minimal at times, leaving wide space for confusion, in newcomers and veterans alike, and making the DJGPP learning curve steeper than it could be.
This FAQ list is an attempt to take the sting out of that learning curve, by supplying solutions for problems which are known to puzzle DJGPP users. (Another solution would be to pay to DJ Delorie and other people who develop DJGPP to produce more documentation ;-).
Some additional places to look for tutorials and other introductory material about DJGPP are listed below.
One good place to look for DJGPP features that are often overlooked is the DJGPP Knowledge Base. The Knowledge Base is also available in Info format; type info knowledge from the DOS prompt. A User's Guide is also being written by several contributors; it is currently available from the DJGPP server.
Brennan Underwood maintains a home page, which is another valuable source for information about DJGPP.
You can browse the HTML version of this FAQ list on line at DJ Delorie's Web server.
Also available from the DJ's server: FAQ in several additional formats.
A previous version of this FAQ was translated into French, also available through the WWW.
This is Edition 2.11 of the FAQ, last updated 13 September 1998, for DJGPP Version 2.01.
The following master menu lists the major topics in this FAQ list, including all the indices.
Q: I have this problem which I absolutely MUST solve NOW! What do I do?
Here's a brief description of the necessary steps:
set PATH=C:\DJGPP\BIN;%PATH% set DJGPP=C:\DJGPP\DJGPP.ENVIf your top DJGPP directory is other than C:\DJGPP, change these two lines accordingly!
Your installation is now complete.
Here are several simple commands:
gcc -o cprog.exe cprog.c
gxx -o cxxprog.exe cxxprog.cc
gcc -c cfile1.c cxxfile2.cc
gxx -o myprog.exe cfile1.o cxxfile2.o
To compile with optimizations, add the -O2 switch to the command line. In addition, use of the -Wall switch is highly recommended: it turns on many useful diagnostic messages.
Use the DJGPP News group or mailing list. For most questions, you will have your answer in a day or two. See the details on how to ask the gurus.
This depends on your hardware and software. Detailed instructions are in system configuration guidelines.
Check out list of required and optional packages.
See subscription instructions. However, it is better to read the comp.os.msdos.djgpp news group if you have access to Usenet News.
This FAQ includes description of DJGPP archive search server. That search facility is set up by DJ Delorie, and you should use it whenever you have any questions or look for an information on a DJGPP-related subject.
The originator and principal maintainer of DJGPP is DJ Delorie; that's where the "DJ" in "DJGPP" comes from. However, anybody is welcome and encouraged to contribute.
Programs compiled with DJGPP, and all development tools provided as part of DJGPP, look on the outside like normal DOS programs, and they rely on MS-DOS and BIOS for file I/O and other basic functions such as keyboard input, screen cursor position, etc. DJGPP programs use DPMI (the DOS Protected Mode Interface) to allow DOS/BIOS calls from protected mode. Therefore, any environment that can run DOS programs and provides DPMI services, will run DJGPP programs as well. Environments that are known to be compatible with DJGPP include MS-DOS, DR-DOS, NWDOS, FreeDOS, OpenDOS, Windows 3.X, 9X and NT, OS/2, and Linux DOSEmu. When DJGPP programs run on Windows 9X, they support long filenames.
It is important to understand that all these environments will treat DJGPP programs as DOS programs which call DPMI services. DJGPP cannot by itself create Win16 or Win32 applications; however, you can use the RSXNT package together with DJGPP to achieve this. See writing Windows applications with DJGPP.
Programs compiled with DJGPP can access all the physical memory on your machine and support virtual memory. All this memory presents a flat address space with no segmentation (you can say goodbye to far and huge pointers and to memory models), and is only limited by the amount of virtual memory supported by the DPMI server in use. A typical DPMI server can provide at least 64MB of virtual memory (if you have enough free disk space).
DJGPP is free: you don't have to pay anything to download and use it, even if you write commercial programs. DJGPP doesn't impose any restrictions on programs that you write and compile with it: you can make them commercial, shareware, freeware, or any other kind. (There are a few minor exceptions to that rule, see (un)restrictions on distribution of DJGPP apps.)
The core of DJGPP is the MS-DOS port of the GNU C/C++ compiler, GCC, and auxiliary utilities, such as assembler, linker, librarian, Make, and a hypertext docs browser. The DJGPP C library was written specifically for DJGPP, mainly by DJ Delorie himself, with help from a small group of volunteers.
DJGPP presents a set of tools which are remarkably ANSI- and Posix-compliant(Note: Posix is an international standard for a portable operating system. It specifies facilities of a
compiler, its libraries, and the basic set of development tools. Posix was originally modeled on Unix systems, but is currently supported by most modern operating systems.). GCC complies to
ANSI/ISO C Standard; the DJGPP C library is ANSI- and Posix-compliant (however, a small number of Posix features, like the fork
system call, are unimplemented); the C++
libraries also comply to the latest standards; and the GNU development tools used by DJGPP are all Posix-compliant. As a result, DJGPP tools provide a complete and coherent Posix layer on top of
Microsoft operating systems, to the degree that even the infamous limitations of DOS and incompatibilities between DOS/Windows and Unix are almost completely concealed from users and developers.
Here are some of the tasks that DJGPP is said to be good for:
Starting from v2.0, DJGPP programs do not need a separate extender program, only a DPMI server to run; DJGPP includes a free 32-bit DPMI server which allows for a 32-bit, 4 GByte flat address space and up to 512 MBytes of virtual memory.
| Previous | Next | Up | Top |
Q: Will DJGPP run on my brand-new Acme i986DX7/500 PC with a SCSI-III 10-Terabyte disk drive under MulticOS/42 v7.99 operating system?
DJGPP will run under native DOS; any other operating system is OK if it includes a DPMI server and supports some kind of "DOS box". Environments known to run DJGPP besides native DOS: Windows 3.1 & 3.11 DOS box, OS/2 (including Warp) DOS box, Windows 9X/DOS 7, Windows NT (on Intel CPUs), Novell NWDOS 7 and Caldera's OpenDOS (but several people have found the DPMI services of NWDOS and OpendDOS incompatible with DJGPP, so they should probably be turned off and CWSDPMI used instead), and Linux DOSEmu environment.
| Previous | Next | Up | Top |
Q: DJGPP Make crashes when I run it on OS/2!
One particular problem with OS/2 v3.0 is that RHIDE 1.4 and later exits after the compilation ends. This doesn't happen under OS/2 v4.0, so you should upgrade if you have such problems.
If the above doesn't help, please post the details of the crashes you see to the DJGPP mailing list (see how to post to the mailing list), or to the comp.os.msdos.djgpp news group, and somebody will help you.
| Previous | Next | Up | Top |
The DPMI server built into NT (and Windows 9X) loses selectors with each child program that is invoked by a DJGPP program, so after about two thousand calls to functions from the spawnXX
family you can see an error message like this:
Load error: no DPMI selectorsThis problem is likely to afflict only DJGPP ports of Unix shells (such as bash), since no other DJGPP program, not even Make, is likely to call so many child programs before it exits. The only known work-around is to exit the shell every now and then, because when all the available selectors are exhausted, the DOS box will crash. I'm told that Make sometimes fails on long Makefiles on Windows 9X, where the selectors are lost at even higher rate than on NT. If you ever run a very long Makefile and see Make crash, just run Make again, and it will pick up where the crashed session has left off.
Note that the long filename API (the special functions of Int 21h which support file names longer than the DOS 8+3 limitation) for DOS box is not supported by current versions of Windows/NT, so you cannot have long filenames there from DJGPP programs. An alpha version of an LFN driver for NT which enables long file name support for DJGPP programs, written by Andrew Crabtree, can be downloaded from Andrew's site.
The popular DJGPP IDE RHIDE needs a -M switch to work on NT (to disable the mouse support which will otherwise crash RHIDE).
You might have problems with using the SVGA modes of your video card under Windows/NT. That is because NT doesn't allow direct access to the SVGA registers, without which it is impossible to recognize the type of the SVGA and employ its capabilities. For example, a user reported that GRX functions and the MODETEST.EXE program thought that only a standard VGA was installed, whereas he had an S3 card. There is nothing you can do about this feature of Windows/NT; that is the price you pay for the stability and protection you get under this OS (a runaway program that accesses hardware registers can wipe out your disk or wedge the entire system cold). However, I'm told that Windows/NT 4.0 supports DirectX which is a method of accessing screen, audio and other peripherals directly, so it might be possible to use full GRX graphics capabilities there.
Programs that use the "nearptr" facility of DJGPP to access absolute memory addresses (e.g., for memory-mapped devices) won't work on NT, because its DPMI server silently ignores functions that set
huge limits on selectors. Since the default algorithm which allocates memory from the DPMI server needs to set such huge limit in some rare cases, there's a small probability that a program will
fail or crash even if it doesn't set selector limits in user code. It is best to use the Unix-style sbrk
algorithm in programs that run on Windows/NT. See the library docs for the
variable _crt0_startup_flags
where the _CRT0_FLAG_UNIX_SBRK
bit is explained, for more info on this issue. If you cannot switch to the Unixy sbrk
(e.g., if you
don't have access to the program's sources), I'm told that sometimes such problems can be worked around if you run DJGPP programs in a full-screen session; your mileage may vary.
Some people report that NT servers cause much more problems than NT workstations of the same version and build. It seems that these problems usually mean that NT installation was done incorrectly (maybe it is much harder to get it right with a server than with a workstation?). If you have such problems, try to install a workstation, or re-install the server, and see if that helps. And if you gain some insight as to why servers like DJGPP less than workstations, please tell what you've learned.
The Cygnus Win32 project is another (unrelated to DJGPP) port of GCC and development tools to Windows/NT and Windows 9X platforms, which specifically targets development of Windows programs. See , for more details about the Cygnus ports.
| Previous | Next | Up | Top |
Q: I can run DJGPP on Linux, but Make crashes with SIGFPE on even the simplest Makefiles!
Q: When I run bash on Linux/DOSEmu, echoing of what I type is very slow.
In general, upgrading to DOSEmu version 0.97.10 or later is recommended, at least with versions of Linux kernel earlier than 2.1; in particular, some users report that DJGPP programs sometimes crash on version 0.66.7 under Linux 2.0.35.
You might also need to edit the RAM section of the /etc/dosemu.conf file to make it comfortable for DJGPP. I suggest setting dpmi and xms to 16MB and ems to 4MB. For example, I'm told that building the Allegro library with the -O3 optimization switch fails in DOSEmu unless you allocate at least 16MB of DPMI memory to DOSEmu sessions.
If DJGPP programs crash with an error message like this(Note: The typo in the word Exception is in the actual message popped by Linux.):
DPMI: Unhandled Execption 0d - Terminating Client It is likely that dosemu is unstable now and should be rebootedthen you should add a line saying secure off to your /etc/dosemu.conf file. Some users reported that Make, and possibly other programs which use floating point computations, crash in DOSEmu environment on systems without an FPU, even if you set the 387 and EMU387 environment variables correctly (as explained in Setting up the FP emulator, below). The only known work-around is to not use floating point or to upgrade your machine hardware. It is possible that newer versions of Linux might solve this problem too, so try upgrading your Linux software.
If your only problem is to run GNU Make, get the latest DJGPP port of Make, since ports of Make 3.75 or later can be configured to not issue FP instructions at all.
If DJGPP programs respond too slow to keyboard input, you might need to tune the HogThreshold parameter in the dosemu.conf file. Set it to zero and see if this helps; if so, further tune it until you get reasonable response time, but still leave Linux with enough cycles for the other programs that run.
Several users reported that DJGPP programs cannot get input from the keyboard if Caldera's OpendDOS is booted under DOSEmu. I'm told that adding rawkeyboard to dosemu.conf might solve this.
Some people complain that RHIDE crashes on DOSEmu whenever the mouse is moved. I'm told that using the -M switch when invoking RHIDE solves this problem. Alternatively, you could try giving DOSEmu access to the serial port to which the mouse is connected, and then using your DOS mouse driver. To this end, add the following to your dosemu.conf(Note: This was reported for DOSEmu version 0.66.7; the format of dosemu.conf might be different in version 0.9x.):
serial { mouse com 2 device /dev/mouse } mouse {mousesystems device /dev/mouse emulate3buttons }and then load a DOS mouse driver in the DOSEmu AUTOEXEC.BAT.
If you have problems with mounting FAT32 partitions, upgrade the Linux kernel to version 2.0.34 or later.
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
RSXNTDJ is an add-on to DJGPP which allows to develop Win32 programs. This is targeted for Win32 (Windows 9X and NT) and Win32s (Windows 3.X + Win32s) platforms (but the development environment will only run on Windows 9X/NT); it supports DJGPP v2.x and includes debugging tools and an IDE, but it needs to be registered (for a small fee) if you want to develop commercial or shareware applications with it.
RSXNTDJ supports Win32 console, GUI, DLLs and bound programs (the latter can be run on DOS under the RSX extender, as well as on Windows). You can download RSXNTDJ from SimTel.
RSXNTDJ was produced with GCC v2.7.2.1 and DJGPP v2.01. If you use it with later versions of GCC and DJGPP, you might need to tweak the installation a bit. People who succeeded in this feat report that they needed to make the following changes:
PATH
environment variable. (Without this, the resource compiler won't work.)
LIBRARY_PATH
variable.
patch
utility fails.
extern
qualifier, which causes GCC to not compile them into the
object file, and triggers undefined references. The solution is to define the extern
symbol to an empty string in one of the source files which includes the stdio.h header.
pestack
utility, allegedly due to insufficient size of the default stack.
Note that the version of linker ld.exe which comes with RSXNTDJ doesn't print any message if you forget to link in libraries such as libcomct.a and libcomdl.a.
Instead, the produced executables will die with SIGSEGV when run. Sometimes, forgetting to #include
windows.h also produces a program that crashes at run time. You can use
the stock DJGPP version of ld.exe to see the list of the missing functions, and then find out which libraries to add to the link command line (use the nm utility to find out
which libraries contain the required external symbols).
If RSXNTDJ doesn't suit your needs, you can use a few other compilers which target Win32 platforms:
| Previous | Next | Up | Top |
TMPDIR
environment variable points to it (e.g., set TMPDIR=e:, if E: is the RAM drive letter);
| Previous | Next | Up | Top |
TMPDIR
to your hard disk and make the disk cache larger, if you can.
| Previous | Next | Up | Top |
TMPDIR
environment variable to a directory on your hard disk. Put a sufficiently large BUFFERS=
statement into your CONFIG.SYS (I recommend setting BUFFERS=40,8) to make DOS file operations faster.
TMPDIR
environment variable to a directory on your hard disk.
TMPDIR
environment variable to a directory on your hard disk.
TMPDIR
environment variable to it. If your RAM disk is less than 4
MBytes, GCC might run out of space there for very large source files (e.g., cccp.c file from the GCC source distribution), but this shouldn't happen unless the size of the source file you
are compiling approaches 1 MByte. Note that software is available that lets you install a RAM disk even on Windows 9X.
A tutorial is available from the Web on how to set up and get started with DJGPP. Using a memory manager, such as EMM386 or QEMM, is not required (DJGPP will run without it), but highly recommended, since it has several advantages:
Q: I have 128MB of memory installed, but go32-v2
only reports 32MB, how can I get more?
DEVICE=C:\WINDOWS\EMM386.EXE NOEMS L=131072I'm told that this line (here for 128MB of installed memory) together with an "Auto" setting of the DPMI memory for the DOS box allows DJGPP programs to use up to 117MB of memory when running from the DOS box under Windows 9X.
If you need to use more than 256MB of physical memory, try to convince Charles Sandmann to upgrade CWSDPMI. However, note that breaking the current limit of 256MB will make CWSDPMI considerably slower (it requires to abandon 16-bit arithmetics and move to 32-bit longs, which causes Turbo C, the compiler used to build CWSDPMI, to generate much slower code). Charles says that people who got such customized versions of CWSDPMI were never really happy with its performance, so he advises to consider the 256MB limit a serious reason to switch to another operating system. For example, a dual-boot DOS/Linux system will probably do. Another possibility is to run under OS/2 which features a built-in DPMI 1.0 support which can be configured to support as much as 512MB of DPMI memory (the user who reported this didn't know how much of this can be physical RAM).
| Previous | Next | Up | Top |
This section lists the SimTel.NET mirrors; see below, for the list of CCT sites.
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
Gopher users can get CCT files with a Gopher client.
For those of you who only have an e-mail connection to the Internet, CCT files may be also obtained by e-mail from various ftp-mail servers or through the BITNET/EARN file servers. For details send a message to the CCT list server with this command in the message body:
get simtel-mailserver.infoAnother ftp-mail server is ftpmail@pub1.bryant.vix.com. Send a message with a single word "help" in the body to the above address, to get instructions. Walnut Creek, the company which maintains the SimTel.NET collection where the DJGPP archives are held, also sells a DJGPP Development System CDROM. It includes everything from the DJGPP sites on SimTel.NET (even the old version 1.12 of DJGPP), some example source code packages to get you started, and a ready-to-run feature, which allows you to use DJGPP directly from the CDROM; you can also use a provided install program to copy some or all of the packages to your hard disk. To order the CDROM, go to the Walnut Creek Web site.
Salvador Eduardo Tropea (SET), himself a veteran DJGPP user and developer, sells a low-cost CDROM with all the DJGPP v2 files, plus a lot of related stuff downloaded from the net. For information, send email to set-soft@usa.net.
| Previous | Next | Up | Top |
as
, the GNU assembler; ld
, the GNU linker; and their docs. GCC calls these utilities during compilation.
djdev
distribution includes two simpler, assembly-level debuggers, edebug
and fsdb.
The latter
presents a user interface similar to that of Turbo Debugger.)
PATH
, or to rename the DOS
find program to some other name.
texi2html
(Note: Like its name suggests,
texi2html
converts a Texinfo source to HTML.), use Perl.
For description of additional files not mentioned here, get the file 00_index.txt; it contains a full list of the distribution files and a short description of every file.
| Previous | Next | Up | Top |
Execution-only environment..................300 KBytes Developing C programs.......................15 MBytes Developing C++ programs.....................20 MBytes Developing Objective-C programs.............16 MBytes Additional storage for RHIDE................4 MBytes Additional storage for DJGPP sources........6 MBytes Additional storage for GDB..................1.1 MBytes Additional storage for Emacs................30 MBytes Additional storage for Flex.................280 KBytes Additional storage for Bison................310 KBytes Additional storage for Diffutils............560 KBytes Additional storage for Make.................650 KBytes Additional storage for Patch................180 KBytes Additional storage for Sed..................200 KBytes Additional storage for Graphics libraries...4 MBytesNote that the above lists only approximate numbers. In particular, the disk cluster size can significantly change the actual disk space required by some of the distributions (those with a large number of files). The numbers above are for disks which have 8KB or smaller clusters.
In addition to the space for installing the software, you will need some free disk space for the swap file. You should leave enough free disk space to make the total virtual memory at least 20 MBytes; that will be enough for most applications. Invoke the go32-v2.exe program without arguments to see how much DPMI memory and swap space DJGPP applications can use. Depending on your DPMI host, you might need to review its virtual memory settings in addition to leaving free disk space; CWSDPMI only requires that enough free disk space be available, but other DPMI hosts have special settings to specify how much virtual memory they let their clients use, as explained in how to set up memory, below.
| Previous | Next | Up | Top |
Q: Pulling that many megabytes through the net from my overloaded SimTel.NET mirror is almost impossible. Can't you prepare a ZIP archive which only includes stuff I can't do without?
To make downloading DJGPP easier, download and compile the BatchFTP program. It allows you to submit a script of FTP commands and will repeatedly try to login into the FTP site you specify until the script is successfully completed. It is smart enough to understand the messages which the FTP server sends to you (like login refused etc.) and also is nice to the remote server by sleeping for some time between login attempts. BatchFTP is free software and can be found on many FTP sites.
BatchFTP is a Unix program; those who access the net from their PC (not by dialing into some Unix host with a shell account), can use one of the available programs for automated FTP access.
As for the minimal DJGPP installation, volunteers are welcome to prepare such an archive and make it publicly available, in the same spirit as EZ-GCC did for DJGPP v1.x.
Q: How can I install a newer version of some package without leaving traces of the older installation?
rm -f @manifest/gcc281b.mftThe
rm
program is part of the GNU Fileutils package, available as v2gnu/fil316b.zip from the usual DJGPP FTP sites.
When you install a new version of a package, it is best to uninstall the previous version first, like in the above example, and then install the new one.
| Previous | Next | Up | Top |
Texinfo includes INFO.EXE and its docs. Unzip it and type info <Enter>. It will bring up a (hopefully) self-explanatory online help system. Confused? Press ? to see the list of all Info commands. Still confused? Press h to have Info take you on a guided tour through its commands and features.
If you use Emacs, you already know about Info. (What's that? You don't? Type C-h <i> and you will get the top-level menu of all the Info topics.) RHIDE also has an integrated Info reader, which is the core of its help system.
| Previous | Next | Up | Top |
You can also produce pure ASCII files yourself, if you have their Texinfo sources. These are usually called *.txi or *.texi and should be included with the source distribution of every package. (You can use the DJGPP server's downloading services, to download individual files.) To produce an ASCII file foo.txt from the Texinfo file foo.txi, invoke the Makeinfo program like this:
makeinfo --no-split --no-headers --output=foo.txt foo.txiMakeinfo is one of the programs which come with the GNU Texinfo distribution.
If you prefer reading the docs through the Web, point your Web browser to the docs page of the DJGPP Web site.
| Previous | Next | Up | Top |
If some package doesn't have a ready *d.zip archive, you will need to get and install a program called TeX or its work-alike, like emTeX. A DJGPP port of
TeX is available on SimTel.NET. Install TeX, then run the texi2dvi
shell
script(Note: You will need to install the port of Bash and some auxiliary utilities to be able to run shell scripts; texi2dvi
itself is part of the GNU Texinfo distribution and
comes with the v2gnu/txiNNNb.zip archive.) on the docs' source files (called *.txi or *.texi) which you get with the source distribution of every
package you download. TeX produces a .dvi file which you can then print using one of the available DVI drivers, as explained above. To convert a .dvi file
into PostScript, use the DVIPS program; you can find it as dvps566.zip on the above-mentioned site, together with the TeX port.
If TeX won't run, check that you have the file texinfo.tex which defines the TeX macros specific to Texinfo files. If you don't, get the latest GNU or DJGPP Texinfo distribution which includes that file.
If you'd like to produce printed docs of the library reference, TeX might complain that it cannot find a file named libc2.tex. This file is generated from all the *.txh files in the DJGPP source distribution (djlsr201.zip). In order to build this file, you need to install djlsr201.zip and the C++ compiler, then go to the src/libc directory and type this from the DOS command prompt:
make -C ../mkdoc make docIf the above command fails due to unresolved externals, you will need to edit the file makefile in the mkdoc directory. It has a line which calls ld (the linker), where you should change -lgcc -lc into -lgcc -lc -lgcc. Save makefile and try the above commands again.
Note that some documentation files (notably, the one for GCC and Emacs) will produce voluminous print-outs. You have been warned!
DJGPP comes with a program called TEXI2PS which can convert *.txi files to a crude PostScript; try it if you don't care much about the appearance of the printed docs. Its advantage is that you don't need to install any additional packages, just to fetch the Texinfo sources of the docs.
Finally, if you don't mind paying for the printed documentation, the Free Software Foundation sells printed copies of manuals for GNU packages. You can contact the FSF for details.
For those who prefer reading docs with a Web browser, many GNU manuals in HTML (hypertext) format, suitable for reading with your Web browser, can be viewed at the DJGPP Web site. The *d.zip archives also include the docs converted to HTML, which you can browse locally on your machine.
| Previous | Next | Up | Top |
Q: STL, the C++ Standard Template Library, seems to be undocumented...
| Previous | Next | Up | Top |
DJGPP binary *b.zip distributions include such man pages already formatted and ready to be browsed. To browse formatted man pages, you will need to install a clone for the Unix man command. One such clone is available from the DJGPP sites.
man knows how to find a manual page file, and will format it if it isn't formatted already, but to browse these files you will need a program that can page through a text file and which understands how to show bold and underlined letters instead of backspace-over-typed characters. I suggest to download the DJGPP port of GNU Less, which uses colors to show bold and underlined letters.
Having installed man and Less, you should be able to view *.1 files like e.g. patch.1 with several alternative tools:
Using Info to display man pages has an advantage of displaying the Info version of documentation if it is available, and the man page version if it's not. So, by using Info, you don't need to bother to remember which version of the docs is available for every topic. Info also knows about special sections in man pages, such as "SEE ALSO", which refer to other man pages, and treats them as hypertext links (i.e., you can press <TAB> to move between the references and press <Enter> to display the man page under cursor).
The binary distribution of the DJGPP port of bash includes a simple SED script called man2txt.sh which will convert formatted man pages into plain text; you can then read them with any text browser or editor. To convert, invoke Sed like so:
sed -f man2txt.sh < file.1 > file.txtIf you want to be able to browse unformatted man pages, get and install the DJGPP port of Groff. man will automatically call Groff if it finds an unformatted page, so all the ways mentioned above to browse man pages will work with unformatted pages as well, once you install Groff.
Note that, for GNU packages, the man pages aren't always updated on a regular basis. If you need more up-to-date information, see the Info files.
| Previous | Next | Up | Top |
Q: Some programs, like Info and Less, hang on my Windows 9X machine after some time, requiring to close the DOS box. Help!!
Q: Bash hangs on Windows 9X after the first DJGPP program I run from it!
DJGPP
environment variable incorrectly, or didn't set it at all, or
messed up your DJGPP.ENV file by editing it. Refer to what to do if GCC hangs, later in this FAQ, for details about possible problems with
setting DJGPP
. When DJGPP
is not set, or points to a non-existent directory, the first release of GCC 2.8.1 would enter an endless loop (the NTDVM process on
Windows/NT will go nuts allocating memory, as a result of this).
The latest uploads of the GCC 2.8.1 binary (v2gnu/gcc281b.zip) were modified to prevent them from hanging. This version aborts with an error message instead of hanging. You should
upgrade to the latest binaries of GCC, and also set your DJGPP
variable correctly.
Some people fail to read the release notes which come with GCC 2.8.1, and install it incorrectly. If you installed GCC 2.8.1 recently and it began to hang, now is the time to read those instructions again (they are installed as gnu/gcc-2.81/problems.txt). In particular, GCC 2.8.1 comes with a modified version of DJGPP.ENV which you should install over the stock version.
If interactive programs like Bash, Less, Info, Emacs, and RHIDE are those which hang, and if it only happens after running another DJGPP program from within those programs, then your
Windows 9X installation is afflicted by a subtle bug whereby programs which call function 1680h of the Interrupt 2Fh (to release the rest of their time slice when they are idle) hang after they spawn
another DJGPP program. A modified version of the library function __dpmi_yield
, which works around that bug in Windows, is available (it will be part of DJGPP v2.02 release), and latest
uploads of the binaries for the affected programs should be free from this problem. If you cannot find a pre-compiled binary that works, get the sources and rebuild the program with a fixed version
of __dpmi_yield
.
| Previous | Next | Up | Top |
If you already have CWSDPMI installed, and these messages still appear, it might be because of a messed up PATH
setting. The DJGPP startup code looks for cwsdpmi.exe along
the PATH
, and, being optimized for size, it might not be robust enough to cope with all possible cases of weirdness in the value of PATH
. Try to copy
cwsdpmi.exe into the same directory as the program you are invoking, and if that helps, change your PATH
as appropriate.
If you see the message "Load error: no DPMI - Get csdpmi*.zip" on Windows/NT, it most probably means that you have disabled the DPMI services built into NT. One way this might happen is if you edit the autoexec.nt file and remove the line which loads dosx.exe, or change some of the parameters on that line. You cannot use CWSDPMI on NT, so your only bet is to restore NT's built-in DPMI services.
| Previous | Next | Up | Top |
Another DPMI host which is known to cause problems in DJGPP is Quarterdeck's QDPMI which comes with QEMM 7.5. It was reported to cause Info and all DJGPP debuggers to crash. If you use QDPMI, upgrade to the version 7.53 or later (patches for that version are available from the Quarterdeck's ftp site), or disable QDPMI and use CWSDPMI.
| Previous | Next | Up | Top |
Q: The compiler prints "Virtual memory exhausted" and dies while compiling some long functions with some optimization options, such as -funroll-loops or -fforce-addr.
If GCC reports that it has exhausted virtual memory, you should first see if your DPMI memory plus the swap space is large enough (run go32-v2 with no arguments to display the available memory) and make more memory available. Some programs really need large amounts of memory to compile and/or link. For example, linking cc1.exe is known to consume more than 12MB of memory. On Windows 9X, be sure to set the amount of DPMI memory available to the DOS box to the maximum value of 65535K (64MB) in the DOS box property sheets, under Memory, as explained in how to enlarge memory in the DOS box.
Some users have reported that GCC seems to run out of virtual memory if TMPDIR environment variable points to a RAM disk which doesn't have enough free space. Changing TMPDIR to point to a hard disk would reportedly save the day in those cases.
Compiling with PGCC or EGCS variants of the GNU compiler can also sometimes run out of virtual memory. These two compilers are memory hogs, especially when compiling C++ programs, and at high optimization levels. One particular case is when your program makes use of many STL classes. Try compiling without optimizations. I'm told that sometimes omitting the -Wall switch prevents the compiler from using up too much memory (that sounds awfully like a bug to me), so try that as well.
One user reported that optimization switches force GCC to use a math co-processor, which can cause it to crash on a machine that lacks a numeric processor. Be sure you didn't delete the emu387.dxe file from your bin subdirectory, when you compile on such machines, and that your emulation-related setup is right. See how to set up FP emulation, for details.
GCC can sometimes crash when optimizing, especially when compiling C++ programs, in particular if your code has some syntactic or semantic bug. (This is usually a genuine GCC bug, not
something special to DJGPP.) Upgrade to the latest version of GCC. If that doesn't help, then narrow the offending code fragment using the #if 0 ... #endif
paradigm. If this fragment
includes an error, correct it and try again; if it is syntactically and semantically correct, then rewrite it as equivalent, but syntactically different one.
A GCC switch can sometimes help you zero in on the code fragment that causes GCC to crash. If you add -Q to the GCC command line, it will print the name of every function it compiles. The function that makes it crash is probably the one whose name is the last one printed, or the one after that.
As an extreme measure, don't optimize at all, if that's the only way to make your program compile.
Another reason for crashes could be some problem with your system hardware or the BIOS (like if you set an incorrect number of wait states when accessing memory). To check, try running the same compilation on another machine, or review your BIOS settings.
Yet another cause for such crashes can be connected with excess memory usage that GCC needs when compiling certain programs, which makes some DPMI hosts fail. For details about this, see CWSDPMI allocation problems, below.
| Previous | Next | Up | Top |
as
"?
Q: When I try compiling a program, GCC aborts saying "Installation problem, cannot exec `cpp': No such file". Huh?
COMPILER_PATH
environment variable or what the
COMPILER_PATH
line in the DJGPP.ENV file says, and make sure they point to the directory where DJGPP programs reside. Also check that the named directory has all the
required programs: cpp.exe, cc1.exe, cc1plus.exe, cxxfilt.exe, gasp.exe, as.exe, ld.exe, and (for
Objective-C) cc1obj.exe. A typical case is when people fail to install the Binutils package and GCC cannot
find as.exe (the assembler) and ld.exe (the linker). You can use the -v switch to GCC to see what programs it invokes and which one of them causes the fatal
error. Beginning with version 2.8.0 of GCC, the place where the pre-processor, cpp.exe, and the C and C++ compilers, cc1.exe and cc1plus.exe, are installed, has changed: they are no more in the same directory as gcc.exe itself. If you are using GCC version 2.8.0 or later, and the compiler cannot find cpp.exe, read the installation instructions carefully: the file problems.txt explains how to change the settings on DJGPP.ENV so that GCC will find the pre-processor.
| Previous | Next | Up | Top |
Q: GCC aborts with "Internal compiler error" when compiling a large C++ program.
Q: GCC behaves erratically when compiling programs, sometimes crashes with register dump, sometimes compiles okay, sometimes reports "Internal compiler error". Why is this happening?
Q: When I try to compile any program, GCC prints "Abort!" and doesn't compile anything...
Q: The compiler crashes or dies with "Virtual memory exhausted" when I compile my simple program!
DJGPP
not being defined means just that--that your DJGPP
environment variable is not defined. The other two messages
you could see are:
Environment variable DJGPP point to file `XXYYZZ' which doesn't existor
Environment variable DJGPP points to wrong or corrupt file `ABCDEFG'(In both cases, you will see an actual file name instead of
XXYYZZ
and ABCDEFG
.) These messages mean that DJGPP
points to a non-existing directory, or to a
file whose contents are too messed up. Beginning with version 2.8.1, GCC refuses to work when the DJGPP
variable doesn't point to the actual path name of a valid DJGPP.ENV
file, because GCC uses the value of the DJGPP
variable to find out where to look for its subprograms like cpp.exe, cc1.exe, etc. To solve this, set the
DJGPP
variable as the installation instructions (in the file readme.1st) describe. Also, make sure you didn't mess up the beginning of the DJGPP.ENV file,
where the value of the DJDIR
variable is computed (when in doubt, compare it with the stock DJGPP.ENV from the djdevNNN.zip distribution).
A possible cause for the "Abort!" message is that the TMPDIR
environment variable points to a non-writable directory. If you don't set TMPDIR
from your
AUTOEXEC.BAT or from the DOS prompt, the DJGPP startup code sets it to the tmp subdirectory of the main DJGPP installation directory. If DJGPP is installed on a read-only
drive, like CD-ROM or an unwritable networked drive, this default will not work. To solve this, set TMPDIR
to point to a writable temporary directory. If TMPDIR
is not set
at all, GCC tries to use TEMP
and TMP
, in that order, so make sure these also point to a valid directory.
Internal compiler errors (a.k.a. bugs) can also cause GCC to print "Abort!". This FAQ describes a procedure that allows you to find the spot in the sources where the compiler aborts, see use of the -Q switch, above. Once you find the offending code, you could rewrite it and/or submit a bug report to the GCC maintainers.
When GCC aborts with a message such as "Internal compiler error" or "Exiting due to signal SIGSEGV", it might mean a genuine bug in GCC (which should be reported to FSF), but it can also happen when GCC requests additional chunk of memory, and the DPMI server fails to allocate it because it exhausts available memory for its internal tables. Old releases of CWSDPMI could fail like this if an application asks for a large number of small memory chunks. Beginning with release 2, CWSDPMI defines a larger (6KB) default heap that is configurable by CWSPARAM program to be anywhere between 3K and 40K bytes, without recompiling CWSDPMI. You should upgrade to the latest CWSDPMI if you experience such problems, and if that doesn't help, bump up the size of CWSDPMI heap using CWSPARAM.
Some innocent-looking programs are known to cause GCC to gobble preposterous amounts of memory, which could cause it to crash or abort after printing "Virtual memory exhausted". One particular case of such programs is when you initialize very large arrays. For example, to compile a source which initializes a char array of 300,000 elements requires more than 60MB(!) of memory. You should avoid such constructs in your programs.
Some programs require very large amounts of stack to compile. DJGPP programs have a fixed-size stack that is by default 256KB. If the compiler, cc1.exe or cc1plus.exe, doesn't have enough stack to compile a program, it will overflow its stack and crash, or hang, or die with "Internal compiler error". You can enlarge the stack size of any DJGPP program by running the stubedit program, like this:
stubedit cc1.exe minstack=512kI recommend to enlarge the maximum stack size of cc1.exe to at least 512K bytes and that of cc1plus.exe to at least 1MB. Some people report that they needed to enlarge both the heap of CWSDPMI and the stack of the C++ compiler to make such problems go away.
Note that the problems with insufficient stack size have nothing to do with the total available memory as reported by go32-v2
. A compiler can crash because of insufficient stack size
even though it has gobs of memory available to it. When in doubt, always enlarge the compiler stack size.
Sometimes, GCC can crash due to problems with your system hardware. In particular, bad memory chips can cause GCC to behave erratically, since the compiler is a memory-intensive program. One cause of problems with accessing memory is incorrect setting of the wait states in your BIOS setup, or too aggressive CPU cache mode that your motherboard cannot support reliably. Try to play with your BIOS setup and see if that helps.
For a program that you wrote, another work-around for the cases where a program crashes due to failure of CWSDPMI to allocate more RAM is to use an alternative algorithm for sbrk
, by
putting the following somewhere in your program:
#include <crt0.h> int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;Note that the Unix algorithm for
sbrk
might cause trouble in programs that install hardware interrupts handlers.
| Previous | Next | Up | Top |
Q: Since a few days ago, whenever I try to run most of the DJGPP programs, they print a message "C:\DJGPP\BIN\prog.exe: not COFF" and just terminate. Help!!!
Another possible cause of the "Unknown filetype" message is that you mix a v2.0 gcc.exe driver with cc1plus.exe, cc1.exe or other programs from an old v1.x distribution.
| Previous | Next | Up | Top |
Q: When I try to compile something, I get a message "16-bit DPMI not supported".
PATH
than the Make and the preprocessor which came with DJGPP. Moving DJGPP's bin directory to
the beginning of your PATH
will usually solve these problems. Note that if you try to mix 16-bit and 32-bit DPMI clients in Windows DOS box (like use Borland's Make to run GCC, or invoking Borland's cpp.exe under GCC), the DOS box will usually crash. So this problem is not specific to CWSDPMI.
If you must use a non-DJGPP compiler or another utility together with DJGPP programs, one solution would be to find a version of that utility that doesn't use the 16-bit DPMI services. For example, many DOS compilers have a real-mode version that won't conflict with DJGPP.
If you use Make compiled under DJGPP v1.x, you will also experience all kinds of trouble when invoking programs compiled under DJGPP v2. That's because v1.x programs cannot spawn v2 programs directly (the v1.x program sees that the child is a DJGPP program and tries to call go32 to run it, but v1's go32 cannot run v2 programs). The result usually will be that the child either crashes or silently exits. If that's your problem, be sure to upgrade your Make to the port distributed with v2. (Note that v2.x programs generally know how to spawn both v1.x and v2.x programs.) You can use go32-v2 to work around this limitation (see description of go32-v2, below), but I suggest doing that only if you absolutely cannot upgrade to v2's Make.
Some users report that v1.x programs might sometimes hang or reboot the machine when invoked from v2.x Make. The reason for this is a known bug in the versions of go32-v2.exe program distributed with DJGPP v2.0 and 2.01: it would not restore the keyboard handler after the COFF image it runs exits. To work around that bug, don't touch the keyboard throughout the entire run of Make.
| Previous | Next | Up | Top |
Q: Sometimes, when I mistype the name of the Info topic, info.exe seems to hang...
INFOPATH
which should point
to the directory where Info looks for its files. It must find there a file named DIR, the file you are trying to read, and other files with .iNN or .NN
extension, where NN is a number. Also, make sure you didn't edit the beginning of DJGPP.ENV, where the value of %DJDIR%
is computed; if you did, try the
original DJGPP.ENV.
Also, the DJGPP
environment variable should be set to point to the full pathname of the file DJGPP.ENV. See problems with DJGPP
variable setting, for a description of some frequent problems with setting the DJGPP
variable.
Assuming the above checks OK, and all the necessary info files are indeed installed in those directories (did you remember to give that -d switch to PKUNZIP when unzipping all DJGPP packages?), it might be that you have an old version of info.exe. Upgrading to version 3.12 or later should solve several problems which cause Info to complain about the "Top" node, or at least make its error messages more self-explaining.
Another possibility is that the file DIR or the Info file that you want to browse is corrupted. For example, it might be a compressed file, but without the telltale .gz or similar extension that tells info.exe to decompress it. You could examine the offending file(s) with a text editor, and re-install them as needed.
If you invoke Info with a name of a topic that is non-existent or not installed on your system, and you don't have a man
command or its clone installed, versions of Info before 3.12
would wait for 15 seconds before they print an error message and exit. If you think Info is wedged, wait for 15 seconds and see what happens then. The DJGPP port of Texinfo 3.12 removes this
misfeature, so upgrade if you can.
| Previous | Next | Up | Top |
EMM386
shipped with some versions of DOS 6.x. This bug is only triggered if your system loads the
DISPLAY.SYS
driver, usually to display non-US characters supported by national code pages. In addition, this bug causes Info to crash only if it is run in 35- or 40-line display mode;
any other display size avoids the problem. (The default display mode is 40 lines, as set in the [info] section of DJGPP.ENV.) So either switching to another display size,
or removing either EMM386
or DISPLAY.SYS
from CONFIG.SYS, should prevent Info from crashing. If you use DJGPP v2.0, yet another cause of crashes in Info might be trailing whitespace in the DJGPP.ENV file. The telltale signs of this failure are a stack dump that is bogus or doesn't start with your `main' function, or a series of SIGSEGV that won't stop. Actually, this is a bug in the DJGPP v2.0 startup code, so any v2.0 program could crash in this way, but since the last section of stock v2.0 DJGPP.ENV belongs to Info, it is the one which suffers most from this bug. Make sure your DJGPP.ENV doesn't have a ^Z character at the end (some DOS editors put it if you edit the file), and doesn't end with a blank line. Alternatively, upgrade to DJGPP v2.01 or later, where that bug is fixed.
| Previous | Next | Up | Top |
Q: Why does Bash say "pipe error: Access denied" when I try to run two programs via a pipe?
Q: When I run certain complex shell scripts, Bash sometimes prints a message saying "Cannot make a child for command substitution: (null)". What gives??
PATH
(it does not have to be in /bin!). Either copy bash.exe into
sh.exe, or create a "symlink" to bash.exe, like this:
ln -s c:/djgpp/bin/bash.exe c:/djgpp/bin/sh.exe(replace c:/djgpp with the actual pathname of your DJGPP installation).
Error messages about pipes and command substitution usually mean that your TMPDIR
environment variable points to an invalid drive. Old ports of Bash had problems with
`command`
substitution, so make sure you have the latest binaries.
| Previous | Next | Up | Top |
You can see which directories on what drives does the linker try to access by passing the -verbose option to the linker. Here's an example:
gcc -o hello.exe hello.o -Xlinker --verbose > linker.logThis redirects the linker log to a file which you can then examine. Since the list of directories accessed by the linker doesn't depend on the program being linked, you can try this with any trivial program.
| Previous | Next | Up | Top |
Q: I get errors I can't figure out when I try to compile something.
One cause of such problems might be that your system is set up inefficiently. If GCC doesn't get enough free RAM, it will run very slowly, and you might think it crashed when in fact it didn't.
(This kind of problem usually happens on memory-starved machines.) Invoking go32-v2
with no arguments will report the amount of memory available to DJGPP programs; large programs might
require up to 20MBytes to compile, sometimes more. If you run from the DOS box on Windows 9X, set its DPMI memory property to 65535KB (64MB) and try again. Check out the system
configuration advice, earlier in this FAQ list, for other suggestions about your system configuration.
Sometimes, if the TMPDIR
environment variable points to a full disk, GCC may hang or crash as well. Make sure you have enough free disk space where TMPDIR
points.
| Previous | Next | Up | Top |
Q: When I add -v to the GCC command line, how can I put all the voluminous output into a file, so I don't miss anything when reporting a problem?
Q: I have this nifty graphics program which bombs from time to time, but the registers and traceback info are hidden by the graphics display. How can I see it?
stderr
, and stock COMMAND.COM cannot redirect it. There are several alternatives to do that:
redir -o gcc.log -eo gcc -v ...(put the rest of the GCC command line instead of the dots). The messages printed by GCC will be written to the file gcc.log.
| Previous | Next | Up | Top |
Q: I don't have time to download all these messages, not to mention looking through them. Can't you DJGPP gurus help me? Please??
symify
on the stack dump, and post the output of symify
:
symify -o dumpfile yourprog(See detailed description of symify, for more details.
| Previous | Next | Up | Top |
| Without optimization | With -O2 -----------+------------------------+------------ C++ source | 800 | 400 -----------+------------------------+------------ C source | 1800 | 1000
On machines faster or slower than P166, scale these numbers accordingly. For example, i486/DX2-66 is about 4 times slower than P166. When comparing to this table, don't forget to count header files
your program #include's
in the total line count. And don't check compilation speed on very short programs (like the classic "Hello, world!"), because the
overhead of loading the multiple passes of the compiler will completely hide the compiler performance. It is also useful to run the compilation twice in succession, especially if you have a disk
cache installed, to prevent the overhead of the first load from skewing the results.
If your results are close to these (deviations of a few percent are considered "close" here), then that's as fast as you can get with GCC. If they are significantly lower, you may indeed have a problem; read on.
First, check to see if GCC pages to disk when it compiles. This is manifested by a heavy disk traffic which won't go away even if you have a large write-back disk cache installed. To be sure, disable the virtual memory services for your DPMI host (for CWSDPMI, load it before your program with the -s- switch, or use the CWSPARAM program to point the swap file to a non-existent drive), or use or CWSDPR0 or PMODE/DJ as the DPMI host, and then run the compilation again; if the compiler aborts with an error message saying there isn't enough memory, then it was paging in your original environment.
If paging does happen, you need to free more extended memory. If you have a RAM disk, make it smaller, or don't use it at all (it only makes compiles run about 10% faster), or make your disk cache smaller (but don't discard the disk cache altogether); if you have other programs which use extended RAM, make them use less of it. Failing all of the above, buy more RAM (see the description of reasonable configuration). Also see recommendations for optimal software configuration.
If GCC doesn't page, check the settings of your disk cache. If you don't use a cache, install one--this can slash your compilation times by as much as 30%, more so when compiling a large number of small files. If you already have a cache, enable its delayed-write (a.k.a. write-back, a.k.a. staggered-write) operation. Some people disable the delayed-write feature for safety reasons, to avoid losing files due to system crashes. If you are worried about this, you can usually gain performance without sacrificing safety by enabling delayed-write together with an option that causes the cache to flush the write-behind data before the system returns to the DOS prompt. (For SmartDrv disk cache, this is achieved by specifying /N/F switches instead of /X.) GCC usually gains a lot when you set up your cache in such a way, because each compiler pass (pre-processor, compiler, assembler) must write temporary files that are used by the following passes.
It is also worthwhile to check the settings of your system BIOS. In particular, the following items should be checked against your motherboard vendor recommendations:
Internal and external CPU cache....set to Enable CPU cache scheme...................set to Write-back, if possible DRAM and SRAM wait states..........vendor-recommended optimal valuesIncorrect or suboptimal settings of the above items can explain as much as 30% performance degradation on 486 machines, and as much as 500% (!) if you have a Pentium CPU.
A few users have reported that they got much faster linking after they've stub-edited ld.exe to decrease the transfer buffer size to 4KB or even 2KB. This speedup effect is usually seen
when DJGPP is installed on a networked drive or on a compressed disk, and sometimes when you run DJGPP from a DOS emulator (such as OS/2 DOS box); when DJGPP is installed on a local disk drive on
plain DOS or Windows, linking speed is not affected by the size of transfer buffer. The reason for this seems to be the large number of calls to fseek
function issued by the linker,
which defeats the benefits of aggressive buffering imposed by the default 16KB size of the transfer buffer. (DJGPP v2.02 will introduce a heuristic into the buffering of stdio
functions, whereby the size of the buffer for each FILE *
stream adapts itself to the behavior of that stream--grows when the stream is read sequentially, and shrinks when it is seeked.
This should eliminate the need for stubediting ld.exe and other similar programs.)
If you use a disk cache, make sure you enable its write-back (a.k.a. delayed-write) operation. Some people disable the delayed-write feature for safety reasons, to avoid losing files due to system crashes. If you are worried about this, you can usually gain performance without sacrificing safety by enabling delayed-write together with an option that causes the cache to flush the write-behind data before the system returns to the DOS prompt. For SmartDrv disk cache, this is achieved by specifying /N/F switches instead of /X.
For very large (several MBytes) executables which are built from a large number of small source files, the link (as opposed to the compilation) stage might be the one which needs more RAM than you have free, and thus be the bottleneck of the time it takes to build your program. Check that the size of the executable isn't larger than the amount of your free RAM. If it is, then it might make sense to use a smaller (or even no) disk cache, and allow the linker as much physical RAM as it needs. Make sure that the linker wasn't stub-edited to make its transfer buffer too small.
Another reason for slow linking might be that the DJGPP.ENV file by default sets TMPDIR
to a tmp/ subdirectory of the main DJGPP installation directory; if
DJGPP is installed on a networked drive, this means all your temporary files go back and forth through the network (and networked disks are usually not cached on your PC). In such cases, setting
TMPDIR
to a directory on your local drive, or to a RAM disk, would probably make linking faster.
Generally, it is not recommended to install DJGPP on a networked drive. If you have to, you should configure your network interface for best performance. Consult your network administrator.
This chapter explains how to solve some of those problems which tend to appear when compiling and linking your programs.
| Previous | Next | Up | Top |
Q: When I link my programs, ld.exe complains that it cannot open crt0.o, although that file exists in the lib subdirectory...
Q: I tried to compile a program, but GCC complained about missing header files netdb.h and socket.h. Can somebody please mail me those headers?
Q: Why does GCC complain that it "cannot open -lgcc: File format not recognized"?
If a header file indeed is not there, and you cannot find it in the djdevNNN.zip and gppNNNb.zip distributions, it probably means that header belongs to a package which isn't part of the basic DJGPP distribution. You need to find that package and install it. It is important to understand that if a package is missing, getting hold of the header files like socket.h is not enough: you need the library of the functions whose declarations and prototypes are in the header.
If the header or the library does in fact exist on your machine, then in order for the compiler to find them, you should have the following variable set in your environment(Note: The example uses Unix-style forward slashes, but DOS-style backslashes can also be used.):
set DJGPP=c:/djgpp/djgpp.envand it should point to the correct path of the file DJGPP.ENV on your system; the file itself is in djdev201.zip in the DJGPP distribution. In the above example it is assumed to be in the C:/DJGPP directory, but you should set it as appropriate for your installation.
Most of the problems with "missing" files, including the highly-confusing message about -lgcc ("File format not recognized"), are usually caused by having the DJGPP
variable
set incorrectly. The following describes some problems with defining DJGPP
which pop up frequently on the DJGPP forum.
Sometimes, people make errors in their AUTOEXEC.BAT that cause the DJGPP variable to be defined incorrectly, or not defined at all (some of the more common errors are listed below). To check what is the actual setting, type from the DOS prompt:
set > env.lstthen examine the contents of the file env.lst. You should see there a line like this:
DJGPP=c:/djgpp/djgpp.envIf a line such as this isn't there, you should investigate the cause for this (see below for some of the possibilities).
Many problems with setting DJGPP happen when people put excess blanks around the = character, which has the effect of defining "DJGPP " (with the blank) which is not the same as "DJGPP" (without blanks). You should make sure there are no such excess blanks, or DJGPP won't find its files.
Another possible cause of DJGPP variable not being set is that you invoke another batch file from your AUTOEXEC.BAT before the line that sets DJGPP. Make sure such
batch files are invoked with the CALL
statement, because otherwise the subsidiary batch file will never return to process the rest of AUTOEXEC.BAT (that's a "feature" of DOS
batch file processing).
The code that processes DJGPP.ENV assumes that this file resides in the main DJGPP installation directory. If that assumption is wrong, the compiler (and some other DJGPP programs) might fail to find some of the files or auxiliary programs they need. Do NOT move DJGPP.ENV to any other directory!
Note that if you run DJGPP on Windows/NT, you cannot use long names of the directories in the pathname of DJGPP.ENV when you set the above variable in the environment; you should use their 8+3 aliases instead. That's because Windows/NT doesn't support the LFN API for DOS programs, so the DJGPP startup code won't be able to find the DJGPP.ENV file using its long pathname. For example, the following setting won't work on Windows/NT because Development is longer than 8 characters:
set DJGPP=c:/Programs/Development/Djgpp/djgpp.envIf the DJGPP variable is set correctly, then check the following possible causes of this misbehavior:
stat
in some cases. The exact reason of the failure has been identified, and the library which comes with DJGPP v2.01 includes a version of
stat that works around that problem, so the linker from v2.01 is free of this bug, and upgrading will solve this. Another solution would be to upgrade your Novell software; version 4.x
is reportedly free of this problem, even if you use DJGPP v2.0.
main
function is
called, but it searches for the relevant variables using the actual name of the program, so when you rename the executable, it can't find its section and doesn't put the necessary variables into the
environment.
DJGPP
variable points to the main installation directory,
because GCC should be able to figure out all the linker switches itself. If linking fails without explicit -L or -B, check out above for the possible causes.
| Previous | Next | Up | Top |
Q: GCC complains about being unable to find Complex.h, Regex.h and other header files which start with a capital letter, and I indeed don't see them in my lang/cxx/ directory. Where are they?
Q: My C++ program needs header files whose filenames exceed the 8+3 DOS filename restrictions, like stdiostream.h and streambuf.h, and GCC cannot find those files. How in the world can I write portable C++ programs??
Complex.h
to _Complex.h
, and String.h
to _String.h
in your source, and GCC will find them. The same goes for the header
iostreamP.h
--you should use _iostreamP.h
instead. If you don't have the underscore _ on your keyboard, you might find using strclass.h
instead of
_String.h
easier.
Another possibility to handle header files like Complex.h
in a portable way is to pass the -remap switch (supported by GCC 2.8.0 and later) to the pre-processor; see the
cpp docs and the README.DJGPP file in the GCC distribution, for more info about this feature.
The most probable cause of problems with header files whose names exceed the DOS 8+3 limits is that you are compiling on Windows 9X, but the Long File Names (a.k.a. LFN) support is
disabled. DJGPP v2.01 comes with LFN disabled by default on the DJGPP.ENV file. To enable it, set the environment variable LFN
to y, like this:
set LFN=yIf the problems with long names of header files aren't solved by this, it is possible that you unpacked the DJGPP distribution with a program which doesn't support long file names. The solution is to install DJGPP again using a different unzip program.
If you have problems with header files with long filenames, and you run under Windows NT, it usually means that you used an unzip program which supports long file names on NT; unzip again using a DOS unzip program. Alternatively, you could install an LFN driver for Windows NT, see LFN driver for NT, earlier in this FAQ.
Another possible cause for problems with C++ include files is that your source file has a .c extension. GCC then thinks that this is a C program and doesn't instruct the preprocessor to search the include directories specific to C++. Rename your file to .cc or .cpp extension, or call GCC with the -x c++ switch, and the header files will be found. A full list of extension rules which GCC uses to determine the source language can be found in the list of language-specific suffixes, elsewhere in this FAQ.
| Previous | Next | Up | Top |
#include <stdio.h> int main () { printf ("%d \n" 10 //* / 2 //*/ 1 ); return 0; }If you must have both -ansi and C++-style comments, use -lang-c-c++-comments preprocessor switch. Gcc doesn't accept the -lang-XXX switches on its command line, so you will have to use the -Wp option, like this:
gcc -c -Wp,-lang-c-c++-comments myprog.cAlternatively, you can add -lang-c-c++-comments to the
*cpp:
section of your lib/specs file (but that will make it permanent).
Bottom line: until the future ANSI/ISO C standard includes this as part of the C language, it's best to change those //
comments to C-style ones, if you really mean to write a C program.
The following SED command will convert a C program with C++-style comments into a valid C source, provided you don't have the string "//" in a character string:
sed "s?//\(.*\)?/*\1 */?" file.c > newfile.cSED can be found with the DJGPP archives on SimTel.NET, in the v2gnu directory.
| Previous | Next | Up | Top |
Q: I type GCC PROG.C to compile a C program which I already remember to pass compilation without a single warning, and suddenly it gives all kinds of strange error messages and unresolved externals.
In the examples above, PROG.C is taken as a C++ program, not a C one, and PROG.CC is passed to the linker as if it were an object file. You can see what GCC does by adding the -v switch to the GCC command line; if you see that it's invoking cc1plus.exe (the C++ compiler) instead of cc1.exe (the C compiler), or calling ld.exe (the linker) on a source file, then you'd know this is your problem. If you have problems keeping up with the verbose GCC output caused by -v, see how to capture GCC output, earlier in this FAQ.
You can override the default rules gcc uses to decide how each input file should be treated, using the -x LANGUAGE switch. For instance, the command
gcc -x c++ prog.ccompiles prog.c as C++ source. See the "Overall Options" section of the "The GNU C Compiler Manual", for more info on -x options.
| Previous | Next | Up | Top |
Q: I compile an Objective-C program, but get unresolved symbols.
Q: I can't compile the Objective-C test program which came with DJGPP.
Objective-C was broken in GCC 2.6.0. The problem manifests itself by unresolved modules. If you use that version, you'll have to upgrade to version 2.6.3 or higher.
| Previous | Next | Up | Top |
#ifdef
directive to make it only visible under DJGPP?
__DJGPP__
, like this:
#ifdef __DJGPP__ ... DJGPP-specific code ... #else ... not seen under DJGPP ... #endif
__DJGPP__
has the value of the DJGPP major revision number, so you can write code fragments which have different behavior under different versions of DJGPP:
#ifdef __DJGPP__ #if __DJGPP__ > 2 .... will work only in DJGPP v3.x and later ... #else .... get here for DJGPP v2.x ... #endif #else .... get here in DJGPP v1.x or non-DJGPP environment #endifIf you need to distinguish between minor DJGPP revision numbers, use the symbol
__DJGPP_MINOR__
. For example:
#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 1 .... will work only in DJGPP v2.01 .... #endifAnother DJGPP-specific pre-processor symbol which DJGPP defines is
__GO32__
; but it is only provided for compatibility with previous versions of DJGPP (v1.x) and its use should be
discouraged.
| Previous | Next | Up | Top |
Q: Why does GCC complain that it cannot open -lstdcx?
Q: Why do I get "Undefined reference to yywrap" when linking programs produced by Flex?
When linking C++ programs, you can use either one of the gxx, gpp, or g++ commands (the latter on Windows 9X only) instead of gcc; they will then instruct the linker to also scan the C++ libraries automatically, so you don't have to remember doing that yourself.
Another reason for undefined references when linking C++ programs is that you mix GCC and libstdcxx.a from different releases: they are usually incompatible.
An error message about missing -lstdcx usually means that the linker cannot find the standard C++ library, libstdcxx.a. Look into your lib/ subdirectory to see if it's there; if not, unzip it from the gppNNNb.zip file. If libstdcxx.a exists but the linker still complains, you most probably have a problem related to long file names on Windows 9X (libstdcxx.a exceeds the DOS 8+3 limits). For a quick fix, try to set LFN=y in the environment and see if that helps. If that doesn't help, make sure you unpacked gppNNNb.zip with an unzip program which supports long file names. This issue is further complicated if you use RHIDE, and is described in full in the file gnu/gcc-2.81/problems.txt which comes with the GCC distribution (and which you should have read before installing it). Bottom line is that you need to add a line either to rhide.env or to DJGPP.ENV which says this:
RHIDE_TYPED_LIBS_DJGPP.cc=stdcxxWhen you add this line, make sure neither it nor the [rhide] line have trailing whitespace, otherwise RHIDE will not recognize these lines.
If your program uses a lot of floating-point math, or needs math functions beyond those specified in the ANSI/ISO standard, consider appending -lm to your link command line. The basic
math functions required by ANSI/ISO standard are included in the libc.a library, but libm.a includes higher quality versions of these functions, and also some functions not
included in the default library, like Gamma function and Bessel functions, support for Posix-compliant behavior in case of errors (e.g., it math functions from libm.a always set
errno
), a matherr
facility, etc.
| Previous | Next | Up | Top |
T
before their name. For example, the following is a fragment from the listing produced by nm:
c:\djgpp\lib> nm --demangle libc.a . . . stdio.o: 000000e4 b .bss 000000e4 d .data 00000000 t .text 00000098 t L12 0000001e t L3 00000042 t L6 0000004d t L7 0000006a t L9 00000000 t __gnu_compiled_c U _filbuf U _flsbuf 00000000 T clearerr 000000ac T feof 000000c2 T ferror 000000d8 T fileno 0000000c T getc 00000052 T getchar 0000002a T putc 0000007c T putchar 00000000 t gcc2_compiled. . . .Here we see that the module stdio.o defines the functions
clearerr
, feof
, ferror
, fileno
, getc
, getchar
,
putc
and putchar
, and calls functions _filbuf
and _flsbuf
which aren't defined on this module. Alternatively, you can call nm with the -s or -print-armap, which will print an index of what symbols are included in what modules. For instance, for libc.a, we will see:
c:\djgpp\lib> nm --print-armap libc.a . . . _feof in stdio.o _ferror in stdio.o _fileno in stdio.o . . .which tells us that the functions
feof
, ferror
and fileno
are defined in the module stdio.o. nm is fully described in the GNU docs. See the "nm" section of the "GNU Binutils Manual".
| Previous | Next | Up | Top |
-lgpp -lstdcxx -lmE.g., to link files main.o and sub.o into a C++ library, use the following command line:
gcc -o main.exe main.o sub.o -lgpp -lstdcxxor, if you compile and link in one command:
gcc -o main.exe main.cc sub.cc -lgpp -lstdcxx -lmIf you have any libraries of your own, put them before the above system libraries, like this:
gcc -o main.exe main.cc sub.cc -lmylib -lgpp -lstdcxx -lmWhen you use the gxx, the gpp or g++ compilation drivers to compile a C++ program, it automatically names the C++ libraries in the correct order. (gpp and gxx are the alternative names for g++ on DOS, which doesn't allow the + character in file names.)
You can also force the linker to repeatedly scan a group of libraries until all externals are resolved. To this end, put the names of these libraries between the -( and the -) options (if you invoke GCC to link, use the -Wl or -Xlinker options to pass switches to the linker). Check out the linker docs for more info about -( ... -) groups.
If your installation tree is different from the default, i.e., if you keep the libraries not in the default lib/ subdirectory, then you should add that directory to the
line in the [gcc] section of your DJGPP.ENV file which starts with LIBRARY_PATH, or put into your environment a variable called LIBRARY_PATH
and
point it to the directory where you keep the libraries. Note that if you invoke the linker by itself (not through the gcc driver), then LIBRARY_PATH
will have no effect, because this
variable is only known to the gcc driver. So if you must call ld directly, use the -L option to tell it where to look for the libraries.
| Previous | Next | Up | Top |
Q: I get many undefined references to symbols like __eh_pc
, terminate
, and __throw
...
inline
and defined on header files. However, GCC won't inline them unless you compile with optimizations enabled, so
it tries to find the compiled version of the functions in the library. Workaround: compile with -O.
Another cause of missing external symbols might be that your versions of libgcc.a and the compiler aren't in sync. These cases usually produce undefined references to symbols such as
__throw
and __eh_pc
. You should only use libgcc.a from the same distribution where you got the compiler binaries. The reason for these problems is that the
setup for supporting C++ exceptions is subtly different in each version of the compiler.
For C++ programs, be sure to compile all of your object files and libraries with the same version of the compiler. If you cannot recompile some of the old C++ object files or libraries, try using the -fno-exceptions -fno-rtti switches to GCC, it helps sometimes.
If you call C functions from a C++ program, you need to make sure the prototype of the C function is declared with the extern "C"
qualifier. DJGPP header files take care about
this, but headers you get with third-party libraries might not. Failure to use extern "C"
will cause the linker to look for a C++ function instead of a C function, which will
fail because names of C++ functions are mangled by the compiler.
| Previous | Next | Up | Top |
nm
, and I cannot find these creatures. Where in the world are they??
Another reason might be that you have edited your DJGPP.ENV file in a way that prevents the linker from finding its djgpp.djl script.
Mixing an old v1.x installation with a v2.x one can also cause such problems. Be sure to delete the entire v1.x tree, or rename it, before installing the v2.x distribution.
| Previous | Next | Up | Top |
static
array has the effect of bloating the program image on disk by that many bytes. Surely there is a more compact way of
telling the loader to set the next N bytes of RAM to zero?
If the problems with using this switch doesn't deter you, you can even add this switch to your lib/specs file to make it permanent.
| Previous | Next | Up | Top |
Q: I switched to GCC 2.8.1, and my C++ executables are considerably larger than when compiled with GCC 2.7.2.1!
C++ programs could be further bloated because the release of Binutils 2.8.1 was configured in a way that caused the assembler to put into the symbol table local labels generated when compiling code that uses exceptions. Later uploads of GNU Binutils should solve this problem, so consider upgrading to the latest bnuNNNb.zip.
Judging code sizes by looking at the size of "Hello" programs is meaningless, since most of the power of protected-mode programming goes wasted in such programs. There is no point in switching the processor to protected mode (which requires a lot of code) just to print a 15-byte string and exit. The overhead induced by the code needed to set up the protected-mode environment is additive; the larger the program, the smaller the overhead relative to the program size.
Apart from getting to protected-mode, the DJGPP startup code also includes such functionality as wildcard expansion, long command-line support, and loading the environment from a disk file; these usually aren't available with other DOS protected-mode compilers. Exception and signal handling (not available at all in v1.x), FPU detection and emulator loading (which were part of go32 in v1.x), are now also part of the startup code.
If your program doesn't need parts of the startup code, it can be made smaller by defining certain functions with empty bodies. These functions are __crt0_glob_function
,
__crt0_load_environment_file
, and __crt0_setup_arguments.
By defining empty substitutes for all three of these, you can make the "Hello" program be 28KB on disk. These
functions are documented in the DJGPP libc reference, which see. Here's an example of definitions for these functions that will make the startup code as small as it gets(Note: If you
define an empty substitute for __crt0_setup_arguments
, you don't need to define a substitute for __crt0_glob_function
.):
char **__crt0_glob_function (char *arg) { return 0; } void __crt0_load_environment_file (char *progname) { } void __crt0_setup_arguments (void) { }Note that if you define an empty substitute for
__crt0_setup_arguments
, your program will not be able to access its command-line arguments via the argv[]
array. So this is
only recommended for programs which don't accept any arguments at all.
You can make your program image still smaller by compressing it with a compressor called DJP.
DJP is a DJGPP-specific executable file compressor. It is fast and has no memory overhead. It also knows about DJGPP Dynamically Loaded Modules (DLM) technology. (Note
that DJP before version 1.06 was incompatible with Binutils 2.8.1 and later(Note: In particular, running strip
on a program and then compressing it with
DJP would produce a program that crashes upon startup.), so you should always use the latest DJP version available on SimTel.NET mirrors.)
| Previous | Next | Up | Top |
djgpp
, Windows will create a
file djgpp.lnk in your working directory. In that case, when ld.exe looks for its linking script, it will find this shortcut instead, and will be totally confused by its
format and contents. In DJGPP v2.01 and later, the linker script is called djgpp.djl, so that this conflict doesn't exist after you upgrade.
| Previous | Next | Up | Top |
Q: I run STUBIFY on a networked drive under Novell, but it doesn't produce a .EXE file. How come?
SMODE stubify.exe 2 SMODE ld.exe 2
| Previous | Next | Up | Top |
Q: I have some large libraries that I cannot link because the linker fails on them with a message saying "memory exhausted". I have plenty of virtual memory on my system, so why would ld fail?
calloc
.
| Previous | Next | Up | Top |
Q: It seems I miss one of the source files from the Allegro distribution, because Make cannot find it when I try to build Allegro.
Q: I can't build Allegro: it keeps telling me that I "need to install gcc2721b.zip". But I already have GCC installed!
| Previous | Next | Up | Top |
NULL
...
NULL
in a way that conflicts with the DJGPP headers. It's a bug in the GNU
C++ headers, but until it is fixed, you will need to make sure you include the C++ headers after the C headers. If that doesn't help in your case, you will need to hack
your headers to reconcile them.
| Previous | Next | Up | Top |
Q: When linking C++ programs, I get messages about undefined references to __EH_FRAME_BEGIN__
and such likes. Huh?
Q: I cannot compile C++ programs that include the header math.h: the compiler complains about redefinition of class exception!
Note that exception support with -fsjlj-exceptions is very slow, since it has a significant runtime overhead, even if the exception doesn't occur.
If you already use GCC 2.8.1, these problems could happen if you failed to replace the specs file with the version which comes with the GCC 2.8.1 distribution. Read the file README.DJGPP in the GCC distribution, for more details.
Exception support in GCC is generally not stable enough yet, so you need to treat with some suspicion code produced by GCC 2.8.1 for programs that use exceptions.
Undefined references to symbols like __EH_FRAME_BEGIN__
are a symptom of using an old linker script djgpp.djl. You should remove this file from your lib
subdirectory, which lets GCC use the new version that installs into the lib/gcc-lib/djgpp/X.YZ/ directory (where X.YZ is the GCC version number). Again,
README.DJGPP in the GCC distribution has more on this.
If GCC complains about "Redefinition of class exception" when you compile C++ programs which include the header math.h, you need to replace that header. GCC 2.8.1 comes with a
header exception that conflicts with math.h from DJGPP v2.01, which defines a struct exception
. Version 2.02 of DJGPP will correct math.h, and a
corrected version is included in the gcc281b.zip distribution. The corrected math.h is installed into the lib/gcc-lib/djgpp/2.81/include directory, so either
delete or rename the old version in the include directory, or copy the corrected version into include. Another solution is to compile with the -posix or
-ansi compiler switch, which cause math.h to not define struct exception
.
| Previous | Next | Up | Top |
Q: How can I create a file where I can see the C code and its assembly translation together?
gcc -O2 -S -c foo.cwill leave the generated assembly code on the file foo.s. If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -Wa,-a,-ad [other GCC options] foo.c > foo.lstwhich will output the combined C/assembly listing to the file foo.lst.
If you need to both get the assembly code and to compile/link the program, you can either give the -save-temps option to GCC (which will leave all the temporary files including the .s file in the current directory), or use the -Wa,aln=foo.s option which instructs the assembler to output the assembly translation of the C code (together with the hex machine code and some additional info) to the file named after the =.
| Previous | Next | Up | Top |
gcc -c -Wall -O2 file1.c gcc -c -Wall -O2 file2.c gcc -c -Wall -O2 file3.c ...The only GCC switch in this example that's required is -c, the rest are just recommended for better code generation and diagnostics.
Once you have the object files ready, use the ar
("Archiver") utility to create a library, let's say we'll call it libacme.a, like this:
ar rvs libacme.a file1.o file2.o file3.o ...The rvs flags tell ar to put named files in to the library, replacing any previous versions of these files if necessary, print the names of object files as it puts them into the library, and add an object-file index to the library, which makes it link faster.
If you use RHIDE, you can create a library by specifying a file with a .a extension as the main target in the project (choose Project | Main Target Name and enter a file name such as libfoo.a).
The library is now ready to use. The simplest way to force the compiler to use it while linking is to mention its name in the link command line, like this:
gcc -o myprog.exe myprog.c libacme.aThis is better than just listing in the command line all the object files in the library, since the latter will cause the linker to link in all the object files, even those which aren't used by the program.
The name of the library which begins with a lib and ends with a .a extension is a convention used for convenience. When the link command line includes an argument -lXXYYZZ, GCC (and all Unix compilers) will look for a file libXXYYZZ.a in every directory they search by default. So, if your library libacme.a is installed in the DJGPP lib subdirectory, the user can instruct GCC to look into it by appending -lacme to the link command line. Other systems might be configured to look for different names when a switch such as -lfoo is mentioned. For example, Linux might look in /usr/lib for a file libfoo.so.4.1, while Alpha/VMS will look for SYS$GNU:[LIBRARIES]FOO.LIB;19. Windows 98, of course, will look for something monstrously long like C:\Windows\Program Files\Vendors\GNU\gcc\libraries\foo.lib. If you don't follow this convention, you will need to type the full name of the library file.
If you need to update a certain object file in a library, use the same command ar rvs library-name object-name as above, but only with the name(s) of the object file(s) you need to replace.
ar
is documented in the Binutils docs. To read, type this from the DOS prompt:
info binutils ar
| Previous | Next | Up | Top |
Q: My v2 program crashes, but only under CWSDPMI; it runs OK under other DPMI hosts like Windows, OS/2 or QDPMI. Is this a bug in CWSDPMI?
malloc
is always zeroed, but v2 doesn't behave this way, so your program might exhibit erratic behavior or crash with
SIGSEGV
because of such bugs. In particular, if the program behaves differently depending on which program was run before it, you might suspect bugs of this kind.
To check whether this is the source of your grief, include the header crt0.h
in your main
and set _crt0_startup_flags
to
_CRT0_FLAG_FILL_SBRK_MEMORY
; this will fill the memory with zeroes when it is first allocated. If the program will run OK after recompilation, then this is probably the cause of your
problem. To make spotting uninitialized memory simpler, you can set _crt0_startup_flags
to _CRT0_FLAG_FILL_DEADBEEF
(don't laugh!); this will cause the sbrk()'ed
memory to be filled with the value 0xdeadbeef
(-559038737
in signed decimal or 3735928559
in unsigned decimal) which should be easy to spot with a debugger.
Any variable which has this value was used without initializing it first.
Another possible cause of problems will most probably be seen only under CWSDPMI; its telltale sign is a message "Page fault at ..." that is printed when a program crashes, and an error code of 4 or
6. Unlike other DPMI hosts, CWSDPMI supports some DPMI 1.0 extensions which allow DJGPP to capture and disallow illegal dereference of pointers which point to addresses less than 1000h (a.k.a.
NULL pointer protection). This feature can be disabled by setting the _CRT0_FLAG_NULLOK
bit in _crt0_startup_flags
; if this makes SIGSEGV crashes go away, your
program is using such illegal pointers; the stack trace printed when the program crashes should be a starting point to debug this. See how to debug SIGSEGV, for more
details about these problems.
An insufficient stack size can also be a cause of your program's demise, see setting the stack size, below.
| Previous | Next | Up | Top |
symify your-program-nameSymify then walks through the crash traceback by reading back from video memory, and matches the hex addresses to the source files and line numbers of the program. It then writes back the list of source files and line numbers right next to their hex addresses. Now you can start debugging. More info about this is available in how to analyze crash dumps.
One problem with this translation is that it relies on info generated by GCC that maps the instruction addresses to source line numbers. This usually works okay, but one notable exception is when you use inline assembly. In this case, GCC only records the last line of the inline assembly block, which might be way off if the block is large.
You can ask SYMIFY to put the stack trace into a file (so you can consult it later, e.g., from your editor while fixing the bug), by giving it an output file, like this:
symify -o problem.dmp yourprogYou can also save the raw stack trace (without source info) to a disk file and submit it to SYMIFY later, like this:
symify -i core.dmp yourprogThis comes in handy when your program grabs the screen (e.g., for some graphics) and the stack trace can't be seen. You can then redirect the stack trace to a file, e.g., with the REDIR program which comes with DJGPP.
But what if you didn't compile your program with -g, and you aren't sure how to recreate the problem which crashed it, after you recompile? Well, you can submit the stack dump after you recompile your program. Just press that PrintScreen key or otherwise save the stack trace, then submit it to SYMIFY from a file as described above, after you've recompiled the program. Be sure to give gcc all the compilation switches (sans -s) that you gave it when you originally compiled your program (in addition to -g), including the optimization switches, or else the addresses shown in the stack trace might be invalid.
If all you have from the crash is the program counter, the eight-digit hex number after "eip=", you can still find out the corresponding source line using GDB. Assuming that the EIP value is NNNNNNNN, type this at the GDB prompt:
list *0xNNNNNNNN
| Previous | Next | Up | Top |
Q: My program crashes when I read data files, but the same program on Unix works OK.
Q: When I read a file I get only a small portion of it.
Q: I'm trying to open an existing binary file for read/write using the fstream
class, but no mater what I do, the file is always truncated after I write to it...
read
and write
library functions. Text files get their
newlines converted to CR-LF pairs on write and vice versa on read; reading in "text" mode stops at the first ^Z character. Reading binary files as text will therefore
corrupt the data and fail to read all the data you need. You must tell the system that a file is binary through the b
flag in fopen
, or O_BINARY
in
open
, or use the setmode
library function. Note that the above distinction between binary and text files is written into the ANSI/ISO C standard, so programs that rely on the Unix behavior whereby there's no such distinction, are strictly speaking not portable.
You can also use the low-level _read
and _write
library functions which give you the direct interface to the DOS file I/O; they always use binary I/O.
Problems with read/write access to binary files via fstream
class in C++ programs are due to a bug in the GNU iostream library. This bug causes truncation of files, even if you
never write to the file. The library distributed with GCC version 2.8.1 is free of that bug, so upgrade. A workaround is to do something like this:
fstream inFile; int fd = open ("foobar", O_RDWR | O_BINARY); inFile.open (fd);
| Previous | Next | Up | Top |
Q: Help! I cannot make `gotoxy' work! The text I print appears on the screen in incorrect locations after I use `gotoxy'!
Q: Why does the text appear in the default colors even though I call `textcolor' and `textbackground'?
fprintf
, fputs
and the like) functions, or send your output to the C++ cout
stream? Then what you see is the effect of the buffering of the standard output streams. The buffer is not written to screen until it's full, or until a newline is output, which might produce very
unpleasant and unexpected behavior when used in interactive programs.
It is usually a bad idea to use buffered I/O in interactive programs; you should instead use screen-oriented functions like cprintf
and cputs.
If you must use buffered I/O,
you should be sure that both stdout
and stderr
are line-buffered or unbuffered (you can change the buffering by calling the setvbuf
library function); another
solution would be to fflush
the output stream before calling any input function, which will ensure all pending output is written to the operating system. While this will generally work
under DOS and DJGPP, note that in some cases the operating system might further buffer your output, so sometimes a call like sync
would be needed to actually cause the output be
delivered to the screen.
The functions that set text attributes only affect the screen-oriented output (a.k.a. conio) functions (cputs
, cprintf
etc.), the text written by
fprintf
and other stdio functions doesn't change. This is unlike some 16-bit DOS compilers where stdio
functions can also print colored text.
| Previous | Next | Up | Top |
PATH
, or (b) install another DPMI host (such as QDPMI, 386Max, Windows, etc.) on the target machine. If your program could be run on a machine which lacks a floating-point processor, you should also distribute an emulator, or link your program with an emulator library. See floating-point emulation issues.
PMODE/DJ can be bound with your program, so that you have a single self-sufficient executable, but remember that PMODE/DJ doesn't support virtual memory, so such programs will only run on machines with enough free physical RAM.
Q: I put a FILES=60 directive in my CONFIG.SYS, but my programs cannot use more than 42 when they run on Windows. Why is that?
It is true that DJGPP library lets you open up to 255 handles--but only if the operating system allows it. The operating system further limits this number, depending on several factors.
First, if you create new handles by calling the dup
library function (or the underlying function 45h of the DOS Interrupt 21h), you can always have up to 255 such handles, even if the
FILES= directive sets a much smaller count. All such handles refer to the same file or device and moving the file pointer using one handle moves all the rest of them.
In nested programs (that is, programs that were invoked by other programs), this is a bit more complicated. By default, any handle that is open in the parent program is inherited by the
child, unless the parent sets the special O_NOINHERIT
bit when it opens the file. Thus, if the parent had 10 files open when it invoked the child, the child program will have 10 less
available handles--245--to work with, even if it only calls dup
(Note: All DOS programs get the default 20-handle table when they start; DOS only copies the first 20 handles
into the child, so it is not possible to inherit more than 20 handles. The expansion of the default 20-handle table to 255 handles is a special feature of the DJGPP library, and it only happens when
the programs exhausts all of the 20 handles while it runs. Therefore, when all of the first 20 handles are taken up by files inherited from the parent program, the child program can fail to start
because the DJGPP stub loader needs one free handle to open and read the COFF executable into memory. The stub cannot use the enlarged 255-handle table, since it cannot call the DJGPP library. Such
problems indeed happen in programs compiled with DJGPP v2.01; v2.02 fixes this bug.).
The FILES= directive comes into play when you call open
or any of its brethren to create handles. Unlike the handles created by dup
, open
(and the
underlying functions 3Dh or 6Ch of Interrupt 21h) create handles that are independent of each other, even if you open the same file over and over again. The operating system will not let
you create more such handles than the limit set by the FILES= directive. This is because the FILES= directive sets the number of entries in the SFT, the System File
Table maintained by DOS, where all the information about every open file is kept(Note: Each handle created by a call to open
uses up one slot in the SFT, whereas a handle
created by dup
just increments the use count of a slot that was already in use.). So, if your CONFIG.SYS specifies FILES=60, you cannot open
more than 60 files. After that, a call to open
will fail with ENFILE
(Too many open files in system).
In practice, you won't even be able to get 60 handles if you have FILES=60 in your CONFIG.SYS, since several handles are always preconnected. On plain DOS, 5 handles are already open when a program starts. These correspond to standard input, standard output, and standard error streams, and the other 2 handles are connected to the AUX and PRN devices. So, if you have FILES=60, DOS will only let you open up to 55 independent handles.
The plot thickens even more if you run DJGPP programs on Windows. Since Windows itself uses up 10-15 handles in the System Virtual Machine (VM), it tries to make it up for the DOS programs by adding private file tables to each DOS box with additional handles, beyond those maintained in the SFT. The default is to add a private table with 10 handles to each DOS box, but the PerVMFiles= entry in the [386Enh] section of the SYSTEM.INI file can override that. So on Windows, you need to consider the PerVMFiles= setting as well, and the resulting limit on open handles is less predictable since the number of handles used by Windows isn't constant (for example, it depends on how many fonts are loaded by Windows programs at any given moment).
If your system loads SHARE.EXE during bootstrap, things become even more complicated. SHARE.EXE prevents Windows from adding private file tables (because it couldn't spy on files open via those private handles), so you get 10-15 less handles than what the FILES= directive says, and sometimes even less than that. That is how somebody who has FILES=60 on their CONFIG.SYS could only get 42 handles on Windows. If you are looking for reasons not to load SHARE.EXE, here you have another one.
Another important source of related information is a tutorial on graphics programming with DJGPP.
| Previous | Next | Up | Top |
Q: How do I tell GRX which driver to use with my SVGA?
GRX20DRV
environment variable, like this:
set GRX20DRV=et4000 gw 1024 gh 768 nc 256To set that variable, you need to know the chip-set on your adapter; refer to your SVGA documentation. Currently, GRX supports the following chip-sets:
GRX20DRV
variable, run modetest.exe to see what modes you have available. If your chip-set is not one of the above, try the VESA driver because many adapters support the VESA BIOS extensions. If yours doesn't, try installing a VESA BIOS emulator, like UNIVBE. The latest version of UNIVBE and related software is always available from SciTech Web site.
| Previous | Next | Up | Top |
0xa0000
, but my program crashes with SIGSEGV... Q: How can I access the text-mode video memory of my VGA?
_farpeekb
and _farpokew
; they are described in the C Library reference. See more details on using "farptr" functions to access absolute addresses in low
memory, below.
For text-mode screen updates, you can use the ScreenUpdate
and ScreenUpdateLine
library functions to quickly update the screen from a text buffer.
Using the _farpeekX/_farpokeX
paradigm to access memory isn't much slower than direct access (they compile into 2 machine instructions when optimizations are enabled). But if you need
even faster access (and don't want to write it in assembly), see using the "nearptr" access facilities, as described below.
If your video card supports the VBE 2.0 standard, you can access the linear frame buffer as a normal array in memory. For an example of such a technique, see the VBE example code by Charles Sandmann. You can also reach this file via the Web. Some examples of how to access video memory from DJGPP programs are available from Brennan Underwood's Web page.
Q: I cannot run my program which uses Allegro: Windows 9X says the program would work better in DOS Mode...
The only reasonable thing to do is to dedicate a "hotkey" in your application (e.g., Alt-R) whose action is to redraw the entire screen. If you do that, it's best to start all the way
from the beginning, e.g. with a call to GrSetMode
(if you use GRX), as there are a few bad Windows video drivers which do not restore SVGA graphics modes properly upon the switch back.
Windows 9X does save and restore the SVGA state, but only if you task-switch with the Alt-<TAB> key. If the switch happens because of anything else, like a window popping up, or you pressing the Start button, there's nothing your application can do to ensure it restores correctly, because it just never gets moved back into focus. As soon as the user tries to restore it, Windows 9X comes up with this message:
This application cannot be restored and will be terminated.To prevent Windows 9X from getting in your way when running graphics programs, like popping up messages that suggest to run the program in DOS Mode, just disable one or more of the relevant properties for that program. Here's a detailed procedure to disable them all:
| Previous | Next | Up | Top |
Q: What shall I install on a target machine which lacks hardware floating-point support?
A few users reported that the emulation won't work for them unless they explicitly tell DJGPP there is no x87 hardware, like this:
set 387=N set emu387=c:/djgpp/bin/emu387.dxeThis is probably due to some subtle bug in the emulator setup code. This code is hard to debug, because the people who developed it have machines with hardware FP processors. Volunteers with FPU-less machines are needed to help debug the above problem. If you have access to a system without an FPU and are willing to fix this problem, write to Charles Sandmann and ask him for guidance.
There is an alternative FP emulator called WMEMU (get the file v2misc/wmemu2b.zip). It mimics a real coprocessor more closely, but is larger in size and is distributed under the GNU General Public License (which generally means you need to distribute its source if you distribute wmemu387.dxe, or distribute the source or objects to your entire program, if you link it with libwmemu.a). Its advantage is that with WMEMU, you can debug FP apps on a non-FPU machine. (But you will need to get the sources and recompile it, since it was compiled with a beta release of DJGPP and will cause unresolved externals if you try linking against libwmemu.a without recompiling it.) Note, however, that even WMEMU doesn't solve all the problems of debugging FP programs on a non-FPU machine (e.g., emulating flags doesn't work).
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
_control87
can be used from within a program to set the coprocessor to a non-default state.
| Previous | Next | Up | Top |
atan
function. So if you use atan(1.)
to get the value of Pi, that might be your problem. Solution: make Pi a constant, as God intended. The
header file <math.h>
includes the constant M_PI
which you can use; or get the value of Pi from the net.
| Previous | Next | Up | Top |
ldexp
function, my program crashes with SIGFPE. What's wrong?
ldexp
. A work-around
is to link without -lm switch; this will cause GCC to use math functions from libc.a. If you need math functions which are only in libm.a, or if
you need libm.a for better numerical performance, a patched version of libm is available, courtesy of
Tom Demmer. DJGPP v2.01 corrects this bug, so upgrade to that version if you can.
| Previous | Next | Up | Top |
gcc -Wall -c -g -O myfile.c gcc -Wall -O2 -g -o myprog.exe mymain.c mysub1.c mysub2.c -lm gcc -g -o myprog myprog.o mysub.oNote that with gcc, you can use optimization switches when compiling with -g. To use stabs debugging, compile with -gstabs3 or -gstabs+ instead of -g.
Then, to debug the program, use a command line like this (here for gdb):
gdb myprog.exeBeginning with v2.01, DJGPP debuggers can debug both unstubbed COFF images and DOS-style .exe executables (v2.0 only supported COFF files). To debug a COFF file, name it without the .exe extension, like so:
gdb myprogYou can use one of several available debuggers with DJGPP:
stdin
or stdout
, you will be unable to
communicate with GDB.
<debugger-name> <program> <args...>
| Previous | Next | Up | Top |
Q: Can you help me figure out all those funny numbers printed when my program crashes?
redir -e crash.txt myprog [arguments to the program go here](here I used the
redir
program supplied with DJGPP; the -e switch tells it to redirect the standard error stream to the named file). After you've saved the crash message, look at the name of the crashed program, usually printed on the 4th line. Knowing which program crashed is important when one program calls another, like if you run a program from RHIDE. Without this step, you might erroneously try to debug the wrong program.
The next step in the debugging is to find out where in the code did the program crash. The SYMIFY
program will help you translate the call frame traceback, which is the last portion of
the crash message, into a list of function names, source files and line numbers which describe the sequence of function calls that led to the crash. The top-most line in the call frame traceback is
the place where the program crashed, the one below it is the place that called the function which crashed, etc. The last line will usually be in the startup code, in a function called
__crt1_startup
, but if the screen is too small to print the entire traceback without scrolling, the traceback will be truncated before it gets to the startup. See
how to use SYMIFY
, for more details about the call frame traceback and SYMIFY
usage.
If you compiled your program without the -g switch, or if you stripped the debugging symbols (e.g., using the -s linker switch), you will have to rebuild the program with -g and without -s, before you continue.
Next, you need to get an idea about the cause of the crash. To this end, look at the first two lines of the crash message. There you will find a description of the type of the crash, like this:
Exiting due to signal SIGSEGV Page Fault at eip=00008e89, error=0004(the actual text in your case will be different). The following table lists common causes for each type of crash:
malloc
(did your code check for that?). An uninitialized pointer holds some random garbage value; it can come from a missing call to malloc
. If the message says Page Fault in RMCB, then it usually means that the program installed an interrupt handler or a real-mode callback (a.k.a. RMCB), but failed to lock all the memory accessed by the handler or functions it calls. See installing hardware interrupt handlers, for more about this.
int
to a
function that expects a double
, or passing buffers to a library function without sufficient space to hold the results;
Overrunning the stack frame usually manifests itself by abnormal values of the EBP or ESP registers, printed right below the first two lines. The normal case is when
ESP is slightly smaller than EBP, smaller than the limit of the SS segment, and usually larger than EIP(Note:
Programs that create machine code in malloc
ed storage and then jump into it could have their EIP above EBP. The Allegro library utilizes this
technique in some of its functions.); anything else is a clear sign of a disaster.
Another telltale sign of an overrun stack frame is that the symified traceback points to a line where the function returns, or to its closing brace.
Suspect a stack overflow if the EBP and ESP values are close to one another, but both very low (the stack grows downwards), or if the call frame traceback
includes many levels, which is a sign of deep recursion. Stubediting the program to enlarge its stack size might solve such problems. See changing stack size, for a
description of how to enlarge the stack. If you use large automatic arrays, try to make their dimension smaller, or make them global, or allocate them at run time using malloc
.
SIGFPE
, mean some error in floating-point computations, like division by zero or overflow.
Sometimes such errors happen when an int
is passed to a function that expects a float
or a double
.
SIGSEGV
(0123 in hex is the numeric code of SIGSEGV
; see the header
signal.h for the other codes), and that handler attempted to return. This is not allowed, since returning to the locus of the exception will just trigger the same exception again and
again, so the DJGPP signal-handling machinery aborts the program after printing this message.
If you indeed wanted SIGSEGV
to be generated in that case, the way to solve such problems is to modify your signal handler so that it calls either exit
or
longjmp
. If SIGSEGV
should not have been triggered, debug this as described below.
abort
: v2.0 had a bug in its library whereby calling abort
would bypass the cleanup code that restored the keyboard interrupt hooked by the DJGPP startup code; v2.01
solves this bug.
Using the itimer
facility can also cause such crashes if the program exits abnormally, or doesn't disable the timer before it exits.
SIGINT
generation works by invalidating the DS/SS selector, but since CWSDPR0 doesn't switch stacks on exceptions there's no place to put the exception frame for the
exception this triggers, so the program double faults and bails out). Otherwise, treat this as Page Fault
.
SIGINT
.
If you are lucky, and the crash happened inside your function (as opposed to some library function), then the above info and the symified call frame traceback should almost immediately suggest where's the bug. You need to analyze the source line corresponding to the top-most EIP in the call frame traceback, and look for the variable(s) that could provide one of the reasons listed above. If you cannot figure it out by looking at the source code, run the program under a debugger until it gets to the point of the crash, then examine the variables involved in the crashed computation, to find those which trigger the problem. Finally, use the debugger to find out how did those variables come to get those buggy values.
People which are less lucky have their programs crash inside library functions for which SYMIFY
will only print their names, since the libraries are usually compiled without the debug
info. You have several possible ways to debug these cases:
SYMIFY
succeeded to convert to a pointer to a line number in a source file. This line should be a call to some function in some library you used
to link your program. Re-read the docs for that function and examine all the arguments you are passing to it under a debugger, looking for variables that could cause the particular type of crash you
have on your hands, as described above.
SYMIFY
to get a full
description of the place where it dies.
SYMIFY
should be able to find the line number info for the entire traceback.
| Previous | Next | Up | Top |
qdpmi off
| Previous | Next | Up | Top |
gcc -o foo foo.oinstead of
gcc -o foo.exe foo.o(the latter will only produce foo.exe, while the former produces both foo, the COFF executable which gdb needs, and foo.exe).
To produce a COFF file from a .exe program, use the EXE2COFF program which comes with DJGPP, like this:
exe2coff foo.exeDebuggers which come with DJGPP v2.01 can debug COFF and .exe programs alike, so upgrading to v2.01 should solve this problem.
| Previous | Next | Up | Top |
gdb myprog > prnThis will only work if the program itself doesn't write to stdout (graphics programs usually don't); otherwise the debugger output will get mixed up with your program's output.
Beginning with version 1.1, RHIDE and RHGDB support debugging graphics programs, so upgrade to latest version of RHIDE and use its built-in debugger or the stand-alone RHGDB subset. This support doesn't work for all video modes, but the standard VGA modes and VESA modes are supported.
The FSDB debugger can switch between the application screen and the debugger screen, so you might use it, at a price of working with a low-level debugger. Press Alt-<F5> to switch between the two screens. Stock FSDB as distributed with DJGPP can only do this with text screens, but a modified version of FSDB with graphics support is available that knows about many graphics modes. The same distribution can also be found on the Oulu repository.
As yet another possibility, consider using the MSHELL program which will redirect I/O from any program to the monochrome monitor at the BIOS level, so you can use it even with GDB. MSHELL was written by DJ Delorie and is available from DJ's server. Be sure that you don't have some other TSR installed that catches screen writes and bypasses the BIOS functions, or else MSHELL won't help you. For example, changing the code page (with the DOS CHCP or MODE commands) might do this.
RHIDE also supports dual-monitor systems for debugging, it allows you to use the monochrome monitor for interface with the debugger, while leaving the color screen for your program's display, with no need to swap between them.
If you have any problems with dual-monitor support, in particular with RHIDE, make sure your memory manager doesn't grab the B000
segment for its own purposes. This
region should be available for the mono adapter, or your system might crash when you try using it.
Another way to redirect the output of a program to a monochrome monitor is by using the MDA display driver from BinaryInfosys. It is a true DOS device driver, and so can be opened as a file--handy for sending debug info, for example. This driver is free and is available from BinaryInfosys' home page.
| Previous | Next | Up | Top |
file.cc: No such file or directory.The source file is there, but it's called file.cpp, not file.cc. Why does this happen?
GCC 2.8.0 and later corrects this bug, so upgrading is also a solution.
| Previous | Next | Up | Top |
CMPForward
has a method
named go
which you need to put a breakpoint in, use the following command:
b 'CMPForward::go'Other GDB features that might be useful in this context are the various demangling options, like set print demangle, set demangle-style etc.; look them up in the GDB on-line docs.
However, there are some cases where you won't be able to get GDB to demangle C++ function names no matter how hard you try. This is due to a lack of sufficient debugging information in the COFF files with SDB debug data. There's simply not enough info there for GDB to detect the source language and use C++-specific support. If you need a description of the GNU style of mangling C++ names (so you could demangle them yourself), look in the GDB or Libg++ source distribution, in the libiberty directory, for a file named cplus-demangle.c. If you really need full C++ support in DJGPP, you will have to use the stabs debugging support. GCC 2.8.0 and later are distributed with built-in stabs support, so upgrade if you need this. Caveat emptor: FSDB, EDEBUG32 and SYMIFY don't understand stabs, so you will have to compile with -gcoff option to use these utilities (RHIDE distribution includes a utility called gsymify that can be used instead of SYMIFY with stabs debugging info).
Note that, as the debugger built into RHIDE uses GDB code, it will also sometimes have such problems with debugging C++ programs.
| Previous | Next | Up | Top |
Q: I cannot debug code produced by Flex, or Bison, or F2C, because GDB somehow messes up all the source file and line number info!
Q: Why can't I step with a debugger into an inline function defined in a header file?
f2c -g myprog.f
gcc -g myprog.c -o myprog.exe -lf2c -lm
copy myprog.f myprog.c
gdb myprog.exe
| Previous | Next | Up | Top |
.bss
section of the program). A work-around is to initialize these variables, which causes the linker to put
them into the .data
section. Another solution is to use the stabs debugging support; latest versions of GCC include this support, so upgrade.
Q: I cannot debug any program which catches signals!!??
Q: I compiled my program with -pg switch, and now I cannot debug it...
Q: When my program hits a breakpoint in GDB, the debugger reports SIGSEGV, but only under Windows...
symify
can identify; programs using alarm
or setitimer
can't be debugged, either. You can't hook the keyboard interrupt in a
debugged program, and you can't debug a program which uses floating point on a machine without FP hardware (unless you use WMEMU as your emulator, but even WMEMU doesn't
solve all the problems). The reason for all these problems is that any exceptions or signals that happen when your program runs under a debugger will be caught by the debugger instead, and they
won't get passed to the debuggee. To debug programs which hook hardware interrupts, you will have to chain the old real-mode interrupt handler to your new handler, which requires to write special
debug version of the program. At least some of these limitations will be fixed in future versions of DJGPP. In case you need a Ctrl-<C> key-press to go to the debuggee instead of the debugger, a work-around is available: use the Alt-Numeric-3 (that is, press the <Alt> key, the press and release the <3> key on the numeric keypad. Some programs (but not Emacs) will also treat the Ctrl-<2> key-press as Ctrl-<C>.
Beginning with version 1.1, the debugger built into RHIDE supports debugging programs that hook keyboard and/or timer hardware interrupts, so if you need e.g. to debug programs built with the Allegro library or programs compiled for profiling, you can use RHIDE.
Another known problem is that GDB GP Faults when the program hits a breakpoint under Windows 3.X (Windows 9X doesn't have this problem). This is because the breakpoint instruction causes a software interrupt (as opposed to an exception) under Windows 3.X, and the DJGPP debug support currently only catches debug exceptions. The only work-around is to use the hardware breakpoints (which use the special debug registers of the i386 and higher CPUs, and which do work with DJGPP on Windows 3), and never have more than 4 of them active at the same time. FSDB will automatically use the hardware breakpoints for the first 4 breakpoints (so it works on Windows 3.X unless you set more than 4 breakpoints simultaneously), but with GDB, you will have to explicitly use the hbreak and thbreak (instead of break and tbreak) commands which set hardware breakpoints. This works with DJGPP ports of GDB 4.16 and later. Note that GDB uses the ordinary breakpoints to implement the step, next and similar commands, so you can't use these on Windows 3.X; use the temporary hardware breakpoints instead. The above is also true for watchpoints (which watch for variables to change value): you need to use hardware watchpoints with GDB (the total number of breakpoints and watchpoints cannot exceed 4). Same considerations apply to the debugger built into RHIDE under Windows 3.X.
| Previous | Next | Up | Top |
gprof myprog(change myprog to whatever name your program is). This will print an execution profile. You can now look at the profile and try to optimize the functions which take a large proportion of the execution time.
Gprof is further documented in the Binutils docs as part of the GNU Binutils distribution.
| Previous | Next | Up | Top |
Q: When I compile my program with -pg, it runs much slower. Does the profiling code have such a huge overhead?
Q: I profiled my program, but the profile contains an entry _mono_putc
which I don't use, and which eats up about 70% of execution time!
Q: When I run a profiled program on my dual (VGA+MDA) display system, the mono screen shows loads of meaningless numbers. Is there a way to stop this behavior?
A patch which corrects this bug was posted to the DJGPP News group; you can find it by searching the DJGPP mail archives. The patched library (see a better library) includes a fixed version of the offending function, so using the patched libc will solve these crashes (as will upgrading to v2.02, when that is available). A work-around is to run the program compiled with -pg on vanilla DOS configuration (no memory managers such as EMM386 or QEMM, and no Windows). However, when you use this work-around, your program might run much slower, although the profile that you get is not affected.
| Previous | Next | Up | Top |
Q: I run Gprof on my program, and it says: "bad format".
| Previous | Next | Up | Top |
Q: I can't figure out some of the info in the Gprof report ...
| Previous | Next | Up | Top |
__dpmi_int
so heavily used?
__dpmi_int.
Can't you guys make
your library right?
__dpmi_int.
So what the profile really says is that the running time of your program is governed by time-consuming operations such as disk I/O.
atexit
library function, and won't be called if the program was terminated
in an abnormal way. Make sure that your program exits with a call to exit
library function or with a return
statement in your main
function. For example, if
your program dies with an exception or a signal, install a signal handler and make it call exit.
| Previous | Next | Up | Top |
Q: Won't my program run much slower when compiled by DJGPP, due to all those CPU cycles wasted in switches between protected and real mode?
| Previous | Next | Up | Top |
Q: I timed a test program and it seems that GCC 2.8.1 produces slower executables than GCC 2.7.2.1 was, which in turn was slower than DJGPP v1.x. Why are we giving up so much speed as we get newer versions?
Q: I installed Binutils 2.8.1, and my programs are now much slower than when they are linked with Binutils 2.7!
errno
variable to be set or the matherr
function to be called in case of errors.
Programs which manipulate multi-dimensional arrays inside their innermost loops can sometimes gain speed by switching from dynamically allocated arrays to static ones. This can speed up code because the size of a static array is known to GCC at compile time, which allows it to avoid dedicating a CPU register to computing offsets. This register is then available for general-purpose use.
Another problem that is related to C++ programs which manipulate arrays happens when you fail to qualify the methods used for array manipulation as inline
. Each method or
function that wasn't declared inline
will not be inlined by GCC, and will incur an overhead of function call at run time.
However, inlining only helps with small functions/methods; large inlined functions will overflow the CPU cache and typically slow down the code instead of speeding it up.
A bug in the startup code distributed with DJGPP versions before v2.02 can also be a reason for slow-down. The problem is that the runtime stack of DJGPP programs is not guaranteed to be aligned on
a 4-byte boundary. This usually only shows up on Windows (since CWSDPMI aligns the stack on its own), and even then only sometimes. But it has been reported that switching to Binutils 2.8.1
sometimes causes such slow-down, and switching to PGCC can reveal his problem as well. In some cases, restarting Windows would cause programs run at normal speed again. If you experience such
problems too much, either upgrade to v2.02 or ask for a patch that solves it. (The patch is in the stub loader, so you will need to recompile the stubify
utility and point the
STUB
environment variable to a program with a new stub.)
| Previous | Next | Up | Top |
Q: I run the same program on a 486 and on a Pentium, and it's slower on a Pentium!!
Lately, the FSF has split the GCC development into two branches: one is the regular GCC, while the other is called EGCS(Note: Pronounced like "eggs".), the Experimental GNU Compiler System. The latter is usually less stable than the GCC releases, but supports more advanced features, like the so-called Haifa scheduler, a new global subexpression elimination engine, and multi-language stuff. PGCC is a derivative of EGCS which supports additional optimizations specific to the x86 architecture; its optimizations for Pentium CPUs, and even for an i486, are better than those of GCC. So if you need to squeeze the last bits of performance from programs that target Pentium machines, use EGCS/PGCC to compile them. One drawback of EGCS/PGCC is that compilation is slower than with GCC and needs much more memory, sometimes an order of magnitude more, especially at higher optimization levels. PGCC was ported by Andrew Crabtree, and can be downloaded from the PCG site.
A program might sometimes run slower on a Pentium due to alignment problems in DJGPP. GCC makes assumptions about how GAS (the assembler) handles alignment, but when GAS is built with the default DJGPP configuration, it treats alignment in a way that's different from what GCC assumes. The outcome of this is that longs are word-aligned, doubles are dword-aligned, etc. Depending on the DJGPP version, link order, library differences, you might get lucky (or unlucky) with a 50/50 chance to get an improper alignment. Different CPUs have different penalties for unaligned accesses, which may explain differences in speed. DJGPP v2.01 has a bug in the startup code, whereby the runtime stack isn't aligned; this could also be a reason for slow-down, especially in programs compiled by EGCS/PGCC.
You might consider adding some slack static variables to induce changes in alignment; if any of the changes suddenly cause a significant change in the runtime performance, then alignment might be the reason.
| Previous | Next | Up | Top |
Q: I tried to improve DJGPP I/O throughput by defining a 64KB-large buffer for buffered I/O with a call to setvbuf
, but that had no effect. Why is that?
Q: It is obvious that disk-bound programs compiled with DJGPP will run awfully slow, since FAT is such a lousy filesystem!
Doing I/O from protected-mode programs requires that low-level library functions move the data between the extended memory and low memory under the 1 MByte mark, where real-mode DOS can get at it. That area in the low memory is called the transfer buffer(Note: Here's a more detailed explanation. DOS cannot access memory above 1MB mark, where your DJGPP program lives, since real-mode addresses are 20-bit wide, which covers only the first megabyte. So, each time a DJGPP program needs to call a DOS function (or any other real-mode service, like some BIOS interrupt) and needs to pass data to or from that service, we must use some buffer in conventional memory to communicate. The transfer buffer is a block of conventional memory that the DJGPP startup code allocates for this purpose. When a real-mode service is called, the data that needs to be submitted to it is copied to the transfer buffer, and the address of the transfer buffer is passed to the real-mode service. If the service returns some data (e.g., if you want to read a portion of a file), data is copied from the transfer buffer when the service returns.
The transfer buffer primarily exists for library functions, but it can also be used by an application, if it needs to invoke real-mode services.). This data shuffling means that some I/O speed
degradation is inevitable in any protected-mode program which runs on top of DOS (including, for example, Windows programs when Windows 3.X is set to 386-Enhanced mode). By default, DJGPP moves data
in chunks of 16 KB, so defining a buffer larger than that won't gain anything. The size of the transfer buffer is customizable up to a maximum of 64 KB(Note: Actually, the maximum possible
value is FEF0h, or 65254 in decimal, because the transfer buffer is created by the startup code by resizing the PSP memory block. Since the resized block needs to leave 256 bytes for the PSP, and
needs to be aligned on a 16-byte boundary, you cannot have the entire 65535 bytes for the transfer buffer. If you invoke stubedit
with a bufsize=64k parameter, what you
actually get is a 2KB buffer, since the combined size of the PSP and the transfer buffer will wrap around in a 16-bit variable when the startup code computes it. The version of stubedit
which will come with DJGPP v2.02 will explicitly warn you about this case and will reset any value that is too large to the maximum allowed size of FE00h (65024 decimal) bytes--this is less than
FEF0h because the latter is not aligned on the 512-byte DOS sector size, which could slow down disk I/O.), so if your program really reads a lot of large files, you might be better off enlarging
it (with the STUBEDIT program).
Some people think that FAT is such a lousy filesystem, that programs which do a lot of disk I/O must run terribly slow when compiled with DJGPP. This is a common misconception. The speed of disk I/O is determined primarily by how efficient is the code in the operating system kernel that handles the filesystem, and the device drivers for the I/O-related devices like the hard disk, not by the disk layout. It is true that DOS and BIOS don't implement I/O too efficiently (they use too many tight loops waiting for low-level I/O to complete), but a large disk cache can help them tremendously. In addition, Windows 9X bypasses DOS and BIOS I/O code entirely, and uses much more efficient protected-mode code instead. Experience shows that DJGPP programs on plain DOS systems with a large (8MB and up) disk cache installed run about 30% slower than a Linux system on the same machine; and Windows 9X will run the same programs at roughly the same speed as Linux. If you get much slower performance on DOS/Windows, chances are that your system is not configured optimally.
Some programs which only copy data between two files might gain significantly if you write your custom low-level I/O functions that avoid moving data to extended memory (only to move them back to the transfer buffer). However, these cases are rare.
You can tell how much your program switches to real mode by profiling your program. In the profile, look at the proportion of time your program spends in low-level library functions called
__dpmi_int
(which calls real-mode DOS/BIOS services) and __dj_movedata
(which moves data between the transfer buffer and your program). If this proportion is large, try
rewriting your program to minimize use of those functions which require a mode switch, even at a price of more computation (a mode switch usually eats up hundreds of CPU cycles).
__djgpp_exception_processor
is high on
the execution profile printed by Gprof. Due to the way FP emulation is implemented in DJGPP(Note: Without a real x87 FPU, an exception is generated by the CPU each time a
floating-point instruction is seen in the code. __djgpp_exception_processor
is called for each such exception and services it by calling the emulator, emu387.dxe, or
functions from the emulator library libemu.a (if the program was linked with -lemu), to emulate the instruction. Since exception processing incurs a lot of overhead, this
emulation is slow.), it might be significantly slower than the way real-mode DOS compilers handle it. The solution is either to rewrite your code so that it doesn't use floating-point code in
its inner loops, or buy an FPU.
| Previous | Next | Up | Top |
malloc(50*1024*1024)
some day. With other DPMI hosts, your mileage may vary. Quarterdeck's QDPMI, for instance, has a bug in some of its versions which effectively disables virtual memory under DJGPP (described in QDPMI VM bug, below), so you only have whatever free physical RAM is left. Under Windows 3.X, the amount of virtual memory you get depends on various virtual memory settings in the Control Panel and on the .pif file settings for the program you run (see Windows allocation subtleties, below). Under Windows 9X, the memory settings of the DOS Box Property Sheets define how much virtual memory a DJGPP program will get (see Windows 9X allocation details, below). OS/2 reportedly can be configured to support up to 512MB of DPMI memory.
| Previous | Next | Up | Top |
malloc
/free
don't affect virtual memory...
malloc(50*1024*1024)
, but didn't see any paging happen, and I only have 8 MBytes of RAM on my machine. Is this virtual memory thing for real?
Q: I malloc
'ed a large chunk of memory, but when I check values returned by _go32_remaining_physical_memory
or
__dpmi_get_memory_information
, I don't see any change!
Q: When I free
allocated RAM, _go32_remaining_physical_memory
reports there was no change in the available RAM...
Q: I'm looking for a way to tell how much memory is available, something like coreleft
in Borland C?
malloc
it, but don't actually access it, it won't grab
those pages. Try calloc
and see the big difference.
When you call free
, DJGPP library doesn't return memory to the system, it just adds it to its internal pool of free pages. So, from the system point of view, these pages are not "free".
In addition, several widely-used DPMI servers, such as those built into Windows, have their own quirks related to memory allocation. For example, some of them won't let you allocate more than half
the available memory in a single chunk. As another example, under OS/2 _go32_remaining_physical_memory
reports a constant very big value that doesn't change in the course of the program.
Because of these peculiarities, there's no convenient and easy way to return the amount of free memory available at any given moment. Some programs only care about available physical RAM (they don't
want to page to disk, since that causes a considerable slow-down); for these, I recommend to call the _go32_remaining_physical_memory
library function at program startup, and then track
memory usage with sbrk(0);
. Alternatively, disabling virtual memory altogether (by using CWSDPR0 or by loading CWSDPMI with -s- parameter), and checking values returned by
malloc
against NULL
, might be all you need to know when you are about to run out of free physical memory. Programs that need to know when they are about to run out of
virtual memory should call _go32_remaining_virtual_memory
instead.
| Previous | Next | Up | Top |
malloc
returns a NULL
pointer, or I get some cryptic error message, like "Memory Paging
Violation" or "Unrecoverable Exception: 000Eh".
This bug was corrected in QDPMI version 1.10 or later, distributed with QEMM beginning with version 8.0, so upgrading to the latest version of QEMM might also be a solution. With QEMM 6.x, make sure
your programs don't override the default type of sbrk
behavior by setting _crt0_startup_flags
to _CRT0_FLAG_UNIX_SBRK
(QEMM 8.0 and later can allocate virtual
memory with both types of sbrk
algorithm).
If you use another DPMI host, make sure that virtual memory is enabled. E.g., for 386Max, include the swapfile= parameter to establish a virtual memory swap file; you can make it permanent (this will speed up DJGPP start-up) with the /p option.
| Previous | Next | Up | Top |
NULL
pointer from malloc/calloc
! Q: Why is my program dying with SIGSEGV under CWSDPMI when allocating a chunk of memory?
With some DPMI providers, this behavior might be triggered by a small overhead of each malloc
call: you might ask for half of available memory, but the DJGPP implementation of
malloc
adds the overhead and then rounds the amount of memory to the next power of 2 before calling sbrk
; thus malloc(8MB)
will actually request 16MBytes from
the DPMI host. When in doubt, call sbrk
directly, especially if you don't plan to free that memory during execution.
If your program asks for memory in lots of small allocations, then it might crash when you use CWSDPMI as your DPMI host. This is because CWSDPMI runs out of its tables, allocated in the heap, where it tracks memory allocations. Beginning with release 2, CWSDPMI defines a 6KB-large default heap that is configurable by CWSPARAM program to be anywhere between 3K and 40K bytes, without recompiling CWSDPMI. The default heap size is enough for about 21MBytes in small chunks. You should upgrade to the latest CWSDPMI if you experience such problems, and bump up its heap size as needed.
| Previous | Next | Up | Top |
PageOverCommit=nin the [386Enh] section of your SYSTEM.INI file. The parameter n is 4 by default, but can be set to be as large as 20.
| Previous | Next | Up | Top |
If you have more than 64MB of physical memory installed, you can specify the amount of memory on the EMM386
command line in your CONFIG.SYS, like this:
DEVICE=C:\WINDOWS\EMM386.EXE NOEMS L=131072I'm told that this line (here for 128MB of installed memory) together with an "Auto" setting of the DPMI memory for the DOS box allows DJGPP programs to use up to 117MB of memory when running from the DOS box under Windows 9X.
Note that you cannot allocate more than half the available memory in one chunk under Windows 9X, exactly as the things are under Windows3.X, and you cannot have more than 64 MBytes of virtual memory available to DJGPP programs running on Windows, unless you have more than 64MB physical memory installed.
| Previous | Next | Up | Top |
Q: I have 5 MBytes of free RAM on my machine, but DJGPP programs start paging after only 256KBytes of memory were used??
If your programs start paging after only 256KBytes of memory were used, most probably you are using EMM386 and CWSDPMI, and your CONFIG.SYS specifies no amount of memory when it installs EMM386. Some versions of EMM386 default to 256K in this case; you should tell EMM386 explicitly how much memory it should take over. You can use the go32-v2 program to see what amount of extended memory your DJGPP programs will get.
| Previous | Next | Up | Top |
system
library function?
system
(like in recursive invocation of Make) eats up about 18K (16K for the transfer buffer and 2K for the PSP and environment) for most DPMI servers; a
notable exception is QDPMI which needs 97K bytes of low memory for the subsequent calls too. If you change the size of the transfer buffer (with STUBEDIT
), the amount of free
conventional RAM left when shelling out of it will change accordingly.
Extended memory management is left to the DPMI server; DJGPP does nothing special about XMS when system
is called. This means that all the extended memory used by the parent program is
not freed when the child program starts; if the child requests more memory than is physically free, the DPMI server is expected to page some of the parent out to honor the request.
(This is unlike DJGPP v1.x, where the go32
extender would completely page out the parent before starting the child.) The advantage of this is that spawning a child or shelling out is
much faster in v2 than it used to be with v1.x, except on machines with low amounts of installed RAM. A disadvantage is that if you spawn a real-mode program that uses XMS, the extended memory used
up by your DJGPP program will be unavailable to it, unless you use a memory manager (as opposed to when CWSDPMI uses raw XMS or HIMEM). The only way around this problem is to buy more RAM, or to
install a real memory manager.
Note that if you use a memory manager such as EMM386 or QEMM386 with the NOEMS and NOVCPI parameters, CWSDPMI will use the XMS (as opposed to VCPI) services to allocate extended memory, and will allocate all of the available XMS memory for itself. So if, while your DJGPP program runs, some resident software such as device driver or TSR will try to allocate XMS, the allocation will fail.
Q: How much stack space do I have in my program?
Q: My program seems to overflow the stack, but only when I run it under a debugger...
Q: My program crashes with SIGSEGV, but the traceback makes no sense: it points to something called ___djgpp_exception_table... When I try to debug this, the traceback mysteriously changes to some innocent library function, like getc(). The same program works flawlessly when compiled with DJGPP v1.x What is going on??
_stklen
in your program. Example:
unsigned _stklen = 1048576; /* need a 1MB stack */The DJGPP startup code checks both the value in the stub info and the value of
_stklen
, and uses the larger of these two. Therefore, programs that are known to require large stack size
should set _stklen
to make sure they will always work, even if somebody stub-edits them to a lower value. This technique is also safer when you need to debug your program with
gdb
(see below). However, you might need to use STUBEDIT with programs for which you don't have the sources.
Programs which need an unusually large stack might crash with bogus stack traces, because part of the heap gets overwritten by the overflowing stack. To see if that is the cause of such crashes, run
STUBEDIT on your program and crank up the stack size to a large value (like 4MBytes). If that makes the problem go away, tune the stack limit to the minimum value your program can live
with, then set _stklen
to an appropriate value as explained above and recompile the program. (Some DPMI hosts will actually allocate the entire stack, even if not all of it is used, so
leaving it at unnecessarily large value will hurt the program on low-memory machines.)
Some users have reported that they needed to enlarge the stack size of the C++ compiler, cc1plus.exe, to prevent it from crashing when compiling some exceedingly large and complex C++ programs. Another program that was reported to need a stack larger than the default is bccbgi.exe from the BCC2GRX package.
After you've used STUBEDIT to change the stack size, run it again to make sure it displays as default the value you thought you entered. This is because STUBEDIT will sometimes silently set the stack size to 0 (and then you will get the default 256K stack) if it doesn't like the value you type (e.g. if it has a wrong syntax).
When you run a program under a debugger, the stack size field in the stub info is ignored, so the only way to change the default stack size is to set _stklen
.
Under Windows 3.X, be sure you've allocated a sufficiently large swap file (let's say, 40MBytes) from the Windows' Control Panel, and make sure the .PIF file for your program doesn't have too low limit on EMS/XMS usage (better make them both -1). What's that? You don't have a .PIF file for this program? Then Windows uses the default file DOSPRMPT.PIF, which almost surely defines very low limits on these two, and your program might have problems getting the memory it needs for its stack.
DJGPP v2.0 has a subtle bug in its startup code that is seen very rarely, and that manifests itself by a program crashing with Page Fault or SIGSEGV. If you are using v2.0 and enlarging the stack and the CWSDPMI heap size didn't help, try adding some (e.g., 4KB) static data to your program and see if that helps. But the best way to overcome this is to upgrade to DJGPP v2.01 or later.
| Previous | Next | Up | Top |
Q: I call my program with an argument x*y and it complains about something called xyzzy??...
Q: I cannot find a way to use the /? switch with my programs!
main
function is called. Unlike other DOS-based compilers, where you must link your
program with a special object module if you want the program to get expanded filenames, in DJGPP this is considered normal behavior and performed by default on behalf of every DJGPP program. The
x*y above was expanded to a file called xyzzy which was probably present in the current working directory; and /? is by default expanded to the list of
one-letter files/directories you happen to have in the root directory of the current drive. (If you don't want the default expansion, see how to disable globbing.)
In DJGPP, filename globbing works like in Unix, which is more general than the usual DOS wildcard expansion. It understands the following constructs with special meta-characters:
Note that *.* only picks up files that actually have an extension. This is contrary to the usual DOS practice where it means all the files, with or without extension.
An argument which cannot be expanded (no filenames matching that particular pattern) will be passed to the program verbatim. This is different from what you might see under Unix, where some shells (like csh) would say something like "No match" and won't call your program at all. DJGPP's behavior in this case is like shells of the Bourne legacy (sh, ksh, and bash).
If the wildcards include upper-case or mixed upper- and lower-case letters, the letter-case of the files is not ignored on Windows 9X when expanding the wildcards. For example, [A-D]*
will not match a file called aFileName. Upper-case letters in wildcards also disable automatic down-casing of short 8+3 file names returned by the code that expand
wildcards (even on plain DOS). If the wildcards include only lower-case letters, the letter-case is ignored during expansion, and short 8+3 file names are automatically down-cased, unless the
environment variable FNCASE
is set to y. The effect of setting FNCASE
is fully described in the DJGPP C Library reference, under the
_preserve_fncase
function; type info libc alpha _preserve_fncase from the DOS prompt.
| Previous | Next | Up | Top |
__crt0_glob_function
and make it always return a NULL
pointer. See the documentation of this function in the library reference, for more details. Here's an example:
char **__crt0_glob_function (char *arg) { return 0; }
| Previous | Next | Up | Top |
Q: How do I pass a command-line argument which contains double quotes?
Q: How do I pass an argument which begins with the @ character?
main
function (see
description of filename expansion), and the quote characters serve to protect the arguments from expansion. You should escape-protect the quote characters with a
backslash in order for them to be treated as literal characters. For example, if you have a file called myfile.c'v, type it as myfile.c\'v when you call your program. If
you have single quotes in your program arguments and you don't want those arguments to be expanded, then surround them by double quotes, like this: "*.c'v". The program will
get the string *.c'v with the double quotes stripped away. Note that backslashes are only special if they are in front of a quote, whitespace, or backslash (they also serve as DOS directory separators, remember?). This is also different from what you get under a Unix shell.
The @ character serves to signal a response file (see the description of response file method), so it's also special. To pass an argument whose first character is @, surround that argument with single or double quotes, otherwise it will be taken as a name of a response file which holds the actual command line.
Note that you can quote parts of the wildcard to protect only those parts from expansion; the unquoted parts will still be expanded. This allows to use wildcards with embedded whitespace and expand file names with special characters which need to be quoted, like in c:/Prog*' 'F* (which should expand into c:/Program Files) and *.c"'"v (which should expand into all files with the *.c'v extension).
| Previous | Next | Up | Top |
Q: I have a Makefile of Unix origin which contains some very long command lines. Will it work with DJGPP?
This method is suitable only for invoking DJGPP programs from other DJGPP programs. You don't have to do anything special to use this method, it is all done automagically for you by the library
functions like system
, spawnXX
and execXX
on the parent program side, and by the start-up code on the child side(Note: In case you wonder, the name
!proxy comes from the string which identifies the use of this method: instead of getting the actual command line, the program gets !proxy followed by the address of the
actual command line.).
system
library functions should be globbed by the
child, while the arguments passed by spawnXX
and execXX
family of functions should not; thus the former uses the environment method while the latter use the
!proxy method.
Note that this method makes @ special when it is the first (or the only) character of a command-line argument, which should be escape-protected if you want to use it verbatim (see how to pass the @ character).
Since the long command lines are a very important feature, DJGPP's version of the system
library function avoids calling the DOS command processor, COMMAND.COM, unless it
needs to run a batch file or an internal command of COMMAND.COM. Other features of the command processor, like redirection and pipes, are emulated internally by system
.
See the library reference for system
, for more details about its extended functionality.
| Previous | Next | Up | Top |
The above limit depends on the size of the transfer buffer, so check the size of the value recorded in the stub header of the parent program before you pass extremely long command lines to its children. GCC is the first program you should worry about, because the linker (ld.exe) usually gets long command lines from GCC (they include the list of all the object files and libraries to be linked).
Q: I use RHIDE, but it only passes the first 126 characters of my long command lines to the compiler!
SHELL = command.com
statements, or for commands which include pipe or redirection characters like >,
|, etc. If Make sees any such statements, it will invoke COMMAND.COM to run GCC, and COMMAND.COM can't pass more than 126 characters to GCC. To work around,
comment-out the SHELL=
line, and change your commands to work without redirection/pipe characters. One easy way to get rid of redirection characters without losing their effect is to
use the redir program which comes with DJGPP. For example, the following command:
frobnicate foo.bar > myfile.tmpcan be re-written instead like this:
redir -o myfile.tmp frobnicate foo.barThe ports of Make 3.75 and later doesn't call COMMAND.COM in the above cases, but rather emulates pipes and redirection internally, so upgrading to the latest version of Make will solve such problems. If you think about using Make 3.75 with DJGPP v2.0, don't: invoking v2.0 programs from v2.01 programs will cause subtle and hard-to-debug problems due to incompatibilities between these two versions regarding the methods of invoking child programs (in particular, v2.0 doesn't support the environment method of passing long command lines described above).
Problems with passing long commands from RHIDE are usually caused by invoking old programs compiled with DJGPP v2.0. Upgrade to the latest binaries.
| Previous | Next | Up | Top |
$
; Intel immediate operands are undelimited (Intel push 4
is AT&T pushl $4
).
%
; Intel register operands are undelimited. AT&T absolute (as opposed to PC-relative) jump
/call
operands are
prefixed by *
; they are undelimited in Intel syntax.
add eax, 4
is addl $4, %eax
in AT&T syntax.
The source, dest
convention is maintained for compatibility with previous Unix assemblers, so that GCC won't care about the assembler with which it is configured, as some of GCC
installations (on systems other than MS-DOS) don't use GNU Binutils.
b
, w
, and l
specify byte (8-bit),
word (16-bit), and long (32-bit) memory references. Intel syntax accomplishes this by prefixing memory operands (not the opcodes themselves) with `byte ptr'
, `word
ptr'
, and `dword ptr'.
Thus, Intel mov al, byte ptr FOO
is movb FOO, %al
in AT&T syntax.
lcall/ljmp $SECTION, $OFFSET
in AT&T syntax; the Intel syntax is call/jmp far SECTION:OFFSET.
Also, the far return instruction
is lret $STACK-ADJUST
in AT&T syntax; Intel syntax is ret far STACK-ADJUST.
SECTION:[BASE + INDEX*SCALE + DISP]is translated into the AT&T syntax
SECTION:DISP(BASE, INDEX, SCALE)
Intel: [ebp - 4] AT&T: -4(%ebp) Intel: [foo + eax*4] AT&T: foo(,%eax,4) Intel: [foo] AT&T: foo(,1) Intel: gs:foo AT&T: %gs:fooFor a complete description of the differences, see the "i386-Dependent" section of the "GNU assembler documentation". If you don't read this FAQ with an Info browser, download GNU Binutils, unzip the files named as.iN (where N is a digit) from it, then type at the DOS prompt:
info as machine i386You will see a menu of Gas features specific to x86 architecture.
A guide is available which was written by Brennan Underwood; it describes how to use inline assembly programming with DJGPP and includes a tutorial on the AT&T assembly syntax. Check out the DJGPP inline assembly tutorial. Another useful tutorial about writing separate assembly-language modules for DJGPP was written by George Foot and is available from George's home page. The DJGPP User's Guide also has a tutorial on writing assembly-language code. Many people who used Intel syntax and then converted to the AT&T style say that they like the AT&T variant more. However, if you prefer to stick with the Intel syntax, download and install NASM, which is a free portable assembler. It is compatible with DJGPP and accepts a syntax which is much more similar to the Intel style. A guide for using NASM with DJGPP was written by Matthew Mastracci and is available from Matthew's Web page.
| Previous | Next | Up | Top |
Q: Where can I find a converter from AT&T assembly to Intel style?
Alternatively, here is what you can do to make your code linkable with DJGPP programs:
Be warned that NASM is not 100% identical to MASM or TASM. Even experienced assembly programmers might need some time to adapt to the slightly different flavor of NASM. If you want something much more similar to TASM, get JAS. JAS is available from OULU.
Keep in mind that syntax is only one of the aspects of converting code written for DOS to DJGPP. You should also make sure your code doesn't violate any of the rules for protected-mode programming (see next question).
If you need to perform the opposite conversion, from the AT&T style to the Intel style, try the Att2Intl converter written by Greg Velichansky. Its output is intended for NASM or TASM. Att2Intl is available from Greg's home page.
| Previous | Next | Up | Top |
Here is a short list of some of the techniques found in many real-mode programs, which will trigger protection violation or erratic behavior in protected mode:
INT NN
instruction.
| Previous | Next | Up | Top |
Q: How come my program crashes with a GPF, but only if I compile it with -O2?
| Previous | Next | Up | Top |
Q: I have this ACMELUXE.LIB library of functions which I want to use. I've extracted all the .obj files, but when I try to link them with my program, GCC complains: "File format not recognized". Can't I use these object files?
Q: I've got a bunch of .obj files I want to use. I've ran AR to make a GCC-style .a object library, but got an error message from GCC saying "couldn't read symbols: No symbols". How can I link them with my code?
However, if you are really desperate, one conversion tool you might try is OBJ2BFD. It was written by Robert Hoehne based on the EMXAOUT utility from the emx/gcc package. OBJ2BFD requires the .obj files to be written for the flat-address memory model and will reportedly complain if you feed it with code written for segmented memory models. OBJ2BFD is available from the DJGPP sites.
Another automated conversion tool called OBJ2COFF was written by the SPiRiT team, and it can be used to convert .obj object files and .lib libraries to COFF format, provided that the original .obj files have been written for flat-address memory model.
OBJ2COFF is available via anonymous FTP transfer from the Oulu MSDOS repository. If you have any problems with it or questions about it, send them to its author Rico or to George van Venrooij. Note that the authors of OBJ2COFF have explicitly prohibited commercial use, so you shouldn't use OBJ2COFF for converting commercial object files.
You can also try using LIB32 librarian from Microsoft C8 to convert object files to COFF.
The main problem with these conversion methods is, of course, that most object files you'd want to converted were written for real-mode programs in memory models other than flat, and without extensive modifications would crash your program anyway... (See previous question.)
| Previous | Next | Up | Top |
spawnXX
function call. On the DJGPP side, you can directly call 16-bit functions from the real-mode program using the library function called
__dpmi_simulate_real_mode_procedure_retf
, provided the 16-bit program passes the CS:IP values of these functions to the 32-bit program. You can even put your 16-bit code as binary
instructions into a buffer allocated in low memory and call it with __dpmi_simulate_real_mode_procedure_retf
(but if you can do that, you can probably also disassemble the code into a
source form and submit it to Gas). Now will you consider sticking with DJGPP? Please??...
| Previous | Next | Up | Top |
Q: A program written for a 16-bit compiler uses the MK_FP or _MK_FP macro, but DJGPP doesn't seem to have it. How should I port it?
Q: How do I compute a segment and an offset of a protected-mode address?
#define far #define near #define huge #define _far #define _near #define _hugeAlternatively, you could add suitable
-D
switches to the GCC command line, like this:
gcc -Dfar= -Dnear= -Dhuge= -c myprog.cMacros that create far pointers from the segment and offset (usually called
MK_FP
or _MK_FP
) are mostly used in 16-bit code to access certain absolute addresses on
memory-mapped peripheral devices, like the video RAM. These chores are done differently in DJGPP. Here's one possible way to express MK_FP
in DJGPP (courtesy of
Charles Sandmann):
#include <sys/nearptr.h> #include <crt0.h> void * MK_FP (unsigned short seg, unsigned short ofs) { if ( !(_crt0_startup_flags & _CRT0_FLAG_NEARPTR) ) if (!__djgpp_nearptr_enable ()) return (void *)0; return (void *) (seg*16 + ofs + __djgpp_conventional_base); }The above uses the DJGPP nearptr facility; if you prefer to use farptr functions (which are safer and work with all known DPMI hosts), you will need to rewrite the code that uses these macros, so don't bother writing a replacement for the macro itself. The details are described in Accessing absolute addresses, below.
Macros that extract the segment and the offset from a far pointer (called FP_SEG
and FP_OFF
) are required in 16-bit code to pass addresses in registers when calling
real-mode DOS or BIOS services, like functions of interrupt 21h. See How to call real-mode interrupt functions, which describes how that should be done in DJGPP; here,
too, you won't need to port the macros but instead rewrite the code that calls the DOS or BIOS service. In particular, you cannot compute a real-mode segment and offset of a
protected-mode address, because real-mode addresses can only access the first 1MB of memory, whereas the variables of DJGPP programs all live above the 1MB mark.
To port such code to DJGPP, use the fields of the __dpmi_regs
structure (declared on the dpmi.h header file) to set the register values, and library function
__dpmi_int
to invoke the interrupt service. For example, consider the following code snippet:
#include <dos.h> void _highcolor (void) { _AH = 0x10; _AL = 0x03; _BL = 0; geninterrupt (0x10); }Here's one way to express this in DJGPP(Note: This function calls the video BIOS interrupt 10h to allow bright background colors to be used instead of blinking characters. DJGPP has a library function, called
intensevideo
, to do that, but let's assume we have reasons not to use it.):
#include <dpmi.h> void _highcolor (void) { __dpmi_regs r; r.h.ah = 0x10; r.h.al = 0x03; r.h.bl = 0; __dpmi_int (0x10, &r); }Please read how to call real-mode interrupt functions, elsewhere in this document, for further details on how call real-mode services from DJGPP programs.
GCC features extensive inline assembly facilities which allow you to assign values to, or read values from registers from the inline assembly code. See description of inline assembly, for further info.
| Previous | Next | Up | Top |
int86
int86
or intdos
functions to invoke a software
interrupt?
int86
family of functions in the DJGPP library should
reissue the INT instruction after the mode switch. However, some services require pointers to memory buffers. Real-mode DOS/BIOS functions can only access buffers in conventional memory, so
int86
has to move data between your program and low memory to transparently support these services. But this means it should know about all these services to perform these chores
correctly, because each service has its own layout and size of the buffer(s). While int86
supports many of these services, it doesn't support all of them. The supported functions are
listed in the library reference. See the "int86" section of the "libc.a reference". For those it doesn't support, you
will have to call the __dpmi_int
library function instead. It is also documented in the library reference, see
the "__dpmi_int" section of the "libc.a reference". __dpmi_int
requires that you set up all the data as
required by the service you are calling, including moving the data to and from low memory (see how to use buffers with DOS/BIOS services).
Note that calling int86
and intdos
can sometimes cause trouble due to size (16 bits as opposed to 32 bits) of the members in the union REGS
structure. Do
not assume that e.g. regs.x.ax
is always 16 bit! This problem and the facilities available to specify the width of the registers are all described in the library reference; see
the "int86" section of the "libc.a reference".
In particular, programs which interface with the mouse via calls to the int86
library function, should mask off the high 16 bits of the registers which report mouse position and other
values, since the high 16 bits aren't necessarily zeroed (which will wreak havoc in any program that interfaces to the mouse).
| Previous | Next | Up | Top |
Q: I have some real-mode code that calls the segread
function. How can I make it work with DJGPP?
int86x
or intdosx
for a DOS or BIOS function supported by them, then just put the address of your buffer into the register which expects
the offset (regs.x.di
), forget about the segment, and call int86
or intdos
instead of int86x
and intdosx
. The DOS/BIOS functions
supported by int86
and intdos
are processed specially by the library, which will take care of the rest. Note that calling int86x
and intdosx
will
usually crash your program, since they expect that you pass them a real-mode segment:offset address to a buffer in conventional memory; this is done more easily with __dpmi_int
, see
below.
If you call __dpmi_int
, then you must put into that register pair an address of some buffer in conventional memory (in the first 1 MByte). If the size of that buffer doesn't
have to be larger than the size of transfer buffer used by DJGPP (at least 2KB, 16KB by default), then the easiest way is to use the transfer buffer. (Library functions don't assume the contents of
the transfer buffer to be preserved across function calls, so you can use it freely.) That buffer is used for all DOS/BIOS services supported by DJGPP, it resides in conventional memory, and is
allocated by the startup code. DJGPP makes the address and the size of the transfer buffer available for you in the _go32_info_block
external variable, which is documented the library
reference. Check the size of the buffer (usually, 16K bytes, but it can be made as small as 2KB), and if it suits you, use its linear address this way:
dpmi_regs.x.di = _go32_info_block.linear_address_of_transfer_buffer & 0x0f; dpmi_regs.x.es = _go32_info_block.linear_address_of_transfer_buffer >> 4;For your convenience, the header file go32.h defines a macro
__tb
which is an alias for _go32_info_block.linear_address_of_transfer_buffer.
Here's a simple example of calling a real-mode service. This function queries DOS about the country-specific information, by calling function 38h of the DOS Interrupt 21h, then returns the local
currency symbol as a C-style null-terminated string in malloc
ed storage. Note how the transfer buffer is used to retrieve the info: the address of the transfer buffer is passed to DOS,
so it stores the data there, and the function then retrieves part of that data using dosmemget
.
#include <sys/types.h> #include <sys/movedata.h> #include <dpmi.h> #include <go32.h> char * local_currency (void) { __dpmi_regs regs; regs.x.ax = 0x3800; /* AH = 38h, AL = 00h */ regs.x.ds = __tb >> 4; /* transfer buffer address in DS:DX */ regs.x.dx = __tb & 0x0f; __dpmi_int (0x21, ®s); /* call DOS */ if (regs.x.flags & 1) /* is carry flag set? */ /* The call failed; use the default symbol. */ return strdup ("$"); else { /* The call succeeded. The local currency symbol is stored as an ASCIIZ string at offset 2 in the transfer buffer. */ char *p = (char *)malloc (2); if (p != 0) dosmemget (__tb + 2, 2, p); return p; } }If the size of the transfer buffer isn't enough, you will have to allocate your own buffer in conventional memory with a call to the
__dpmi_allocate_dos_memory
library function. It
returns to you the segment of the allocated block (the offset is zero). If you only need a small number of such buffers which can be allocated once, then you don't have to worry about freeing them:
they will be freed by DOS when your program calls exit.
For bullet-proof code, you should test the size of the transfer buffer at runtime and act accordingly. This is because its size can be changed by the STUBEDIT program without your knowledge (however, it can never be less than 2KB, the size of the stub, because memory used by the stub is reused for the transfer buffer).
The function segread
used by some real-mode compilers does not exist in DJGPP. It is used in real-mode code to store the values of the CS, DS,
SS, and ES registers into a struct SREGS
variable, when some service that needs one of these registers is called from code written for small and tiny
memory models. DJGPP has the functions _my_cs
, _my_ds
, and _my_ss
for that purpose (ES and DS always hold the same selector in
code produced by GCC from a C or C++ source, so you don't need a fourth function). However, these will not be useful if the original real-mode code used the segment registers to invoke
DOS/BIOS services. For these cases, you will need to rewrite the code so that it copies the data to/from the transfer buffer and passes its address via __dpmi_int
, as described above.
| Previous | Next | Up | Top |
__dpmi_simulate_real_mode_interrupt.
__dpmi_regs
structure before you call that function. Random values in these members can cause your program to
behave erratically. The members in point are .x.ss
, .x.sp
, and .x.flags
. When .x.ss
and .x.sp
are zeroed, the DPMI host will provide
a stack for the interrupt call. This stack is locked and is 4KB-long for any handling done in protected mode (such as real-mode callbacks), and at least 512 bytes in size for interrupts reflected
into real mode. This is usually enough, but sometimes you'll need to use your own, larger stack, e.g., if you expect interrupts to nest, or if your handler needs a lot of stack space(Note:
The DPMI spec indicates that you should not use the default stack if your procedure/interrupt handler uses more that 60 bytes, or 1/8 of the total stack space available by default.).
In these cases you should point .x.ss
and .x.sp
to a larger buffer which is in conventional memory (possibly part of the transfer buffer). If SS:SP isn't zero, it will be used as the address of the stack for the interrupt handler, so if it points to a random location, your program will most certainly crash. A non-zero FLAGS member can also make the processor do all kinds of weird things (e.g., imagine that the single-step or the debug bit is set!).
If you don't have any reason to set SS:SP to a user-defined stack, it's easier to call the __dpmi_int
library function, which zeroes out the stack pointer and the
FLAGS fields for you (and also doesn't force you to type long function names!).
| Previous | Next | Up | Top |
Q: How do I access my peripheral card which is memory-mapped to an address between 640K and 1M?
Q: How can I read or change a value of one of the variables in the BIOS data area?
Q: How can I peek at an address whose far pointer I get from an INT 21h call?
_dos_ds
macro (defined on the go32.h
header file). This selector has base address of 0 and a limit of 1MB+64KB, so you can use it to access any address in the conventional memory, including the UMBs, but the relatively large limit
allows a buggy program to overwrite portions of DOS memory(Note: DJGPP v2.01 makes the limit of _dos_ds
be 4GB, which effectively disables memory protection when you use that
selector. However, since no memory outside the first 1MB is properly mapped into your program's address space without additional DPMI calls, and the DPMI host is then free to put memory-mapped
devices, such as Weitek I/O space or the linear frame buffer of an SVGA, on any address it sees fit, that huge limit is an unjustified security hole. DJGPP v2.02 will really be limited by
1MB+64KB.). The advantage of _dos_ds
is obviously that you don't have to create it, and that it is good for accessing every region in the first MByte range.
_dos_ds
. For example, here's a code snippet to set up a
selector which provides access to 32KB of text-mode video memory at 0xB800:0000
, courtesy of Bill Currie(Note: If you want to
decipher the 8-byte structure that is passed to __dpmi_set_descriptor
in this example, read the documentation of the __dpmi_get_descriptor
library function in the library
reference. This structure is the descriptor maintained by the processor for each protected-mode segment, such as those loaded into the CS and DS registers.):
int TxtVRAMSetupSelector (void) { static char selectorData[8] = { 0xff, 0x7f, 0x00, 0x80, 0x0b, 0xf3, 0x40, 0x00 }; int screenSelector = __dpmi_allocate_ldt_descriptors (1); if (__dpmi_set_descriptor (screenSelector, selectorData) < 0) abort (); return screenSelector; }The advantages of this method are that (a) you can set up the selector limit such that it only covers the memory region that you need, thus protection of the rest of memory is retained; and (b) you may set the base address to point to the beginning of the specific memory region you need to access, so that you don't have to add the base address for every access, making the access faster.
__dpmi_segment_to_descriptor
which is a wrapper
around that DPMI service. It is easier to use than the __dpmi_set_descriptor
function above, since you don't have to mess with the 8-byte descriptor buffer, but it always defines a 64KB
limit by default. Here is an example of code which gets a selector to access 64KB of video RAM beginning at 0xA000:0000
:
short video = __dpmi_segment_to_descriptor(0xa000);Note that descriptors created by this function should never be modified or freed. For this reason, you should use this function sparingly. For instance, if your program needs to examine various real mode addresses using the same selector, you should allocate a descriptor and change the base using the
__dpmi_set_segment_base_address
library function instead of using
__dpmi_segment_to_descriptor
to allocate separate descriptor for each address.
header file. You should convert any real-mode
far pointer segment:offset pair into a linear address (i.e., segment*16 + offset), and use _dos_ds
or any other selector which allows access to conventional memory, like this:
unsigned char value = _farpeekb(_dos_ds, segment * 16 + offset);For access to memory-mapped devices for which you have allocated a dedicated descriptor, use the selector of that descriptor instead of
_dos_ds
in the above example, and use the offset
into the on-board device memory as the offset. For example, the following snippet writes a value of 3 to the 10th dword of the device:
long lword = 3; _farpokel (selector, 9, lword);Use
_farpeekw
to peek at 16-bit shorts and _farpeekl
to peek at 32-bit longs. If you need to access several (non-contiguous) values in a loop, use the corresponding
_farnspeekX
functions which allow you to set the selector only once, as opposed to passing it with every call (but be sure the loop doesn't call any function that itself sets the
selector; see the library reference for more details).
There is a corresponding set of _farpokeX
and _farnspokeX
functions to poke (change the values of) such memory locations.
These functions have an advantage of emitting inline assembly code when you compile with optimizations, so they are very fast. See the library reference Info file for further details about these functions.
dosmemget
and dosmemput
library functions. They also require you to convert the segment:offset pair into a
linear address, but they don't need the conventional memory selector, as they can only be used to access the conventional memory (they use _dos_ds
internally).
Note that some memory-mapped peripheral devices might require 16-bit word accesses to work properly, so if dosmemXXX
yields garbled results, try dosmemXXXw
or set up a loop
which calls "farptr" functions.
_dos_ds
(e.g., created by one of the methods explained above), use the movedata
library function. It requires that you pass
a selector and an offset for both the memory-mapped address and for the buffer in your program's address space. Use the _my_ds()
function (note that it's a function,
not a variable!) to get the selector of any variable in your program, and use the address of the variable (cast to an int
) as its "offset" or linear address. movedata
is
fast because it moves by 32-bit longs, but be careful with its use when moving data to and from peripheral cards: some of them only support 8- or 16-bit wide data path, so moving data 4 bytes at a
time won't gain you much, and might even get you in trouble with some buggy BIOSes. The functions movedatab
and movedataw
are provided for moving by bytes and by 16-bit
words, respectively.
For example, here is a code snippet that combines one of the methods for allocating a descriptor for video RAM access with a call to movedata
to move a buffer to the graphics screen:
short video = __dpmi_segment_to_descriptor(0xa000); movedata(_my_ds(), buffer, video, 0, 320*200);
| Previous | Next | Up | Top |
Here are some gotchas in this context:
__attribute__((packed))
, to prevent GCC from inserting gaps between some members to make them properly aligned for faster access (see
how gcc aligns structs). C programs can declare the entire struct with the packed attribute, but C++ programs will need to declare each member with it, see
__attribute__((packed)).
dosmemget
or one of the _farpeekX
family of functions in conjunction with the _dos_ds
selector, and
don't forget to compute the linear address as segment * 16 + offset
.
__dpmi_simulate_real_mode_procedure_retf
to call it (don't forget to zero out the .x.ss
and
.x.sp
members of the __dpmi_regs
structure!).
int
s, whereas in DJGPP, an int
is 32-bit wide. You need to change the declaration of all struct members from int
to
short
, and from unsigned
to unsigned short
.
struct ncb { unsigned ncb_command; int ncb_status; char far *ncb_buffer; /* a far pointer to a buffer */ char ncb_name[32]; int far (*ncb_dispatch)(); /* a pointer to a far function */ };should be converted to this in a DJGPP program:
struct ncb { unsigned short ncb_command __attribute__((packed)); short ncb_status __attribute__((packed)); unsigned short ncb_buf_offset __attribute__((packed)); unsigned short ncb_buf_segment __attribute__((packed)); char ncb_name[32] __attribute__((packed)); unsigned short ncb_dispatch_offset __attribute__((packed)); unsigned short ncb_dispatch_segment __attribute__((packed)); };
| Previous | Next | Up | Top |
Surgeon General's WARNING: The description below uses the "Fat DS hack", a steroid derivative which gives your program great strength, a thick neck, baldness, and is known to be closely linked with the Alzheimer's disease.
In addition to the above warning, experience shows that many programs which use the safer "farptr" functions do not sacrifice performance. So, with the exception of a small number of programs, "nearptr" is really a convenience trick: it allows you to treat memory-mapped devices with usual C pointers, rather than with function calls. Therefore, I would generally advise against using "nearptr" unless your program absolutely needs the last percent of speed.
Having said that, here is the trick: you change the limit of the segment descriptor stored in DS to 0xffffffff
(i.e., -1), using library function
__djgpp_nearptr_enable
. After that, you have access to all the memory which is currently mapped in. This works due to 32-bit wrap-around in the linear address space to access memory
at, say, linear address 0xa0000 (which belongs to the VGA), or any other address on your memory-mapped device, by adding the value of the global variable __djgpp_conventional_base
to the
target address. __djgpp_conventional_base
is the negated base address of the DS selector that you program is using to access its data. By adding the value of
__djgpp_conventional_base
, you effectively subtract the DS base address, which makes the result zero-based, exactly what you need to access absolute addresses.
You should know up front that this trick won't work with every DPMI host. Linux's DOSEmu and Windows/NT won't allow you to set such a huge limit on the memory segment, because these operating
systems take memory protection seriously; in these cases __djgpp_nearptr_enable
will return zero--a sign of a failure. CWSDPMI, QDPMI, Windows 3.X and Windows 9X all allow this
technique (OS/2 Warp seems to allow it too, at least as of version 8.200), but some events break this scheme even for those DPMI hosts which will allow it. A call to malloc
or any other
library function which calls sbrk
might sometimes change the base address of the DS selector and break this method unless the base address is recomputed after
sbrk
call. (The "nearptr" functions support this recomputation by providing you with the __djgpp_conventional_base
variable, but it is your responsibility to
recompute the pointers using it.) The same change can happen when you call system
, and as a result of some other events external to the executing code thread, like multitasking or
debugger execution.
You should also know that the __djgpp_nearptr_enable
function in DJGPP v2.0 didn't verify that the limit was properly set. So if the DPMI server would fail the call
silently, the function won't detect it and will not return a failure indication. DJGPP v2.01 corrects this omission by always verifying that the DPMI host has honored the request,
and returns a failure indication if it hasn't.
If you are aware of these limitations, and don't need your code to run under all DPMI hosts, it might be the fix to your problems.
Confused about how exactly should you go about using this technique in your program? Look at the docs of the "nearptr" functions, see the "__djgpp_nearptr_enable" section of the "libc.a reference".
Another possibility is to use the DPMI function 0x508
that can map any range of physical memory addresses into a block that you allocate. Note that this is a DPMI 1.0 functionality
which is not supported by most DPMI 0.9 hosts (CWSDPMI does support it). There is a helper function __djgpp_map_physical_memory
in the DJGPP C library that you can use
to call these services.
| Previous | Next | Up | Top |
__dpmi__XXX
wrappers in the DJGPP library. Here's a somewhat schematic example:
#include <dpmi.h> . . __dpmi_meminfo mi; int selector; . . /* Map the physical device address to linear memory. */ mi.address = physical_address; mi.size = physical_address_size; __dpmi_physical_address_mapping (&mi); /* Now mi.address holds the linear address. */ . . /* Allocate an LDT descriptor and set it up to span the entire device on-board memory. */ selector = __dpmi_allocate_ldt_descriptor (1); __dpmi_set_segment_base_address (selector, mi.address); __dpmi_set_segment_limit (selector, mi.size - 1);Note that the segment limit should be one less than the size. Also, segments over 1MB in length must be a multiple of 4KB, otherwise the DPMI server might fail the call, or silently change the limit. You can then use the functions from the sys/farptr.h header file to access that device. See accessing memory-mapped devices, for more details about accessing memory-mapped devices given their linear address.
| Previous | Next | Up | Top |
_go32_dpmi_allocate_real_mode_callback_retf
or the _go32_dpmi_allocate_real_mode_callback_iret
library function, as required by the real-mode service you want to hook, and
pass the `segment' and `offset' members it returns to the service you want (in the above example, Int 33h function 0Ch) by calling __dpmi_int.
Here's a code fragment that shows how to do
this(Note: If you are using this example in your program, don't forget to disable the handler at program's exit by calling the same function 0Ch of Int 33h with a zero mask in the CX
register, and then deallocate the callback by calling the _go32_dpmi_free_real_mode_callback
library function. Also, remember that all code and data touched by the handler must be
locked, otherwise it will crash under some DPMI servers, such as CWSDPMI.):
#include <dpmi.h> #include <go32.h> static __dpmi_regs callback_regs; static _go32_dpmi_seginfo callback_info; int install_mouse_handler (unsigned mask, void (*func)(__dpmi_regs *)) { __dpmi_regs r; callback_info.pm_offset = (long)func; if (_go32_dpmi_allocate_real_mode_callback_retf(&callback_info, &callback_regs)) return -1; /* failure */ r.x.ax = 0xc; r.x.cx = mask; r.x.es = callback_info.rm_segment; r.x.dx = callback_info.rm_offset; __dpmi_int (0x33, &r); return (r.x.flags & 1) ? -1 : 0; }The handler (
func
in the above example) will be called with a pointer to a __dpmi_regs
structure which is filled by values found in the CPU registers when the mouse driver
calls the handler. See the docs in the library reference Info file for further details about allocating wrapper functions.
| Previous | Next | Up | Top |
First, some background. Hardware interrupts can occur when the processor is either in real mode (like when your program calls some DOS service) or in protected mode. When your program runs under a DPMI host, hardware interrupts are caught by the DPMI host and passed to protected mode first; only if unhandled, they are then reflected to real mode. Therefore, in DPMI mode you can get away with installing only a protected-mode handler. However, if the interrupts happen at a high frequency (say, more than 10 KHz), then the overhead of the interrupt reflection from real to protected mode might be too painful, and you should consider installing a real-mode interrupt handler in addition to the protected-mode one. Such a real-mode handler will be called before the interrupt gets to the DPMI host, and handle the interrupt entirely in real mode, so it must be written in assembly and located in conventional memory (below the 1MB mark). If you need to hook an interrupt with both PM and RM handlers, you must hook the PM interrupt first, then the RM one (because hooking the PM interrupt modifies the RM one). Also, you should know that some DPMI hosts don't allow you to hook the RM interrupt (CWSDPMI does), and some call both handlers, no matter in what mode the interrupt arrived (CWSDPMI will only call one of them); the only way to be sure is to try.
To install a protected-mode interrupt handler, you do this:
__dpmi_get_protected_mode_interrupt_vector
and save the structure it returns (to restore the previous handler address before your program exits).
__dpmi_lock_linear_region
. Failure to lock memory
accessed during the interrupt handling will cause your program to crash. Alternatively, you could set the _CRT0_FLAG_LOCK_MEMORY
bit in the _crt0_startup_flags
variable, or
disable virtual memory by using CWSDPR0.
__dpmi_set_protected_mode_interrupt_vector
and pass it a pointer to a __dpmi_paddr
structure filled with the value returned by _my_cs()
in
the selector
field and the address of your function in the offset32
field.
_go32_dpmi_XXX
functions instead of the bare-bones API wrappers whose names start with __dpmi_.
Specifically:
_go32_dpmi_get_protected_mode_interrupt_vector.
This function puts the selector and offset of the specified interrupt vector into the pm_selector
and
pm_offset
fields of the structure pointed to by its second argument. This data should be saved and later passed to _go32_dpmi_set_protected_mode_interrupt_vector
to restore
the vector on exit.
_go32_dpmi_allocate_iret_wrapper,
passing it the address of your function in the pm_offset
field and the value returned by _my_cs()
in the
pm_selector
field. The pm_offset
field will get replaced with the address of the wrapper function which is a small assembler function that handles everything an interrupt
handler should do on entry and before exit (and what the code GCC generates for an ordinary C function doesn't include); the effect is similar to using the interrupt
or
_interrupt
keyword in some DOS-based compilers.
_go32_dpmi_chain_protected_mode_interrupt_vector.
This will set up a wrapper function which, when called, will call
your handler, then jump to the previous handler after your handler returns. Put the address of your handler into the pm_offset
field and the value of _my_cs
into the
pm_selector
field of the _go32_dpmi_seginfo
structure and pass a pointer to it to this function.
_go32_dpmi_set_protected_mode_interrupt_vector
with the address of the _go32_dpmi_seginfo
structure you got from either
_go32_dpmi_allocate_iret_wrapper
or _go32_dpmi_chain_protected_mode_interrupt_vector.
The problem with writing handlers in C as above is that the wrappers' code and data aren't locked, and in practice you can't lock all of memory the handler itself uses, either. Thus, this approach is
generally unsuitable for production-quality software and should be used only when the program is known not to page (i.e., only the physical memory is used). You might consider disabling virtual
memory to make sure your program doesn't page. To accomplish this, either set the _CRT0_FLAG_LOCK_MEMORY
bit in the _crt0_startup_flags
variable, or use CWSDPR0 or PMODE/DJ
as your DPMI host. In fact, using one of these methods is the recommended way of debugging the first versions of a program that hooks hardware interrupts; only after you are sure that your basic
machinery works should you move to testing it in a setup when paging might happen.
Note that _CRT0_FLAG_LOCK_MEMORY
is only recommended for small programs that run on a machine where enough physical memory is always available, because the startup code currently doesn't
test if memory is indeed locked, and if there's not enough physical memory installed to page in all of the memory your program needs, you can end up with unlocked or partially unlocked memory, which
will crash your program. If you want to make sure all memory is locked, use a DPMI server which disables paging.
To install a real-mode interrupt handler, you do this:
__dpmi_get_real_mode_interrupt_vector
and save the structure it returns (to restore the previous handler address before your program exits).
__dpmi_allocate_dos_memory
and put the code of your handler there with the dosmemput
function. (You could also call one of the
functions which allocate a real-mode call-back, but these will cause a mode switch on every interrupt, which you want to avoid; otherwise there is no point in installing a real-mode handler, right?)
__dpmi_allocate_dos_memory
returned into a __dpmi_raddr
structure (the lower 4 bits into offset16
field, the rest into
segment
field), then call __dpmi_set_real_mode_interrupt_vector.
The DPMI spec says that 3 software interrupts are special, in that they also get reflected to a protected-mode handler. These interrupts are: 1Ch (the timer tick interrupt), 23h (Keyboard Break interrupt), and 24h (Critical Error interrupt). This means that, to catch these interrupts, you need to install a protected-mode handler only. Unlike hardware interrupts, it doesn't make sense to install dual RM and PM handlers for these software interrupts. In particular, Windows will call both RM and PM handlers if you install both, so you effectively wind up handling the same interrupt twice.
For examples of installing and using hardware interrupt handlers, see the sources of the Allegro library, the sample code written by Bill Currie, the Sound Blaster interrupt-driven functions, the mkkbd package, and the libhw library, described under sample DJGPP packages. Alaric B. Williams has written a tutorial on interrupt handling.
The file src/libc/crt0/crt0.S in the DJGPP library sources, djlsrNNN.zip, is one example of the subtleties involved with installing a real-mode interrupt handler.
| Previous | Next | Up | Top |
_go32_...
functions, but now comes v2 which also has __dpmi_...
functions. Are there any differences between these two
varieties?
Q: Do I need to convert my old v1.x code to use the new __dpmi_...
functions?
__dpmi_...
functions are just bare-bones wrappers of the DPMI API calls (see DPMI Specification), generally unsuitable for use with handlers written in C,
whereas the old _go32_...
functions are intelligent helper routines which only make sense if your interrupt handlers are C functions. They save all the registers on the stack (to be
restored before return to caller), and set up DS, SS, and ES registers as GCC assumes in the code it produces for a C program. If these assumptions
are wrong, the C functions called by an interrupt handler will crash miserably.
The problem with the _go32_...
functions is that they don't lock all the code and data they (and your handlers) use, so they can crash on memory-tight machines and thus aren't suitable
for production-quality code. But they are certainly useful in the initial stages of writing and debugging code that hooks hardware interrupts, and for migrating existing v1.x code to v2. Some of
the old names were just #define
d to the new names where the functionality is identical.
The bottom line is that it shouldn't be necessary to convert your code for it to work at least as well as it did in v1.x; but if you want it to be more stable, you should rewrite your handlers in
assembly and use the new __dpmi_...
functions (see How to install a hardware interrupt handler).
| Previous | Next | Up | Top |
Q: From time to time my program crashes with a message "Page Fault in RMCB". What's that?
One cause of your problems might be that your interrupt handler or some memory location it uses get paged out because of the virtual memory mechanism, or because your program spawned a child program.
In that case, the interrupt might cause a call to a non-existent service routine, with the obvious results. You should lock all the memory pages that your handler accesses by calling the
__dpmi_lock_linear_region
library function. This also means in practice that you should write your handler in assembly, as described in how to set an
interrupt handler, above. You can disable virtual memory, or put _CRT0_FLAG_LOCK_MEMORY
into _crt0_startup_flags
to make sure nothing is paged out (but then your
program might not have enough memory to run, unless you run on memory-abundant systems).
When CWSDPMI detects that your handler accesses memory that is not locked, it aborts your program with a message saying "Page Fault in RMCB". This can happen even if your program installs a callback for some real-mode service, like the mouse callback, as well as if you install a hardware interrupt handler; in both of these cases you need to lock all the memory touched by your handler or by functions it calls. CWSDPMI aborts your program if your program attempts to page while an interrupt handler or a real-mode callback are active, because paging uses DOS file I/O. Since DOS is non-reentrant, if the hardware interrupt handler was called in a middle of another DOS call, paging could badly damage your hard disk(Note: Actually, it is possible to avoid reentrancy problems in interrupt-driven programs: programs known as TSRs (Terminate and Stay Resident) have been doing that for years. But doing so requires hooking and monitoring many DOS and BIOS interrupts, to know when it is safe to page. If CWSDPMI would use these techniques, it would take much more DOS memory to load and run. It would also need to be updated with every new DOS release, since some of the internal DOS structures it would need to track change their address and/or layout with new versions of DOS.). By refusing to page in these cases, CWSDPMI ensures the stability of your system and integrity of your files. You pay for that stability by having to lock all code and data touched by the handler.
Another problem might be that the hardware peripheral you use generates a lot of interrupts. Due to specifics of hardware interrupts handling in protected mode, there is a substantial overhead involved with reflection of interrupts between real and protected modes. For instance, on a 486DX/33 this reflection might consume up to 3000 clocks; on a 386SX/16, even a 1KHz clock might eat up 1/2 of available cycles. One user reported that a 120 MHz Pentium will be able to service up to 45-50K interrupts per second before exhausting its CPU resources, and a 486DX/50 is capable of about half that number. If your hardware fires too many interrupts, your CPU might not be able to keep up. A good rule of thumb is to consider 10KHz as the breaking point, if your program needs to do something non-trivial besides servicing interrupts. If you are beyond that interrupt rate, consider reducing the interrupt frequency, or move some of the processing done inside the interrupt handler to some other place. Use a ring-0 DPMI server such as CWSDPR0 or PMODE/DJ (of these two, the latter is the faster one) which don't swap interrupt stacks--this will reduce the overhead of the interrupt reflection to some degree. If your handler is written in C, write it in assembly and make sure it doesn't chain. And most important--make sure your program keeps the processor completely in protected mode while handling high-frequency interrupts: avoid unnecessary library calls, disk I/O, BIOS calls, and anything else that could generate a mode switch. For example, using BIOS services to wait a certain period of time while interrupts come in is clearly a bad idea. Preventing the program from paging (by installing enough physical RAM and using memory efficiently) will also help keeping the CPU in protected mode, since paging is done by calling DOS in real mode. By keeping your processor in protected mode as much as you can, you avoid the expensive mode switches when the interrupts are reflected to your PM handler.
If all that still doesn't help, install a real-mode handler.
Some losing memory managers, notably EMM386, were reported to induce a high interrupt handling overhead. In one case, a user reported an increase in the maximum interrupt rate his program could support from 2 KHz to 6 KHz after uninstalling EMM386.
Still another possibility is that you use a non-default sbrk
algorithm in your program. Check if the header file crt0.h is included anywhere in the program, and if so, if
the _CRT0_FLAG_UNIX_SBRK
bit in the _crt0_startup_flags
variable is set by the program. If it is, then a hardware interrupt which happens at the wrong time could crash your
machine, especially if you run under Windows 3.X.
You should also keep in mind that the DPMI server can decide to handle some of the interrupts itself and not pass them to your program, although this is rare. For example, Windows 9X won't pass the Ctrl-Alt-Del combination to your keyboard interrupt handler, but will rather act on it itself; QDPMI sometimes processes Ctrl-C keypresses so that your program never sees them, etc. Sometimes, but not always, you can change some configuration option to make some keys get to your handler (e.g., the Alt-TAB setting on the Windows3.X .PIF file).
If the above still doesn't explain your problem, then post your code on the DJGPP mailing list or the comp.os.msdos.djgpp news group, tell there how it fails and somebody will usually have a solution or a work-around for you.
| Previous | Next | Up | Top |
inp
and outp
functions. But I hear they aren't available in DJGPP?
#include <pc.h>
and you get their prototypes. The functions themselves are in the default library. Note that there are also
size-specific versions for byte- word- and dword-long access (e.g., inportl
for reading a 32-bit dword), as well as functions to read/write sequences of bytes and words, like
inportsb
and outportsw
; these are DJGPP-specific.
| Previous | Next | Up | Top |
Q: How can I reference C variables from my inline assembly code?
info gcc "C Extensions" "Extended Asm"(Note the quotes: they are important.) You will, of course, need that the stand-alone Info reader be installed on your system for the above command to work. If it is not already installed, get the file v2gnu/txi312b.zip from the DJGPP distribution and install it.
If you read this FAQ via WWW, you can also read about the GCC inline assembly extensions with your Web browser.
Brennan Underwood has written a tutorial on using inline assembly, which is another valuable resource on this issue.
Q: I want to use DMA, but I don't know how to get the physical address of the buffer I allocate for that purpose.
__dpmi_get_segment_base_address
library function and add it to the address of your buffer, but the resulting address is a logical address, translated into a physical address by the
memory-mapping unit which is part of the CPU. You have two alternatives to get the physical address of your buffer:
__dpmi_allocate_dos_memory
. This method has a disadvantage of using conventional memory which is at a premium, and is therefore generally ill-suited for large DMA buffers.
EMM386
or QEMM
, to run, since only memory managers and Windows support the VDS API. In other words, if you use VDS, your program
won't work on a system where CWSDPMI(Note: CWSDPMI has an experimental VDS support in its sources, but the distributed binary was compiled without it. Contact
Charles Sandmann if you want to try to enable VDS support in CWSDPMI.) is used as the DPMI server, allocating memory by raw XMS calls or via HIMEM.
| Previous | Next | Up | Top |
Q: Can I write commercial programs with DJGPP?
Using the GNU C/C++ compiler doesn't make your programs subject to any restrictions. The C library which comes with DJGPP is free (unless you change the library sources, see below), which means you are free to use the stock libc.a in any way you like (but please try to comply with basic rules of courtesy.)
Some functions from the DJGPP C library are under the BSD copyright (their sources were taken from the Berkeley Software Distribution of Unix). One of these functions is malloc
, which
is by default linked into every DJGPP program (the startup code calls it), the others are time-related functions such as time
, ctime
, and asctime
, and also
qsort
and random
. The BSD copyright requires that your binary distribution displays the following acknowledgment somewhere in the docs, and in all ads that mention the
features and/or use of your software:
This product includes software developed by the University of California, Berkeley and its contributors.So, if you write C programs and link them with the stock version of the DJGPP library, you only need to tell your recipients how to get the latest versions of DJGPP, mention the BSD blurb in your docs, and have absolutely nothing else to worry about.
The basic C++ iostream class library (libiostr.a) and the Standard Template Library (libstdcxx.a) which come with DJGPP allow you to use them binary-wise (i.e., without changing library sources) in your C++ programs without restrictions, unless you compile your programs with a compiler other than Gcc (which won't happen if you work with DJGPP). So C++ programs linked with -lstdcxx and/or -liostream switches are also free from any restrictions.
Only the library of additional GNU C++ classes (libgpp.a) requires that you provide your customers with source or object code of the application, so they could relink the application with future or modified versions of the C++ library. However, this library is deprecated and chances are most C++ programs won't use it. (If you intend to distribute commercial programs linked with the libgpp.a library, you are strongly advised to read the GNU Library General Public License which comes with the library, for rigorous definition of its terms.)
Two GNU packages, Flex and Bison, are also special in that using them to produce your programs doesn't place your programs under GPL or LGPL. In other words, lexers produced by Flex and parsers produced by Bison do not imply GPL/LGPL.
If you do use in your program any of the FSF sources that fall under GPL/LGPL (like some of the GCC's sources, or the GNU getopt or regex packages which come with many GNU programs), then you must comply with the terms of GNU licenses when distributing your programs; in this case your entire application becomes GPL. If that is unacceptable to you, consider using the versions of regex and getopt from the DJGPP C library (which are not as powerful, but are free from any restrictions).
You may ship any of the utilities developed specifically for DJGPP (e.g., the floating-point emulator emu387.dxe or the DPMI host cwsdpmi.exe) and the C library, as distributed by DJ Delorie, with your program with no other requirement besides telling your customers how to get DJGPP for themselves.
If you do change the sources of either the C library or the utilities distributed with the djdev package, they, and the programs developed with them, immediately fall under the GPL, the GNU License. In practice this means that you cannot distribute any binaries made with such a patched version of libc.a without offering the recipient full sources, including your own sources. However, if you find bugs in the library or the utilities and submit your patches to DJ Delorie, DJ allows to freely use and redistribute patched utilities and binaries made with the patched version of libc.a (even if no official DJGPP version was released with your patches yet).
For the precise legal terms of DJGPP distribution, see the file copying.dj via the Web (latest versions of the djdevNNN.zip package might also include it).
Note that the above says nothing about the legal aspects of contributed packages, like GRX and others; you will need to read their docs to find out.
Q: I run a business that sells shareware for distribution costs. Can I include djgpp on my CD-ROM?
Q: I want to include djgpp in a product that happens to need a compiler provided with it. Can I do this?
Q: Is DJGPP public domain software?
Q: Is DJGPP shareware?
Other parts of DJGPP, which include most of the C library, the free DPMI host CWSDPMI, and some of the utilities, are copyrighted, but in a way that allows you to use them freely and without restrictions. The copyright that covers these parts of DJGPP is GPL, the GNU License, but with a special exception: if you distribute the utilities unmodified, or build programs with the unmodified library, the GPL does not apply.
Compliance with GPL is therefore all you are legally required to consider when you redistribute DJGPP itself (as opposed to your programs compiled with DJGPP). However, based on many years of experience of DJGPP distribution, DJ Delorie requests vendors which distribute DJGPP to follow some additional rules. These rules are generally meant to provide a better service to the DJGPP user community:
In addition, it would be a courtesy to inform DJ that you are including DJGPP in your product, in case this information is obsolete. A token sample of your distribution would be nice also.
Note that the above are not legal restrictions (the latter are described in the file copying.dj mentioned in the previous section), they are recommended guidelines for redistributing DJGPP. These guidelines are based on many years of experience and are generally meant to make it easier for your clients to use DJGPP and get support from its developers. Vendors who do not follow these guidelines could risk public humiliation, verbal abuse, and boycott by the DJGPP community, but not legal action.
Note also that if you make source-level changes to DJGPP library or utilities, the changed software falls under the GNU License, GPL, unless these changes are made to fix bugs, and provided that you also submit all such bug-fixes to DJ Delorie for inclusion in a future DJGPP release.
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
The gateway works on DJ's server, and has a very strict anti-spam filter which prevents spam from getting into the news group; it also has an additional keyword-based ant-crap filter that doesn't pass spam to the mailing list. The entire traffic ends up in the mail archives on the DJ's Web server within 24 hours, and is available for searching.
If you have a Usenet feed, now is the time to consider unsubscribing from the mailing list and switch to reading the news group instead, so that the load on the list server will get lower.
| Previous | Next | Up | Top |
subscribeIf you only want to receive announcements of new versions and ported software, but don't want to see any other DJGPP mail traffic, subscribe to the djgpp-announce by sending message to the list server which says so:djgpp
subscribe djgpp-announce(Note: no email address when subscribing to the djgpp-announce list!) The announcements which go to djgpp-announce get reflected to djgpp, so you don't need to subscribe to both these lists.
The DJGPP mailing list is available in the daily and weekly digest forms. To subscribe to one of these, send this one-line message to the above list server:
subscribeordjgpp-digest-daily
subscribeSome mailers reject messages with too large size, so you might have trouble with the weekly digest. If you subscribe to it and don't get the digest, try the daily one instead, or switch to another mail software.djgpp-digest-weekly
You can also subscribe to DJGPP-related mailing lists through DJ Delorie's WWW server.
Note that you don't have to subscribe to the djgpp mailing list if you don't want to get all the traffic in your mailbox (typically, about 30 messages per day). You can ask questions on the list even if you are not a subscriber, because people usually answer both to your e-mail address and to the list (well, actually, the mailer program does it automatically and most people don't bother to change that). If you want to be sure the mail gets to you directly, say in your message that you don't subscribe to the list, and ask people to answer directly. Be sure to provide a valid return address (remove any anti-spam, if you use one).
Q: I've been trying for days to unsubscribe from the djgpp mailing list. What am I doing wrong?
unsubscribeWhen you unsubscribe, that stops new messages from being sent to you. Messages that are already in the mail queues of various mail programs between the DJGPP list server and the machine where you receive your mail--cannot be stopped. Therefore, allow some time before you decide that your unsubscribe message didn't work. In extreme cases, when one of the machines that are forwarding mail to you is down, you can get the messages up to 5 days after you've unsubscribed.djgpp
If you think you have waited enough and the messages still keep coming, write to listserv administrator and ask him to help you.
You can also unsubscribe yourself from any DJGPP-related mailing list through DJ Delorie's WWW server.
Recently, DJ has added a mail archive browser to his Web site. With this tool, you can list and read the messages by year, month and day, as well as search the last few days for something you might have missed. This service is available via World-Wide Web.
| Previous | Next | Up | Top |
If you want to help in further v2 development, check out the list of features which have yet to be done and volunteer to implement some of them.
| Previous | Next | Up | Top |
main
functions is called (the stub will also load CWSDPMI if no other DPMI host is detected). All the other custom code required to process BIOS- and
DOS-related calls from protected-mode is now built into the library functions which your program calls, so there is no need for a special extender, because the application just issues DPMI calls
serviced by the DPMI host. CWSDPMI can be loaded as a TSR, even loaded HIGH into the HMA/UMB, which will make applications load much faster.
| Previous | Next | Up | Top |
Q: I've been suffering from this bug for months on end! You know there's a bug, 'cause I told you so ages ago. So why in the world didn't you fix that in a new version??
You don't need to look for a large project to make your contribution. The best way to start being involved with DJGPP development is to fix any small and minor problems you see, right when and where you see them. Even bugs and inaccuracies in the DJGPP documentation, like the libc.inf Info file, are a good thing to begin with. DJ Delorie says that if everybody would correct every small bug they see, we would run out of bugs very fast.
When you submit a bug report or code that implements a new feature that you'd like to add to DJGPP, be prepared to withstand some scrutiny and peer review from the other participants of the DJGPP development team. You might hear various comments, from critique of your code and design decisions to questions why your changes are at all needed, and even requests to submit the changes in certain unified format (see instructions for submitting changes). Please be ready for that review process and don't take it as a rebuttal.
Q: I have heard rumors that there's a better C library for DJGPP available from the net. Where is it?
The single most important component of DJGPP tool-chain that might suffer from long release schedule is the djdev
package. This includes the C library, libc.a, which was
written specifically for DJGPP, and some DJGPP-specific development tools, like redir
and symify
. However, the latter are usually stable and don't need too much fixing.
A full release of djdev
is a lot of work, so DJ Delorie decided not to make interim releases (experience from v1.x development shows that such interim releases also generate confusion
and are hard to maintain).
In general, you are advised to constantly improve your C library by fixing any bugs in the library sources and replacing old modules with fixed ones. All this takes is to edit the relevant source file, compile it, and put it into the library. For example, assuming you have made a source-level change in a file called foo.c, here's how you update your library:
gcc -c -O2 foo.c ar rvs c:/djgpp/lib/libc.a foo.o(This example assumes that DJGPP is installed in the C:\DJGPP directory; if not, you will need to change the pathname of libc.a accordingly.)
Patching the library like that requires that you download the DJGPP library sources, djlsrNNN.zip (where NNN is the version number). That file includes sources to all the DJGPP functions and utilities, and you can extract them as the need to edit them arises.
Bug reports regarding the library and patches to fix them are posted from time to time to the comp.os.msdos.djgpp news group. In addition, the DJGPP
bug-tracking system, stores many known bugs and the patches required to solve them. You can use these resources to find solutions to known bugs.
Patches are applied using the patch
utility which is available from the DJGPP sites.
For those who don't want to mess with patching library sources, but still want their library to be as bug-free as possible, a few generous DJGPP users maintain a site where you can find those patches already applied for you and ready to be downloaded. The patched libc at that site includes bugfixes and improvements that were tested by experienced DJGPP users, so they are relatively safe. You can either download one or more individual patches and then put them into your library, or download the entire libc.a with all the patches. Every patch has a short description, in case you'd like to decide whether it's for you.
The patched library was created by Tom Demmer. Nate Eldredge is the current maintainer, and the space available for FTP is courtesy of A. Sinan Unur, on his server. The patched library is available via WWW and by ftp. Be sure to read the file ftp.message.txt when using the FTP server above. The file README explains how the patched library can be downloaded and used.
The above site also includes two additional versions of the C library: one compiled with the -g switch and the other compiled with the -pg switch to GCC. These are handy if you need to debug library functions and profile them, respectively.
| Previous | Next | Up | Top |
If you are installing DJGPP on Windows 9X, find an unzip program which supports long file names and unzip the files again. Make sure that the DJGPP long file names support (a.k.a. LFN) is enabled, otherwise DJGPP programs such as Make won't be able to invoke g++. To enable LFN support, set LFN=y in the environment.
| Previous | Next | Up | Top |
Q: How do I fix a bug/add a feature to one of the DJGPP programs?
Q: How should I produce patches for DJGPP programs I want to submit, and to whom should I submit them?
em1934s1.zip em1934s2.zip em1934s3.zip
All sources are shipped in ready-to-build form. Any diffs that come with the source distribution, like the files called DIFFS, have already been applied, and any configuration scripts and/or batch files have been run.
Next, try to build the program without changing it. Look for a file called README.dos or README.djgpp: it should explain the build procedure and list any optional packages you need to install for that.
If such a README file is unavailable, you will have to poke around and figure things out for yourself; here are some hints to help you out:
After you've successfully built the program, make your fixes and build the program the same way you did before.
Note that generally to build these programs, you must have the GNU Make program, installed, and some makefiles require that you install additional development utilities, like the SED editor. Sometimes the makefiles won't even run under COMMAND.COM (they require a smarter shell). In that case, either get a better shell, or convert the makefile to be runnable by COMMAND.COM, or do the required steps manually. If the Makefile is too complex for you and you can't figure out what are the necessary commands, invoke make with -n switch and see what it would have done.
If your machine lacks floating-point hardware (like a 386 without a 387, or a 486SX), then you should know that current versions of GNU Sed and GNU Make issue floating point instructions, so you will have to make provisions for loading an emulator, see above, FP Emulation. The port of Make 3.75 and later can be built so that it doesn't issue FP instructions, but you will have to get the sources and recompile Make first, as the stock version wasn't configured in that way.
If you think that you found a bug in one of the programs or libraries written for DJGPP (e.g. the C library, CWSDPMI, symify, etc.) be sure to check the list of known bugs. If your bug is not there, you can later submit it to the bug-tracking system.
Before you submit a bug report, please make every effort to verify that your bug is not caused by incorrect usage, or by problems in your DJGPP installation. Reports such as "All DJGPP programs crash" or "I cannot compile any program" are clearly not bugs, because these things work for many hundreds of DJGPP users every day; so either your system setup is messed up or you invoke programs incorrectly.
If you can investigate the cause of the bug and find a solution that makes it go away, submit a bug report with all the details. If you cannot find the cause(s), I suggest posting your problem description to the news group and asking people to verify that it is indeed a bug, before you submit a bug report. The bug-tracking system includes a list of all known bugs, many of them with solutions or work-arounds; please check them before creating a new bug report.
Patches to DJGPP programs and ports should be sent to the person who maintains the relevant package. Patches for the C library, utilities and other software which comes with the djdevNNN.zip distribution should be sent to DJ Delorie. If you don't know who maintains a particular package or port, post the patches to the comp.os.msdos.djgpp news group, since the maintainer is most probably reading that group.
To generate a patch, run the diff
program (from GNU Diffutils, v2gnu/dif271b.zip) on the old and the new version of a source file. For example:
diff -c src/libc/dos/dos/int86.old src/libc/dos/dos/int86.c >int86.difThe file int86.dif created this way should be sent to the maintainer, with a short description of the problem it solves. It is a good idea to run the patch file through DTOU (a utility which comes with DJGPP and converts DOS-style CR-LF pairs into Unix-style newlines), since this makes the patch work on Unix as well, in case the maintainer of the package in question does that on Unix.
Observing the following guidelines when creating the patch will make your patches easy to apply:
diff
, and never use -c with an argument that is less than 3 (for example, do not use
-c2).
diff
from the root of the DJGPP installation, i.e. from the directory where you keep the DJGPP.ENV file, and specify the files being compared with their
pathnames relative to that directory. This allows to concatenate related patches to several files, and apply the combined patch in a single run of the patch
utility.
patch
doesn't understand
backslashes. In particular, DJ Delorie maintains DJGPP on a Unix box.
diff
ignore whitespace, like -b or -w. In most cases, patches generated with these switches
will fail to apply.
| Previous | Next | Up | Top |
Here is a list of places you might look into for examples of frequently needed code fragments, or for packages people keep asking about:
| Previous | Next | Up | Top |
Q: I have this program that behaves differently depending on the name it's called. Under Unix, I just create symbolic links to achieve that, but DOS doesn't support links. Do I have to put several identical programs under different names on my disk??
C:\USR\BIN> stubify -g dj2.exe C:\USR\BIN> stubedit dj2.exe runfile=dj1Voila! Now, when you run dj2, it tells the stub to load the image of dj1, but pass "dj2" in
argv[0].
If you use the DJGPP port of GNU Fileutils 3.13 or later, the ln program there can do the above steps for you if you say this (like on Unix):
ln -s dj1.exe dj2.exe
| Previous | Next | Up | Top |
Q: Where can I find the specifications for the DPMI functions?
The DPMI API is implemented as a set of functions of Interrupt 31h which allow such chores as switch from real to protected mode and back (generally done upon startup and at exit), memory allocation, calling real-mode services, etc. DPMI is by far the most portable way of running protected-mode programs on MS-DOS, MS-Windows and compatible systems.
You can find the DPMI 0.9 spec by anonymous ftp to one of the following sites:
| Previous | Next | Up | Top |
To visit, point your browser to the DJGPP Web site.
| Previous | Next | Up | Top |
Q: I found and corrected a bug in one of the programs distributed with DJGPP. Where should I put it?
If the program is larger than, say, 50K bytes, it's best to upload it to a public site where everybody can get it. You can upload your contribution to a special directory on the DJ Delorie's FTP server. This directory is write-only, and it gets purged every couple of days, so be sure to write to DJ Delorie about your upload; he will then move it to the /pub/djgpp/contrib directory.
If you decide to upload, please send mail to the djgpp-announce list with a brief description of your program/patch. (The message will get reflected to both the news group and the DJGPP mailing list, so you don't have to cross-post there, but it also goes to people who only subscribe to djgpp-announce list because they want to get such announcements and nothing else.)
If your program is more than a patch or a beta version, you might consider uploading it to the DJGPP archives on SimTel.NET. If you decide to do it, write to DJ Delorie and ask him for uploading instructions. Material uploaded there gets automatically distributed to all of the SimTel.NET mirrors throughout the world, which makes it easier to get.
DJ Delorie requests that all contributed packages uploaded to his server be source-only distributions; don't bother to include libraries or pre-compiled binaries, since DJ deletes them when he opens the zip archive. This is so there will be no danger of distributing programs infected by a virus. Please avoid uploading self-extracting archives because DJ extracts them on a Unix machine which can't run DOS executables.
| Previous | Next | Up | Top |
Q: I want to build GCC as a Unix-to-DOS cross-compiler. What should I do?
cin
and cout
don't work. A Win32-hosted gcc-m68k is another possibility. It was created by David Fiddes. The Cygwin32 port of GCC can also be configured as a cross-compiler with m68k as the target. See the description of the Cygnus project, for more details about the Cygwin32 port.
DJGPP can be built and installed as a cross-compiler running on a Unix machine and targeting DOS/Windows platforms. Here are the necessary steps to do that:
You must use the -a switch, to force unzip
to convert any DOS-style text file with CR-LF pairs at the end of each line to Unix-style text files. If you
don't, things will break for you.
unzip
is available in source form from many FTP sites.
The main GNU site is at ftp.gnu.org.
dos-gcc
, so to compile programs with it, use dos-gcc
rather than cc
or gcc
, or set
CC=dos-gcc when invoking Make.
The file cross/readme has some usage info for dos-gcc
. It is generally correct, except that the version numbers for the various packages might not be up to date. You
should always use the latest releases of every package.
Another alternative is the RPM (Redhat Package Maintenance) distribution of the Linux to DOS cross-compiler, which is based on DJGPP v2.01 and includes everything you need to create DJGPP binaries on Linux (without running DOSEmu). This package has been built by James Soutter using the instructions above; you will need Linux and RPM 2.2.7. The RPM packaged cross-compiler is available from Redhat site; the sources are also available.
| Previous | Next | Up | Top |
i = 0xfe+0x20;
Ain't it silly that such a great compiler would fail so miserably?
Judging by the published draft, this is unchanged even in the forthcoming C9X standard.
| Previous | Next | Up | Top |
Q: I have a program that reads struct contents from a binary file. It works OK when compiled with BC, but reads garbage when compiled with DJGPP. This must be a bug in DJGPP, right?
struct my_struct { char name[7]; unsigned long offset; double quality; };To make such a struct use the least number of bytes, rearrange the members, like this(Note: Note that this still allows the struct to be padded at the end.):
struct my_struct { double quality; unsigned long offset; char name[7]; };If the layout of the structure cannot be changed (e.g., when it must match some external specification, like a block of data returned by a system call), you can use the
__attribute__((packed))
extension of GCC (see the "Type Attributes" section of the "GNU C/C++ Manual".) to
prevent GCC from padding the structure members; this will make accesses to some of the members significantly slower.
Beginning with version 2.7.0, GCC has a command-line option -fpack-struct which causes GCC to pack all members of all structs together without any holes, just as if you used
__attribute__((packed))
on every struct declaration in the source file you compile with that switch. If you use this switch, be sure that source files which you compile with it don't
use any of the structures defined by library functions, or you will get some members garbled (because the library functions weren't compiled with that switch). Alternatively, you
could declare any single structure to be packed, like so:
struct { char name[7]; unsigned long offset; double quality; } __attribute__ ((packed));However, note that the latter will only work when you compile it as a C source; C++ doesn't allow such syntax, and you will have to fall back to declaring each struct member with the packed attribute. Therefore, it's best to only use declarations such as above if you are certain it won't be ever compiled as a C++ source.
The padding of struct members should be considered when you read or write struct contents from or to a disk file. In general, this should only be done if the file is read and written by the same
program, because the exact layout of the struct members depends on some subtle aspects of code generation and the compiler switches used, and these may differ between programs, even if they were
compiled by the same compiler on the same system. If you do need this method, be aware of the struct member padding and don't assume that the number of the file bytes that the structure uses is
equal to the sum of the members' sizes, even if you instructed the compiler to pack structs: GCC still can add some padding after the last member. So always use sizeof struct foo
to
read and write a structure.
Another problem with porting programs that read structs from binary files is that the size of some data types might be different under different compilers. Specifically, an int
is
16-bit wide in most DOS-based compilers, but in DJGPP it's 32-bit wide.
The best, most robust and portable way to read and write structs is through a char
buffer, which your code then uses to move the contents into or out of the struct members, one by one.
This way, you always know what you are doing and your program will not break down if the padding rules change one day, or if you port it to another OS/compiler. The ANSI-standard
offsetof
macro comes in handy in many such cases.
| Previous | Next | Up | Top |
struct ffblk
from the header dir.h in a C++ program, I get garbage in some members of the structure!
__attribute__((packed))
directives, so the structures end up being not
packed. DJGPP v2.01 comes with GCC 2.7.2.1 which corrected that bug, so upgrade. As a work-around, surround the declaration of the structure that needs to be packed with #pragma pack
,
like this:
#ifdef __cplusplus #pragma pack(1) #endif . . . #ifdef __cplusplus #pragma pack() #endif
| Previous | Next | Up | Top |
Q: Other DOS compilers supply a function named harderr
or _harderr
to hook the critical-error interrupt 24h, but DJGPP doesn't seem to have these...
IRET
, thus silently failing the DOS call that triggered Int 24h. The DJGPP startup code also hooks the protected-mode Int 24h with a handler that fails the DOS call as described above.
So in most circumstances you won't see that DOS prompt at all; your program will just see a failed DOS call. However, some DPMI hosts (notably, QDPMI), will sometimes crash your program if it generates Int 24h, for instance when you access an empty floppy drive. In such cases, or when the default action of failing the DOS call is not good enough, you will have to hook Int 24h with your handler. This should be done in exactly the same manner as hooking hardware interrupts (see how to set an interrupt handler), because Int 24h is one of the few software interrupts that, like all hardware interrupts, are always reflected to the protected-mode handler first. Note that CWSDPMI currently doesn't support hooking Int 24h; if you set an interrupt handler, it won't be called.
There are ways to avoid program crashes due to Int 24h (under those DPMI hosts that exhibit this buggy behavior) other than to install a handler for it. For instance, you can test if the floppy
drive is empty with a BIOS call before accessing it with DOS functions; there are also similar ways to check if a CD-ROM drive is empty. The library function getmntent
(see
the "getmntent" section of the "libc.a reference".) can be used to detect all the drives that can be safely accessed by
DOS; or you can borrow some of the internal functions used by getmntent
from the library source distribution, or
from the zip picker.
| Previous | Next | Up | Top |
go32-v2
program does the following:
go32
did in v1.x.
go32-v2 myprog
PATH
before the v1.x go32.exe, it can also run a v1 COFF images, by loading the v1.x go32
and
letting it do the job. With this setup, you can run v2 programs from v1.x programs, because the v1.x program will load go32-v2
(since it found it first on the PATH) which knows how to
run v2 images, instead the original go32
which cannot.
| Previous | Next | Up | Top |
Q: Can I make a DLL using the DXE support?
Q: Where can I find information or examples about writing/loading the DXE files?
Q: Why do I get undefined references when I run dxegen
?
A DXE cannot link in any library functions which reference static variables (or which call other routines which reference static variables); this effectively prohibits linking in I/O functions,
allocating memory, and many other useful things. If you do call any of these, you'll get unresolved externals from dxegen
. To work around this limitation, introduce an array of
function addresses which will be used from the DXE at run time to call the "special" routines you cannot link in. Then arrange for the address of this array to be returned by _dxe_load
when it loads the DXE, and make the init routine fill the array with the actual addresses of those "special" functions.
Unloading a DXE is also not supported (but I'm told you can add this by making a few simple changes in the C library).
The only place you can find some docs and examples of writing and using a DXE is in the "tests" archive. The example there is exceedingly simplistic, but then so is the entire DXE mechanism...
| Previous | Next | Up | Top |
Q: Why does Make behave as if some of the files were not there?
PKZIP
) that truncate long names, even on Windows 9X, when they open an archive, which leaves you with names like alongfil.cc, which is not the same as the original
name when LFN is supported. Be sure to use archivers that support long filenames, e.g. use DJTAR when you open .tar.gz archives, or rename all the files to their original
long names after you open the archive. If the problems persist even though the filenames are correct, upgrade to DJGPP v2.01 or later, where all programs should support long filenames properly. If you cannot upgrade, you will have to disable LFN support (set LFN=n from the DOS prompt, setting it in DJGPP.ENV does not always work in DJGPP v2.0).
| Previous | Next | Up | Top |
There are editors that replace TABs with spaces, so even a Makefile that used to work can become unworkable if you edit them with such an editor.
Another, more rare, cause of the above error message is if you use static pattern rules (with the %
character) incorrectly. Read the documentation that comes with Make carefully and try
to find the error.
| Previous | Next | Up | Top |
GNU Make reports such cases because inconsistencies in file times could easily defeat its decisions about which files need to be rebuilt. In particular, if some of the files reside on a networked drive, and there's a clock skew between the machine where Make runs and the one which exports the drive, Make could really fail to rebuild some files.
DJGPP ports of GNU Make v3.77 and later allow for up to 3 seconds of positive difference between the file timestamp and the system clock (that is, the file is allowed to be up to 3 seconds into the future), before the above warning is printed. So upgrading to the latest version of Make should eliminate such bogus warnings and leave you only with messages due to real clock skews.
| Previous | Next | Up | Top |
First, you must set the option in the Windows registry which prevents it from using numeric tails when it invents short 8+3 aliases for long file names. When numeric tails are enabled, and a file with a long name is created, Windows generates a short 8+3 alias for that long name by attaching a numeric tail ~N to the first 6 characters of the basename. For example, a file called ALongFileName.LongExtension will get a short alias alongf~1.lon. When you then reboot into plain DOS, your programs will see this short version only, which will almost certainly break them, since, when a program running under DOS asks for a file with the above long name, DOS transparently truncates it to alongfil.lon, and such a file does not exist. Disabling the numeric tails forces Windows not to use numeric tails unless there is another file in the same directory whose short alias clashes with that of the new file. If no such clash happens, Windows will simply truncate the long name as DOS would, which is exactly what you want. Here is how you disable the numeric tails on Windows 9X:
HKEY_LOCAL_MACHINE
branch of the registry until you see in the left pane an item called HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\FileSystem
, then
click on it.
FileSystem
key. If you don't see an item there called NameNumericTail
, select "New", "Binary Value" from the
"Edit" menu, then type NameNumericTail and it will appear. Now double-click on NameNumericTail
and enter a value of 0.
NameNumericTail
to 0 breaks some programs, you can restore its original setting temporarily, while you run those programs. NameNumericTail
only affects the short
names of new files being created, it has no effect on the files that already exist.(Note: For some reason, Microsoft doesn't like it when users disable numeric tails. Several Microsoft
publications warn against doing that, and I'm told that Windows 98 has made it harder to disable them. I'm not sure why do they object so much. Presumably, some programs rely on certain directories
to have numeric tails, so that they could be found even in plain DOS mode. Apparently, some of those programs have short aliases such as PROGRA~1 (the short version of the Program
Files directory) hard-wired into them, and Microsoft is afraid you could reinstall or move those directories when numeric tails are disabled, and thus cause such programs not to find their
"home". It is obvious that such programs are badly broken (e.g., the short alias could easily be PROGRA~2), and you have every right to yell at the vendor who sells them to you. But
even if you have no other way than to live with them, my experience shows that you have nothing real to worry about. Remember: numeric tails only have effect when files are created or renamed. So,
if you want to be on the safe side, re-enable them before installing Windows software, especially if the programs you install need to run in DOS mode as well (a typical example would be a
disk-recovery package such as Norton Utilities). Then disable numeric tails again, once the installation is over. For what it's worth, I always run my system with numeric tails disabled, and I have yet to see a single real problem.)
Besides the numeric tails, you need to make sure any files and directories you create have unique 8+3 aliases which are true truncations of the long names to 8+3 limits. This means that you should avoid file names with leading dots, such as .emacs and .bashrc, file names with more than a single dot, like make-3.77.tar.gz, or file names which include characters not allowed by DOS, like libg++.a.
One other problem is to avoid using programs which create numeric tails even if they are disabled in Windows. One such program is pkunzip version 2.50. Don't use it, if you want to keep your dual DOS/Windows installation in working order.
The most simple method of deciding at boot time which configuration (DOS or Windows) to start is to edit the (hidden) file MSDOS.SYS, which is a text file in Windows 9X, and force the Windows boot process to present a menu where one menu item, called "Command Prompt Only", allows you to start DOS 7 without the Windows GUI. To this end, change the line of MSDOS.SYS that reads "BootMenu=0" to say "BootMenu=1" instead, and reboot.
| Previous | Next | Up | Top |
One case where the time stamps might be very important is when you need to rebuild some package with Make. Make uses file time stamps to decide which files need to be rebuilt. Another case is if you distribute some files compressed with Zip and want your recipients to be able to restore the correct time stamps of your files when they unzip them.
If you don't care about file time stamps being incorrect in such cases, you can delete all those files and never look back.
You might wonder why we need all these zoneinfo files when the UTC offset is required. Well, the simplest way to tell programs what the UTC offset is, is to have the user specify a single
number which is the offset; but then this number needs to be changed twice a year, to accommodate for the daylight saving time. Another, not-quite-so-simple way is to have the user specify the
current UTC offset and the DST rules; but this is a tedious and error-prone process, and many users get it wrong. Both of these methods have the drawback that if the rules change, programs
misinterpret old time-stamps, since they treat them according to new rules. Using a table that is read from a file and includes the offset calculation rules for every year avoids all these problems
and requires the user to point the TZ
environment variable to the file that is pertinent to his/her time zone, which is easy:
set TZ=c:/djgpp/zoneinfo/israelor
set TZ=c:/djgpp/zoneinfo/us/alaskaTo find the rule suitable for your location, look into the src subdirectory of zoneinfo and browse the file whose name is your continent/part of the world. If no binary file exists with the name of your zone, you can create one with using the time-zone compiler zic, whose source is available in the v2/djlsr201.zip file, with the rest of DJGPP.
A public domain time-zone database exists, and is updated from time to time with the latest world-wide changes to the offset calculation rules. (The rules change because politicians in different countries make laws that change the local clock settings.) The contents of the zoneinfo directory which comes with DJGPP is based on this database, but if you want the latest rules, you can download them from the net as tzdata*.tar.gz; tzcode*.tar.gz in the same directory includes the programs that can be used to generate the offset tables from their source in tzdata*.tar.gz, the latest implementations of POSIX library functions that use time-zone information, and the man pages that document the rules and the software. The last update as of this writing was in May 1998.
On any single machine, you don't need more than a single file from that directory, which is the file for your time zone; once you find that file, you can safely delete the rest. But if you distribute a program that uses the TZ setting, you will have to include all of the files, or tell your users how to get and install them.
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
go32-v2
, stubify
and stubedit
, need to be changed as well.
| Previous | Next | Up | Top |
Q: I keep getting the same random numbers each time I run my program. How do I get a different series on every run?
rand
and random
. The former is part of the ANSI C Standard, and is therefore very portable to other
environments. The latter is available on almost every Unix platform, but is generally unsupported by DOS/Windows compilers. On the other hand, series produced by random
have better
qualities than those produced by rand
. In particular, the least-significant bits in the numbers produced by random
are much more random than those you get from
rand
, so if you need, say, a random number between 0 and 4, and portability is not an issue, you will get better results with random () % 5
. However, the DJGPP
implementation of rand
is quite good, so when portability is important, you should use rand
.
Both rand
and random
return a pseudo-random integer in the range [0..RAND_MAX]
, where RAND_MAX
is defined in the stdlib.h header.
By default, every time you restart a program, you get the same series of pseudo-random numbers. This is important in some applications, because it allows to reproduce exactly the results of running
a program which used random series, and thus makes debugging easier. But sometimes, e.g. in a game, you will want a different series every time. To achieve that, you need to initialize the random
series with a different seed. Two functions provided for this purpose, srand
and srandom
, will seed the series generated, respectively, by rand
and
random
. You seed the series with a single call to srand
or srandom
, and then proceed by calling rand
or random
as usual.
A popular way of getting a different seed every run is to use the current system clock as the seed, like this:
srand (time (NULL));If the 1-second granularity of the values returned by
time
is not enough for you (e.g., if you need to generate more than one series every second), use gettimeofday
or
uclock
, or use the values returned by rand
as an argument to srandom
(or vice versa).
| Previous | Next | Up | Top |
| Previous | Next | Up | Top |
main
function return in a C program?
void main
is bad?
Q: If void main
is incorrect, how come the compiler lets it compile?
main
function be declared in one of the following two ways:
int main (void);or
int main (int argc, char **argv);In both cases the return type is an
int
, and your main
function should therefore either return an int
or call the library function exit
, when the
program ends.
Since the runtime environment assumes that main
returns an int
, declaring main
with any other return type, including void
, invites trouble. The
compiler might compile such a program, since the ANSI Standard doesn't require it to fail, but the behavior of such a program is, in the Standard's parlance, "undefined" (read: anything can
happen). That is why GCC will print a warning in these cases if you use the -Wall switch.
To summarize, using void main
is unsafe and can potentially do evil things to your program. It is best to avoid it.
If you prefer to read the FAQ list as hard-copy, get faqNNNp.zip from the same place. It includes the FAQ in PostScript and PCL formats; the former is for printing on a PostScript printer, the latter is for the LaserJet series. Be warned: the FAQ is a large document, more than 200 printed pages. faqNNNp.zip also includes a .dvi file which you can print or view using one of the available DVI drivers and previewers, such as Ghostscript or dvivga.
If none of these formats is good enough for you, you will need to get the FAQ sources and convert them into the format of your liking. The sources of the latest version of this FAQ list are on SimTel. This includes the FAQ sources themselves (written in Texinfo), and all the auxiliary tools required to produce all the formats in faqNNNb.zip and faqNNNp.zip.
Once you download the sources, you will need one or more of the tools listed below to generate the FAQ list in other formats.
A program called Makertf can reportedly be used to convert a Texinfo sources of this FAQ to the Rich File Format which can then either be browsed by an RTF browser (such as Adobe Acrobat) or converted into a Windows Help file with a Windows Help compiler. The Windows Help Compiler is available via anonymous ftp from the Microsoft ftp site.
A derivative of TeX called PDFTeX can be used to generate a PDF file from TeX sources. This means that a Texinfo source can also be submitted to PDFTeX, but I didn't try that. PDFTeX was port to DJGPP and can be downloaded from its home site via FTP.
There's also a program called INFNG that can be used to convert the Info (not Texinfo) version of the FAQ to the Norton Guide format. INFNG is available from the DJGPP archives.
If you know about any format not mentioned above that can be generated using widely available tools, please drop me a note so I could update this list and consider that format or those tools for inclusion in a future release of the FAQ. If you develop any such tools, consider uploading them to a site where they will be publicly available, and tell me about that site.
Note that the FAQ sources are heavy users of the Texinfo macro facility, so any conversion program that doesn't support Texinfo macros will probably have hard time coping with the FAQ. When confronted with this problem, try feeding the converter with the macro-expanded version of the FAQ (the Makefile in the source distribution has a special target for such cases).
Copyright (C) 1994, 1995, 1996, 1997, 1998 by Eli Zaretskii. This FAQ may be freely redistributed with the DJGPP package or any part thereof, provided that you don't prevent anybody else from redistributing it on the same terms, and that this copyright notice is left intact.
Comments about, suggestions for, or corrections to this FAQ list are welcome. Please make sure to include in your mail the version number of the document to which your comments apply (you can find the version at the beginning of this FAQ list).
Much of the info in this FAQ list was taken from the DJGPP mailing list/news group traffic, so many of you have (unbeknownst to you) contributed to this list. The following people deserve special credit for reading this list in its previous versions and providing useful feedback, comments, information and/or suggestions:
John M. Aldrich Anthony Appleyard Gurunandan R Bhat John Bodfish Francois Charton Alain CULOS Bill Currie Bill Davidson DJ Delorie Tom Demmer Nate Eldredge Juergen Erhard Andy Eskilsson Jeremy Filliben Peter Gerwinski Till Harbaum James W. Haefner Kris Heidenstrom Koen Van Herck Vik Heyndrickx Robert Hoehne Gordon Hogenson Harry Johnston Martynas Kunigelis Pieter Kunst Y. Lazarovitch Alexander Lehmann Marty Leisner Dave Love Randy Maas Cameron Mallory Colin S. Miller Duncan Murdoch Rob Nader Eric Nicolas Adrian Oboroc Jan Oonk Elliott Oti Bob Paddock Esa A E Peuha Walter Prins Steve Salter Charles Sandmann Terrel Shumway Andrew Szymkowiak Launey Thomas Chris Tilbury Ned Ulbricht Stephen Turnbull Santiago Vila Ronan Waide Morten Welinder Anthony Edward Wesley K.B. Williams Mark H. Wood