[comp.sys.ibm.pc] MSC v5.1 bug; variable not made public

evas@euraiv1.UUCP (Eelco van Asperen) (11/02/88)

Hi,

I've just found a nice bug in MSC v5.1; if you declare an unitialized
variable in a module that has no other publics and put that module in
a library, the variable will _not_ be found by LINK. Here's a small
example;

File alfa.c:
	char	alfa[1000];

	proc_alfa() {}

File beta.c:
	extern	char	alfa[];

	main()
	{
		strcpy(alfa,"This is a bug !");
	#ifdef CALL_ALFA
		proc_alfa();
	#endif
		puts(alfa);
		exit(0);
	}

compile this;
	cl -c alfa.c beta.c
create a library;
	lib demo +alfa;
and try to link;
	link /noi beta,,,demo;
and bingo;
	Microsoft (R) Overlay Linker  Version 3.65   
	Copyright (C) Microsoft Corp 1983-1988.  All rights reserved.

	LINK : error L2029: Unresolved externals:

	_alfa in file(s):
	 BETA.OBJ(beta.c)

	There was 1 error detected

Now, I did not insert that #ifdef in beta.c for nothing; let's recompile
with -DCALL_ALFA;

	cl -DCALL_ALFA -c beta.c
	link /noi beta,,,demo;

and everything is fine.
To determine what caused the error, I did the same for TurboC v1.5;

	tcc -c alfa.c beta.c
	lib demo +alfa;
	link \tc\lib\c0s beta,beta,,demo \tc\lib\cs;

and hey, no errors !
I then used OBJSNOOP to peek in the OBJ-files to see what publics they
contained and sure enough the TurboC version contained _alfa while the
MSC version did not;
TurboC:
	---------- alfa.obj

	public _alfa
	public _proc_alfa
MSC:
	---------- alfa.obj

	extrn  __acrtused
	extrn  __chkstk
	extrn  _proc_alfa
	public _proc_alfa


The same thing happens if 'alfa' is an int; however, if you initialize
'alfa', then everything will work ok. For example;

	char	alfa[] = "Just a test!";

Peeking with OBJSNOOP at ALFA.OBJ shows;

	---------- alfa.obj

	extrn  __acrtused
	extrn  __chkstk
	extrn  _proc_alfa
	public _alfa
	public _proc_alfa

I realize that this is a pathetic example but I was bitten by it and 
it took me an hour to find why the *****y linker could not find two 
global arrays I had declared in a separate file with no other entries.
(and then another half hour to document it, try alternatives and 
write this ;-)

-- 
Eelco van Asperen.		            EUR/Rotterdam/Netherlands
uucp: evas@eurtrx / mcvax!eurtrx!evas	 earn/bitnet: asperen@hroeur5
"We'd like to know a little bit about you for our files"
                                    - Mrs.Robinson, Simon & Garfunkel     

creps@silver.bacs.indiana.edu (Steve Creps) (11/03/88)

In article <792@euraiv1.UUCP> evas@euraiv1.UUCP (Eelco van Asperen) writes:
>I've just found a nice bug in MSC v5.1; if you declare an unitialized
>variable in a module that has no other publics and put that module in
>a library, the variable will _not_ be found by LINK. Here's a small

   That problem is also in MSC 4.0. I too noticed that initializing the
variable makes the problem go away. It's also possible that the bug is
actually in LIB, as the uninitialized variable still shows up in the .obj
file when I do a strings on it.

-	-	-	-	-	-	-	-	-	-
Steve Creps, Indiana University, Bloomington, home of the "Hoosiers"
	creps@silver.bacs.indiana.edu (129.79.1.6)
	{inuxc,rutgers,uunet!uiucdcs,pur-ee}!iuvax!silver!creps
	creps@iubacs.bitnet (forwarded)

allbery@ncoast.UUCP (Brandon S. Allbery) (11/10/88)

As quoted from <792@euraiv1.UUCP> by evas@euraiv1.UUCP (Eelco van Asperen):
+---------------
| I've just found a nice bug in MSC v5.1; if you declare an unitialized
| variable in a module that has no other publics and put that module in
| a library, the variable will _not_ be found by LINK. Here's a small
| example;
+---------------

It's not a bug.  Believe it or not, it's a feature.

