(minor) ld buf

Andrew Kurn kurn at sfucmpt
Sun Oct 9 09:19:47 AEST 1983


I have recently had reason to investigate the behavior of ld, the loader.
I would like to take this opportunity to share with you all the results
of that work.

When the loader is processing an archive trying to resolve undefined
symbols it treats symbols defined in Text and Data segments in the
expected manner.  If one of these resolves a previously undefined
reference, the member is loaded.  However, when it sees a COMMON
symbol which increases the size of the named COMMON block above
what had previously been known, it notes the new size INDEPENDENTLY
of whether or not it loads the current member.  That is, a change
in the size of a COMMON block is not taken as a reason to load
the member.  This may be thought of as the mildest kind of bug.

C programmers are perhaps wondering what this might have to do with them.
A little.  It contrives to come about that the C compiler calls global
declarations without initialization (int a; vs. int a=14;) a named
COMMON block.  Thus, despite the fact that brother Kernighan and
brother Ritchie tell you that you must define storage for a 
global variable exactly once, you can get away with multiple definitions
as long as none are initialized.

OK, you say.  Well yes, BUT:

It gives rise to an obscure problem, which is the reason for all this.
When running the loader with -M it is supposed to give you the names
of all the members from an archive which it uses in the core load.
Since in its opinion, it never loads a member which does nothing
but define COMMON, it does not mention it in the list.  Thus the list
may be incomplete.

No one in a million years would ever get hurt by this bug, you say,
but, of course, I've been stung by this problem.

Now it's conceivable that some turkey out there in terminal land
depends on this quirky behavior, so I haven't felt free to change
the actual action of the loader.  My fix is to add a flag to the
command line which reports it whenever the loader increases a COMMON
block without loading the current module.

The flag is -C

The output thus created is mixed in with the -M output but
may be distinguished since those lines begin with "C".

Replies by mail!   --- to sfucmpt!kurn

KEEPERS OF UNIX:
Please add a word about this problem to the manual page!!!

(For those of you who still remember things like the 1620,
the title of this piece is "How Far the Vestiges of Fortran
Pursue Us".)

		Andrew Kurn
		Simon Fraser U.
		Canada

Herewith are the changes to ld.c:

*** ld.C	Tue Oct  4 20:52:57 1983
--- ld.c	Sat Oct  8 13:21:54 1983
***************
*** 218,223
  int	arflag;		/* original copy of rflag */
  int	sflag;		/* discard all symbols */
  int	Mflag;		/* print rudimentary load map */
  int	nflag;		/* pure procedure */
  int	dflag;		/* define common even with rflag */
  int	zflag;		/* demand paged  */

--- 218,224 -----
  int	arflag;		/* original copy of rflag */
  int	sflag;		/* discard all symbols */
  int	Mflag;		/* print rudimentary load map */
+ int	Cflag;		/* mention modules which (only) define common -AK*/
  int	nflag;		/* pure procedure */
  int	dflag;		/* define common even with rflag */
  int	zflag;		/* demand paged  */
***************
*** 400,405
  		case 'M':
  			Mflag++;
  			continue;
  		case 'x':
  			xflag++;
  			continue;

--- 401,409 -----
  		case 'M':
  			Mflag++;
  			continue;
+ 		case 'C':	/*-AK*/
+ 			Cflag++;
+ 			continue;
  		case 'x':
  			xflag++;
  			continue;
***************
*** 566,572
  	int kind;
  
  	kind = getfile(cp);
! 	if (Mflag)
  		printf("%s\n", filname);
  	switch (kind) {
  

--- 570,576 -----
  	int kind;
  
  	kind = getfile(cp);
! 	if (Mflag || (Cflag && kind))
  		printf("%s\n", filname);
  	switch (kind) {
  
***************
*** 727,732
  	register struct nlist *sp;
  	struct nlist *savnext;
  	int ndef, nlocal, type, size, nsymt;
  	register int i;
  	off_t maxoff;
  	struct stat stb;

--- 731,737 -----
  	register struct nlist *sp;
  	struct nlist *savnext;
  	int ndef, nlocal, type, size, nsymt;
+ 	int ncom;
  	register int i;
  	off_t maxoff;
  	struct stat stb;
***************
*** 747,752
  		error(1, "too small (old format .o?)");
  	ctrel = tsize; cdrel += dsize; cbrel += bsize;
  	ndef = 0;
  	nlocal = sizeof(cursym);
  	savnext = nextsym;
  	loc += N_SYMOFF(filhdr);

--- 752,758 -----
  		error(1, "too small (old format .o?)");
  	ctrel = tsize; cdrel += dsize; cbrel += bsize;
  	ndef = 0;
+ 	ncom = 0;
  	nlocal = sizeof(cursym);
  	savnext = nextsym;
  	loc += N_SYMOFF(filhdr);
***************
*** 780,785
  			continue;
  		if (cursym.n_type == N_EXT+N_UNDF) {
  			if (cursym.n_value > sp->n_value)
  				sp->n_value = cursym.n_value;
  			continue;
  		}

--- 786,792 -----
  			continue;
  		if (cursym.n_type == N_EXT+N_UNDF) {
  			if (cursym.n_value > sp->n_value)
+ 				{
  				sp->n_value = cursym.n_value;
  				ncom++;		/* size of named common has */
  				}		/* been increased  -AK*/
***************
*** 781,786
  		if (cursym.n_type == N_EXT+N_UNDF) {
  			if (cursym.n_value > sp->n_value)
  				sp->n_value = cursym.n_value;
  			continue;
  		}
  		if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)

--- 788,795 -----
  			if (cursym.n_value > sp->n_value)
  				{
  				sp->n_value = cursym.n_value;
+ 				ncom++;		/* size of named common has */
+ 				}		/* been increased  -AK*/
  			continue;
  		}
  		if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
***************
*** 805,810
  		}
  		free(curstr);
  		return (1);
  	}
  	/*
  	 * No symbols defined by this library member.

--- 814,826 -----
  		}
  		free(curstr);
  		return (1);
+ 	}
+ 	if (ncom && Cflag && libflg){
+ 		/*
+ 		 * Although not loaded, this member has caused common
+ 		 * allocation to increase. -AK
+ 		 */
+ 		printf("C\t%s\n", archdr.ar_name);
  	}
  	/*
  	 * No symbols defined by this library member.



More information about the Comp.unix.wizards mailing list