[comp.bugs.4bsd] libraries may hide porting problems

wsmith@m.cs.uiuc.edu (08/31/88)

This problem with the BSD linker can cause portability problems for
programs that use programmer created libraries.

Description:  
	In the BSD C compiler may not complain of multiply defined functions
	while in other C compilers will fail to link the same program.
	If the only data needed by the linker from a module is a variable
	in BSS, multiply defined functions in that same module will be 
	ignored.

Repeat-By:  
	Create two files, one.c two.c

one.c:
	extern int a;
	main()
	{
		printf("%d\n",a);
	}
	four() { }
two.c:
	int a;
	four() { }

If the program is compiled with "cc -o aprog one.c two.c", _four is
reported as multiply defined.  However, if the program is compiled with 
"cc -c one.c two.c
 ar r alib.a two.o
 ranlib alib.a
 cc -o aprog one.o alib.a" no error will be reported (under BSD).  

With other compilers on other operating systems, _four will be multiply
defined in both cases.  However, if the first line of two.c is changed to
"int a = 7;", the BSD C compiler will report _four as multiply defined in 
both cases.  Linking with a library should be equivalent to linking the
individual modules in the library that are needed.  In this problematic
case, the equivalence is broken.

Fix: ???

Bill Smith	wsmith@cs.uiuc.edu		uiucdcs!wsmith

ron@topaz.rutgers.edu (Ron Natalie) (09/01/88)

You're problem is NOT that the _four is not properly
reported as being multiply defined, it is that the
module two.o isn't loaded at all.  The "int a" declaration
generates a .com of the appropriate space.  Declarations
need not force loading of modules with identical declarations.

-Ron

mouse@mcgill-vision.UUCP (der Mouse) (09/10/88)

In article <Aug.31.18.45.05.1988.12460@topaz.rutgers.edu>, ron@topaz.rutgers.edu (Ron Natalie) writes:
> You're problem is NOT that the _four is not properly reported as
> being multiply defined, it is that the module two.o isn't loaded at
> all.  The "int a" declaration generates a .com of the appropriate
> space.  Declarations need not force loading of modules with identical
> declarations.

Except the declarations weren't identical.  The explicitly-loaded .o
file's declaration was explicitly extern.  The one in the library was a
non-extern definition (a "tentative" definition).  *Some* definition of
that variable is needed somewhere, or the loader will (properly)
generate an undefined symbol error.  The problem is that two.o provides
that definition, but the definition is being taken from two.o without
including the rest of two.o.  I agree with the original poster that
this is a bug.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

ron@topaz.rutgers.edu (Ron Natalie) (09/12/88)

>  The problem is that two.o provides
>  that definition, but the definition is being taken from two.o without
> including the rest of two.o.  I agree with the original poster that
> this is a bug.

No, no, no.  There is a bug, but it is not that only "part" of the file
is loaded.  The problem is that the file containing the non-externed
definition isn't loaded at all.

There are essentially two types of C-compilers.  Some will take external
definitions (whether they have extern before them or not) and generate
common blocks for them.  The function of a common block is that all references
in the .o files are merged into the same area (with an initialization if one
is available).  For example, these machines will not give an error on
the following:

	a.c:
		int	ex_a;

	b.c:
		int	ex_a;

	cc a.c b.c -o out

"int	ex_a;" and "extern int	ex_a;"  generate the same code, which
looks something like "ex_a:	.com 4".


Other machines will generate an actual data storage declaration for each
of those un-externed declarations.  They rely on the rule in C that says
that only one actual definition occurs and the rest be "externed."

The problem is the user has the commonizing compiler.  Normally that behavior
is OK, in that even if you do use the extern for n-1 definitions rule, the
code will work.  The problem is that if you put a module into a library it
treats the "un-externed" reference as just another instance of the common
block and doesn't cause that to force the module to be loaded.  I get bitten
by this periodically.

-Ron