[comp.unix.questions] Changing symbols to "static"

jobrien@nixbur.UUCP (John O'Brien) (10/31/90)

Is there some way to change a symbol's class to "static" in a ".o" file?
Suppose I have a ".c" file with functions "a" and "b", and global variables
"x" and "y":

int c, d;

a()
{
  ...
}

b()
{
  ...
}

Suppose also that I have another ".c" file that refers to "a",
"b", "c" and "d":

external int c, d;

spot()
{
   ...

   a();
   b();

   ...
}

so I can't just make any of the symbols "static".  Now
suppose that I want to use the function "spot" two ways:  I want to
link it in with my own application, where I am not worried about "a"
and "b" being linked in inadvertently, and I also want to make "spot"
and only "spot" available to someone else for linking.  I think it
would be possible to combine the two ".o" files into one ".o" file,
but would it then be possible to change the class of "a", "b", "c" 
and "d" to static so that they would not be exported to the linker?

				Thanks

internet:  obrien.bur@nixdorf.com
uucp: linus!nixbur!jobrien


Flying saucers, levitation/Yo!  I can do that!  - D. Byrne

gwyn@smoke.brl.mil (Doug Gwyn) (11/01/90)

In article <781@nixbur.UUCP> jobrien@nixbur.UUCP (John O'Brien) writes:
>Is there some way to change a symbol's class to "static" in a ".o" file?

Technically, there probably is, but it wouldn't solve whatever problem
you think it would.

>but would it then be possible to change the class of "a", "b", "c" 
>and "d" to static so that they would not be exported to the linker?

You're missing an important point:  spot() REQUIRES that definitions
be provided for a() and b().  Changing these to private rather than
global symbols wouldn't magically define suitable functions!  In some
(non standard conforming) implementations, c and d might already be
compiled into references to "common" storage, so they would get
storage defined for them even if there were no explicit definition in
the set of modules being linked.

My recommendation is to design the kind of external interfaces you
really want, rather than trying to override the design via the linker.

jobrien@nixbur.UUCP (John O'Brien) (11/01/90)

In article <14294@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:

>You're missing an important point:  spot() REQUIRES that definitions
>be provided for a() and b().  Changing these to private rather than
>global symbols wouldn't magically define suitable functions!  In some
>(non standard conforming) implementations, c and d might already be
>compiled into references to "common" storage, so they would get
>storage defined for them even if there were no explicit definition in
>the set of modules being linked.

Let me try again.  I'm already referring the symbols a,b,c and d from
several places (they are utility functions), so I can't just make them
static.  What I want to do takes two steps.  Assume the file with a, b,
c, and d is named "one.c", and the file with spot is named "two.c" and
both files have been compiled to ".o" files.  The first step is to link
"one" and "two" into another ".o" file:

	ld -r -o big.o one.o two.o

This creates a ".o" file by combining "one.o" and "two.o" into "big.o",
which contains all of the definitions and which has external symbols
a, b, c, d, and spot.  Now, if it is possible to change a, b, c, and d to
"static" class, when another program links in big.o a, b, c, d are not
exported but can be referred to within "big.o".  Nobody ever links in 
more than one pass, so this approach is not commonly understood (by me,
either).

>
>My recommendation is to design the kind of external interfaces you
>really want, rather than trying to override the design via the linker.
This code is here, this code has been extensively tested, this code is
called from many different places.  Part of the design requirements is
that I link in this code and not copy the source (this is to avoid hav-
ing to maintain two pieces of code that do the same thing).

			John

gwyn@smoke.brl.mil (Doug Gwyn) (11/02/90)

In article <783@nixbur.UUCP> jobrien@nixbur.UUCP (John O'Brien) writes:
>	ld -r -o big.o one.o two.o
>Part of the design requirements is that I link in this code and not copy
>the source (this is to avoid having to maintain two pieces of code that
>do the same thing).

Thanks for the additional information.  I don't think in most environments
this approach can be made to work, because while you're still outputting a
.o file the final link-image relocation has not yet been done, and if your
compiler generates external linkages in certain commonly-encountered ways,
you simply can't get "ld" to provide "position-independent code" for the
linkages between one.o and two.o; it will be necessary to retain the
relocation information.  I think that some, maybe all, versions of "ld"
would fail to complete the relocation if you were to somehow change the
intermodule references to have the STATIC attribute.

Here is one possibility that doesn't require playing tricks with the linker:

	/* file one.c: */
	#ifndef STATIC
	#define	STATIC	/* nothing */
	#endif
	STATIC int c, d;
	STATIC a()
	{
	  ...
	}
	STATIC b()
	{
	  ...
	}

	/* file two.c: */
	#ifdef STATIC
	#include "one.c"
	#else
	external a(), b();
	external int c, d;
	#endif
	spot()
	{
	   ...
	   a();
	   b();
	   ...
	}

Thus, if you type
	cc -c one.c
	cc -c two.c
you get the same object code that you started with, but if you type
	cc -c -DSTATIC=static two.c
you get one object "two.o" that contains only one external name, "spot".

Of course, you can make this approach more aesthetically appealing by
using an auxiliary header file that defines the interface to the "one.c"
facilities; you should in general do that anyway as a matter of good
program design.  So, for example,

	/* file one.c: */		/* file one.h: */
	#include "one.h"		#ifndef STATIC
	STATIC int c, d;		#define STATIC	/* nothing */
	STATIC a()			extern int c, d;
	{				extern a(), b();
	  ...				#else /* STATIC = "static" */
	}				#ifndef BEEN_HERE
	STATIC b()			#define BEEN_HERE
	{				#include "one.c"
	  ...				#endif
	}				#endif

	/* file two.c: */
	#include "one.h"
	spot()
	{
	   ...
	   a();
	   b();
	}

We've used similar methods here to control whether or not some subset
of potentially external symbols get "hidden" when modules are added to
a library; some of our debuggers are more helpful when the symbols are
not hidden, i.e., not file-static, so we like to leave them visible
until we've finished debugging the modules.  This nice thing is that
this method is portable.  (If you use a configuration header, say,
"config.h" or "std.h", to optionally predefine STATIC and to set up
flags for other environmental dependencies, then it becomes fully
portable, and you don't have to specify "-DSTATIC=static" to the
compiler.)

richard@aiai.ed.ac.uk (Richard Tobin) (11/02/90)

In article <781@nixbur.UUCP> jobrien@nixbur.UUCP (John O'Brien) writes:
>Is there some way to change a symbol's class to "static" in a ".o" file?

Almost certainly.  Examine the format of symbol table entries, and see what
you can do.  There will be include files describing it - a.out.h perhaps,
and a man page for a.out.  Then write a program which reads in the .o
file, and writes it out with a modified symbol table.

A simple hack which may be enough is just to edit the .o file (using an
editor like gnu emacs which doesn't have line length restrictions).
Find the symbol name and change it to something obscure, being careful
not to change its length.

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

srodawa@vela.acs.oakland.edu (Ron Srodawa) (11/03/90)

In article <3693@skye.ed.ac.uk> richard@aiai.UUCP (Richard Tobin) writes:
>In article <781@nixbur.UUCP> jobrien@nixbur.UUCP (John O'Brien) writes:
>>Is there some way to change a symbol's class to "static" in a ".o" file?
>
>Almost certainly.  Examine the format of symbol table entries, and see what

Uh?  Static variables are allocated storage in a different place than
non-static variables.  Non-static local variables are allocated on the
stack, static variables along with the text.  I would expect the easiest
fix is a recompile.  If youy REALLY wanted to try it, you would have to
increase the length of the module, note where the new space is, then 
change EVERY reference to the variable to the new location.  This will
change the address mode you will use and the new instruction may be shorter
or longer than the instruction it replaces.  I wouldn't even attempt to
try this.  Ron.

-- 
| Ronald J. Srodawa               | Internet: srodawa@unix.secs.oakland.edu |
| School of Engineering and CS    | UUCP:     srodawa@egrunix.UUCP          |
| Oakland University              | Voice:    (313) 370-2247                |
| Rochester, Michigan  48309-4401 |                                         |

gwyn@smoke.brl.mil (Doug Gwyn) (11/03/90)

In article <3653@vela.acs.oakland.edu> srodawa@vela.acs.oakland.edu (Ron Srodawa) writes:
>Non-static local variables are allocated on the stack, ...

The original question concerned global, i.e., file-scope, identifiers,
not auto variables.  Use of the word "STATIC" is unfortunate, since in
C the "static" keyword is semantically overloaded.

cgy@cs.brown.edu (Curtis Yarvin) (11/05/90)

In article <3653@vela.acs.oakland.edu> srodawa@vela.acs.oakland.edu (Ron Srodawa) writes:
>In article <3693@skye.ed.ac.uk> richard@aiai.UUCP (Richard Tobin) writes:
>>In article <781@nixbur.UUCP> jobrien@nixbur.UUCP (John O'Brien) writes:
>>>Is there some way to change a symbol's class to "static" in a ".o" file?
>>
>>Almost certainly.  Examine the format of symbol table entries, and see what
>
>Uh?  Static variables are allocated storage in a different place than
>non-static variables.  Non-static local variables are allocated on the
>stack, static variables along with the text.  I would expect the easiest

It would appear we have a terrible misunderstanding here; so, before we get
an accidental flame war, let's break this thing up.  There are two things
you can do with the "static" keyword in C.  You can tell the compiler to keep
a _local_ variable in the data segment instead of the stack.  Or you can
prevent routines in other files from accessing a _global_ variable in a file.

	The first cannot be altered without a good disassembler.  The second
can.  Which the original poster was referring to is anyone's guess; maybe he
can post again & tell us.

		-Curtis

"I tried living in the real world
 Instead of a shell
 But I was bored before I even began." - The Smiths

jobrien@nixbur.UUCP (John O'Brien) (11/06/90)

>Uh?  Static variables are allocated storage in a different place than
>non-static variables.  Non-static local variables are allocated on the
>stack, static variables along with the text.  I would expect the easiest
>fix is a recompile.  If youy REALLY wanted to try it, you would have to
>increase the length of the module, note where the new space is, then 
>change EVERY reference to the variable to the new location.  This will
>change the address mode you will use and the new instruction may be shorter
>or longer than the instruction it replaces.  I wouldn't even attempt to
>try this.  Ron.

Actually I was much more concerned about the functions (which are always in 
the "text" section) than the variables.  My question was, if I did what I was
proposing to do, would symbols that been changed to static in big.o still be
visible throughout "big.o", and would they be exported to the linker?

I don't know COFF very well, but it seems to me that in the example I gave
it seems to me that the variables "c" and "d" would be in the "bss"
(uninitialized data) section whether or not they were static because they 
exist through out the program, and do not have initial values.  I just simply
want some control of which symbols are exported to the linker.

			John