delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1994/09/20/23:47:18

Date: Tue, 20 Sep 94 14:40 PDT
From: jdp AT polstra DOT com (John Polstra)
To: dj AT ctron DOT com
Cc: djgpp AT polstra DOT com
Subject: Re: strange linker behavior

I wrote, and DJ replied:

> > The implementation is absolutely not allowed to pollute any other
> > portions of the global name space.  The djgpp C library is a bad offender
> > in this regard.
> 
> Which is better - 100% ansi/posix conformance, or compatibility with
> other compilers?

That's a tough question, of course.  It's especially difficult in the
DOS world, which has evolved its own de-facto standards concerning what
library functions and header files should be present.

To some extent, you can get the best of both worlds, though.

ANSI doesn't forbid the compiler implementation from providing functions
(global names) in addition to those required by the standard.  It merely
demands that those names not get in the way of a user unless he asks for
them.  In practice, this means two things:

    1.  The prototypes / declarations for extra functions must not
	appear in any of the standard ANSI header files (or in any other
	files included by the ANSI header files).  The ANSI standard
	header files are the following:

		<assert.h>	<locale.h>	<stddef.h>
		<ctype.h>	<math.h>	<stdio.h>
		<errno.h>	<setjmp.h>	<stdlib.h>
		<float.h>	<signal.h>	<string.h>
		<limits.h>	<stdarg.h>	<time.h>

	The ANSI headers must declare only those symbols specified in
	the standard (and they must declare all of them).

    2.  (Here comes a little lie, which I will clear up in a minute.)
	If the implementation provides any extra global functions (e.g.,
	delay() or read() or write()), none of the standard library
	functions are allowed to use the extra ones.  For example,
	the implementation of fgetc() is not allowed to call read().

	The little lie in the above is this:  The library actually
	*is* allowed to implement fgetc() in terms of read(), provided
	that it behaves as if it didn't, from the user's point of view.
	(Likewise for other functions, of course.)  That is, if fgetc()
	calls read(), then it better still work if the user defines his
	own global function named read() that does something entirely
	different.

Getting the header files and library just right is not all that easy!
Vendors do it wrong all the time.

Incidentally, to expand on #2 above, I'll give an example of how a
library can achieve the "as if" behavior.  As most Unix programmers
realize, fputc() is always really implemented using read().  But the
ANSI-conforming library must behave as if it were not.  Yet, it must
still make read() available to Unix programmers who want to use that
function (which is Posix standard, by the way).  One way to do this is:

    * The library puts all the functionality of read() into a different
      function named "_read".

    * fputc() calls _read() to get its I/O done.

    * The user-visible read() function is just a wrapper that calls
      _read().

    * read() and _read() are in separate object modules in the run-time
      library, so that they can be pulled in from the library
      independently of one another.

That way, the user can write his own version of read(), causing the
library version not to be used.  But that won't affect the behavior of
the standard function fputc(), which uses _read() instead.

Another way to do it involves using so-called "weak" symbols.  But
they're not supported by the COFF object format that djgpp uses.

I hope this is helpful.

   John Polstra                                       jdp AT polstra DOT com
   John D. Polstra & Co., Inc.                   Phone (206) 932-6482
   Seattle, Washington USA                         Fax (206) 935-1262
   "Self-knowledge is always bad news."                 -- John Barth

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019