The idea is to be able to load variant versions of functions based on what
is used by a program.  It applies *only* to programs.  I should note that
UN*X "ld" acts the same way (but Minix "asld" does *not*, which explains why
the following example doesn't work under Minix).

An example of why this is useful is "stdio", as implemented by UN*X and
possibly by the MSC library.  Basically, the C start-up "stub" calls the
function "main" (which is your main program function) and passes the return
value to the function "exit".  Now, IF YOU USE stdio, the exit() function
has to call another function (usually called _cleanup()) to flush stdio
buffers.  If you DON'T use stdio, the function _cleanup() must NOT be called
or stdio will be dragged into your program for no purpose and waste space.

The solution is that the linker watches for the use of multiple externs in
files in some way which I'm not really familiar with.  The effect I do
know:  if you don't reference any other stdio functions, the linker will use
the non-stdio exit().  If you reference any of the other functions, they
will force the loading of the stdio version of exit().

Your problem is that the extern variable isn't enough to force the loading
of the source file where it is declared.  When you add the function call,
it forces LINK to load the file containing it and "drags in" the extern at
the same time.  (Thus, you could have a number of different variables with
the same name declared in that way in the library, but function calling
patterns would determine which one actually got linked into the program.)

I suggest that the best place to find out about this aspect of linkers is
comp.unix.questions, since it's a question that comes up every so often
about the UN*X linker.

++Brandon
-- 
Brandon S. Allbery, comp.sources.misc moderator and one admin of ncoast PA UN*X
uunet!hal.cwru.edu!ncoast!allbery  <PREFERRED!>	    ncoast!allbery@hal.cwru.edu
allberyb@skybridge.sdi.cwru.edu	      <ALSO>		   allbery@uunet.uu.net
comp.sources.misc is moving off ncoast -- please do NOT send submissions direct
      Send comp.sources.misc submissions to comp-sources-misc@<backbone>.

NU013809@NDSUVM1.BITNET (Greg Wettstein) (11/12/88)

I have just noticed what appears to be a bug in Codeview and am wondering if
anyone on the net has noticed a similar problem.  First the hardware
configuration I have noted the problem on:

   ALR 386/220  (80386 processor running at 20 Mhz)
   2 Megabyte RAM
   80 Megabyte hard disk - drive and controller unknown.
   Packard Bell EGA video card
   Phoenix 80385 BIOS 3.07.00   (Mirrored to RAM)
   Packard Bell 2400 baud internal modem configured for COM2
   1 Serial and 1 Parallel Port

Software configuration:
   DOS 3.3
   Codeview Version 2.2
   MSC Version 5.1
   QuickC Version 1.01
   MS LINK Version 3.65 (? - Version number may not be exact but it is the
                             Linker supplied with MSC Version 5.1.

      * All compiler software was installed with the SETUP program supplied
        with MSC 5.1.  Only the small model libraries were selected and
        the emulator library was selected. (Presence of co-processor detected
        at run-time and fixups generated, otherwise emulator code used for
        floating point operations.)

Run-time Environemnet:
   Config.sys entry:  FILES = 20
   No autoexec.bat file executed.
   No memory resident programs active.

Problem:
   A program was compiled using the small memory model with both MSC 5.1 and
   QuickC 1.01.  The program consisted of five modules each of which were
   compiled independently with the following compiler command:

        (Q)CL /Zi /Od /c (pname.c)
           where pname is the filename of the source file.

   The executable file was prepared by linking all five modules together with
   the following linker command:

        LINK /CODEVIEW /NOI  p1+p2+p3+p4+p5,p1,p1.map,lib1.lib+lib2.lib

           Where p1-p5 are the names of the modules and lib1-lib2 are object
           code libraries prepared with MSC 5.1 and continuing various adjunct
           functions.

   The Codeview debugger was invoked with the following commands:

        cv /r p1                   * The /r switch instructs Codeview to use
                                     the hardware debug registers for setting
        cv /r /cgmain p1             tracepoint interrupts.

   In the first case the program was than executed to the program entry point
   with the following command: g main

   In both cases after the startup code was executed returning to DOS with
   the q command resulted in a system hang.  The screen would go blank and
   CTRL-BREAK would elicit no response.  The system still seemed to be
   servicing interrupts since pressing CTL-ALT-DEL would re-boot DOS.

   The first function of this program is to display an entrance menu.  When
   execution was started with a simple go (g or F5) the program would display
   display the menu and when the exit command was issued a 'program terminated
   normally' prompt would be issued and at this time the 'q' command would be
   result in a normal return to dos.

   At first I thought this behavior simply resulted from returning to DOS
   without executing the program termination code.  I then allowed the program
   to execute through several menu levels and then terminate.  After this
   process the computer would hang when a return to DOS was attempted.

   Has anyone else experienced this difficulty while attempting to use the
   hardware debug registers with Codeview?  I have not tested the bug with
   other programs but it is quite reproducible with this example.  Removing
   the /r switch when Codeview was executed resulted in complete alleviation
   of the problem.  I would appreciate comments from anyone who has
   experienced this problem or knows of similar problems with other 80386
   processors.  Replys to either the net or by e-mail would be fine.  Thanks
   in advance.

                                                As always,
                                                G.W. Wettstein
                                                NU013809@NDSUVM1