Here is a note from a coworker regarding shared libraries.  It covers
this in some detail (thanks Joe!):

	Building Well Behaved Shared Objects On Solaris 2.x 

[ This note assumes the reader already has a passing understanding of
shared objects.  For a good discussion on this topic take a look at
the SunOS 5.x Linker and Libraries Manual (Part No. 801-2869-10). ]

Shared objects (aka dynamic or shared libraries) have become an
essential component of software development here at Sun, and while
most engineers have a passing understanding of how they work
relatively few know how to generate one, and even fewer know how to
generate a well behaved one.

What is a well behaved shared object?  It is one that has the
following characteristics:

	1. It is self contained.

	2. It is versioned.

	3. It is shareable.

Let's look at these characteristics in a bit more detail.

1. Self Contained

	Historically libraries have not been self contained.
	I.e. when you linked with a library you were forced to know
	what libraries it depended on and add those to your link line
	as well. This is bad for two reasons:

	1. It is inconvenient to the library user. But more importantly:

	2. It exposes the library's implementation to the library
	   user.  For example an XView client should not need to know
	   that libxview requires libolgx. XView clients don't make
	   calls to libolgx, and at some point in the future XView may
	   change its implementation and use something other than
	   libolgx.  If this happens previous link lines will no
	   longer be correct.  (As it turns out libxview is currently
	   not self contained so we need to specify "-lolgx" on our
	   application link lines.  A bad thing).

	So any symbols a shared object requires should be resolved at
	its link time (the shared objects link time, not the
	executable's).  Also a hint as to the location of these
	libraries should also be specified so the end user isn't
	required to set LD_LIBRARY_PATH to find them at runtime.

	There is one thing to note here.  In the example above if my
	XView client was unusual and happened to make libolgx calls
	directly then I would still need to specify "-lolgx" on my
	link line even if XView was self contained.  The loader
	insists that you explicitly specify any interfaces you use.
	You can't "inherit" them from libxview's dependency list since
	they are part of libxview's implementation, not its interface.
2. Versioned

	Since shared objects are loaded at run time the loader must be
	able to distinguish incompatible versions of a library.  This
	is controlled by a version number associated with the shared
	object's name which is embedded in the shared object.  You
	increment the version number any time you make an incompatible
	change to the library's interface.

3. Shareability

	There are a number of things you can do when writing a shared
	object to maximize shareability.  These are covered in the
	Linker and Library Manual.  There are a couple of things you
	can do at link time that are described below.

So how do I build a well behaved shared object?

You do it in 3 steps:

Step 1: Compile the .c's into .o's.

	For example:

	cc -c -O -K pic -xstrconst -I/usr/openwin/include foo.c -o foo.o

	Two points here:

	-K pic 		(or -K PIC, see cc man page) produces 
			position-independent code that is required
			for shared objects.

	-xstrconst	Forces string literals into the text segment
			of the object file.  This makes them shareable.

Step 2: Link the .o(s) into the .so 

	For example:

	cc -G -z text -z defs -h -i -R/usr/openwin/lib \
		foo.o -L/usr/openwin/lib -lc -lnsl -lX11 -o

	Lots of stuff here:

	cc 		Use cc (not ld) to generate the shared object.
			This makes sure that the .init and .fini
			sections of the shared object are correctly
			initialized.  For C++ use CC instead of ld.

	-G 		Tells ld to produce a shared object

	-z text 	Enforces shareability of the text segment.
			This generates an error if any relocations
			against the text segment remain.  These
			relocations are bad because they force a
			copy-on-write at runtime of the *entire* text
			segment which eliminates shareability.

			What could trigger these relocations?  The
			simple case is if you forget to specify -K pic
			when compiling the .o's.  Another more subtle
			example is if you initialize a constant
			pointer function like this (thanks to Bart
			Smaalders for the example):

			typedef int (*fp)();
			extern int foo();
			const fp fun = & foo;

			In this case "-z text" would cause the link to
			fail because in a shared library, the address
			of foo is (likely) different for each process,
			hence fun cannot be declared const and placed
			in the text segment.  If you don't specify "-z
			text" then the link would have worked, but
			parts of your .so would not be shareable and
			would need patching at runtime.

	-z defs 	Ensures the shared object is self contained by 
			generating an error if any undefined symbols
			remain at the end of the link.

	-h	For versioning. "2" is the version number. This
			records "" in the shared object (in the
			SONAME field). Any executables that link with this
			shared object will require "" at runtime.

			is used to influence runtime behavior and -i
			prevents it from interfering with our link
			step.  (It will still have effect at runtime).
			It's a good idea to use this when building
			executables as well.

			Specifies a search path for locating the
			libraries libfoo depends on at runtime.  This
			is so end users don't have to set
			LD_LIBRARY_PATH at runtime.  Use -R when
			building executables as well. The goal is for
			users to never have to set LD_LIBRARY_PATH if
			they install stuff in the default locations.
			This value is stored in the RPATH field of the
			shared object.

	-L/usr/openwin/lib	For self containment.  Specifies the
	-lc -lnsl -lXll         libraries this shared object
				requires. '-z defs' makes sure we get
				this right. 

Step 3: Install the shared object.

	mcs -d
	mcs -a "Whatever comment string you want to add"
	install -m 755 -f $DESTDIR/lib
	ln -s ./ $DESTDIR/lib/

	mcs -d	Strips the rather lengthy .comment section
				from the shared object.  This is to save
				disk space only.  It has no effect on the
				runtime image.  This should be done on
				executables too.

	mcs -a "..."		Adds a short comment if you so desire.
				mcs -p will print the comment section.

	install -m 755 ...	Copy shared object to the destination directory

	ln -s ./ ...	Create a symbolic link that is the name
				of the library minus the version number.
				Why?  Because when a user specifies "-lfoo"
				at link time the linker looks for
				"" -- no version number.  But at
				runtime we need the name with the version 

That's it.  You are done!  Make sure you understand all of the above
as your project may have different requirements.

You can use dump(1) to peak inside a shared object to get all sorts of
useful information like what other shared objects it depends on, its name,
the run path, etc.  (Don't confuse dump(1) with the 4.x backup utility of
the same name).

sidewinder$ dump -Lv
.dynamic :
[INDEX] Tag      Value
[1]     NEEDED
[2]     NEEDED
[3]     NEEDED
[4]     NEEDED
[5]     NEEDED
[6]     SONAME
[7]     RPATH    /usr/openwin/lib/X11:/usr/openwin/lib
[8]     HASH     0x94
[9]     STRTAB   0x52b4
[10]    SYMTAB   0x1bc4
[11]    STRSZ    0x3494
[12]    SYMENT   0x10
[13]    PLTGOT   0x60d10
[14]    PLTSZ    0xef4
[15]    PLTREL   0x7
[16]    JMPREL   0xb85c
[17]    RELA     0x8748
[18]    RELASZ   0x4008
[19]    RELAENT  0xc

Application binary:
static linking:
dynamic linking:

Q. What is a shared library?

A. A shared library, or shared object file, or dynamic library, is a file in
   the ELF file format (see elf(3E)) that contains data and usually code
   that is needed by application binaries. It, along with any other shared
   libraries an application binary depends on, is transparently loaded into
   memory when the binary is executed, making itself available to the

Q. What are the advantages of shared libraries?

A. The major advantage of a shared library is that it may contain code that
   more than one binary depends on. Thus, this code is only stored once,
   in the shared library, and not in each individual binary. This saves
   storage space on disk, especially when dealing with very common code
   that nearly every program needs. But the benefits go farther than the
   space savings: if the common code needs to be updated (for example, a
   patch to fix a bug), this need only be done once, in the shared library.
   (There are also more reasons, covered below).

   Another big advantage is that programs which use the non shared versions
   of the system supplied libraries like libc, are not supported and are
   not ABI compliant. See "Why does my program, statically linked under a
   different version of Solaris, dump core?" and "Why do I get unresolved
   references when trying to link statically?"

Q. What are the disadvantages of shared libraries?

A. It takes time for a program to load all of the shared library files it
   needs and to link them to the main program and to other shared libraries
   (called dynamic linking). The program will take longer to start up.

   Programs that depend on shared libraries will not work if any of the
   libraries they depend upon are not available. For people who distribute
   software, this often means developers must restrict themselves to using
   only the shared libraries that are sure to be present on every system.
   Unfortunately of course, nothing is for sure and according to Murphy's
   law, there will always be someone who doesn't have whatever library,
   or has a different version that the developers used and the different
   version doesn't work properly. Arguably, it is cleaner (more elegant)
   to have a program that is self contained and requires nothing but

   Finally, the system must be able to locate the require libraries
   wherever they may be, which is, again, error prone. (See "What

Q. What systems can use shared libraries?

A. The model of shared libraries described in this document comes from
   AT&T's System V UNIX operating system and is used in derivatives of
   this OS, including Solaris. Other systems may implement shared
   libraries slightly differently, but the concept is always the same.
   Shared libraries resemble Microsoft Windows .DLL (Dynamic Load
   Library) files.

Q. What does a shared object file look like?

A. Shared object files have the .so (for shared object) extension. They
   often have a numerical extension on top of that. The file(1) command
   will tell you if a file is a shared library (it will say "dynamic
   lib") by examing its contents.

Q. How are shared libraries used in Solaris?

A. Almost all of the binaries that come with Solaris (such as the ones
   found in the /usr/bin directory) are dynamically linked, which
   means they depend on shared libraries to execute. The only ones
   which aren't are a few critical system programs that may need to
   be (or must) run at times when the shared libraries cannot be
   used, such as very early in the boot process. Note that
   technically, the kernel is such an exceptional program.

   Solaris also uses shared libraries in another way than simply
   loading a set of required libraries when run as described in
   the first question. By their nature, shared libraries can be
   opened and imported into a running program at any time. As an
   example of this, take the getpwnam(3C) function. This function
   returns information about a user including her user id and the
   name of her home directory. It looks in the /etc/nsswitch.conf
   file (see nsswitch.conf(4)) to determine what access method to
   use to find this information. It might look in files (the
   /etc/passwd file), NIS (Network Information name Service, aka
   yp), or NIS+ (New version of NIS). (It would also be possible
   to define another access method, but nobody has done this).
   After having looked in the nsswitch.conf file, the getpwnam
   function loads a shared library with the name
   where "database" is the name of whichever access method was
   found in nsswitch.conf. Each access method has a corresponding
   file:,, (you
   can see these files by typing "ls /usr/lib".) Each shared
   library file contains the same set of functions so that
   functions like getpwnam is able to call them all the same way,
   but each version of the functions searches a different
   database. To summarize, it is possible to select one or another
   version of a set of alternative functions by loading one or
   another shared library containing the same function, depending
   on values found in a configuration file, or even depending on
   user input.

   The above "trick" is used not only to select multiple databases
   for a database lookup, but also to select mutiple similar network
   protocols in much the same way.


A. LD_LIBRARY_PATH is an environment variable that tells the system where
   to find shared libraies when they are needed, if the program itself
   does not specify this information. You can view the current value of
   this variable by typing "echo $LD_LIBRARY_PATH" in a shell. The
   contents consist of a colon separated list of directories to search
   sequentially. If it is not set, the default is "/usr/lib".

   If LD_LIBRARY_PATH does not list the directory where a particular
   required library is found, and the program which requires this
   binary does not specify which directory to find it in either, then
   the program will abort. For this reason, it is considered good
   practice, when making programs, to have the program specify to
   the dynamic linker where its libraries may be found if they
   are not found in the standard directory /usr/lib. In this way, no
   program should depend on the correct setting of LD_LIBRARY_PATH.
   A program can be considered broken, or at the very least, lacking
   robustness, if it doesn't work without LD_LIBRARY_PATH set. (See also
   "Why should I use -R?")

Q. So should I use shared libraries?

A. For the system libraries, the answer is certainly yes. You should not
   link with the static versions of libraries like libc (See "Why does
   my program, statically linker under a different version of Solaris,
   dump core?" and "Why do I get unresolved references when trying to link

   For libraries you create yourself or are otherwise not part of Solaris,
   it will depend. A few examples of public domain or shareware packages
   which have libraries is in order:

   pbmplus: pbmplus, which is a suite of graphics format converters plus
   a few other goodies, includes over 100 binaries (e.g. giftoppm,
   pnmtotiff). All of them share a substantial amount of common code
   for dealing with the package's internal representation of graphics.
   A lot of space could be wasted by storing this code 100 times on
   your disk. The common code can be placed in a shared library. When
   this is done, each individual binary can be smaller than 10K while
   it might otherwise have been over 20K with all the common code
   statically linked in. The tradeoff for this is that pbmplus does
   not support the creation of shared libraries for this purpose. It
   takes a fair amount of Makefile editing to get this to work.

   elm: elm, a popular Mail User Agent, includes as part of the source,
   a (static) library libutil.a. This library is used only a few times,
   always in programs that are part of the ELM package. Few of the
   advantages of shared libraries exist in this case. Given the extra
   overhead of loading shared libraries at run time and the need to
   compile them as position independant code, it probably isn't worth
   making a shared library out of this.

Q. How are shared libraries implemented at a low level?

A. Programs are either dynamically linked or statically linked. Statically
   linked programs cannot load shared libraries. Dynamically linked
   programs usually do.

   When a statically linked program is run, it is loaded into memory, and
   the processor jumps to a set location in the program which performs
   program initialization. For C programs, this function sets things up
   and then calls the program's main() function.

   When a dynamically linked program is run, it is also loaded into
   memory, but control is not transfered to a set location in the
   program. Instead, the program contains the name of an interpreter
   under which it should run. In practice, there is only one
   interpreter, called /usr/lib/ This file is known as the
   dynamic linker and is a *VERY* critical file for the operation of
   a system!

   The dynamic linker read the information that was recorded in the
   program when it was made and loads the apropriate shared libraries.
   It uses the LD_LIBRARY_PATH environment variabe (described above)
   to locate them. It also uses LD_RUN_PATH. This paramater serves a
   similar function, but it comes from the program, not the
   environment. Thus the program can itself specify directories where
   the dynamic linker should look without absolutely depending on
   the proper setting of LD_LIBRARY_PATH.

   Shared libraries are mapped into virtual memory using the
   mmap(2) system call.

   Once the loading process is complete, control is transferred to a
   special function in the main program and we continue as with a
   statically linked program.

Q. How do I make a shared library?

A. Making a shared library is a lot like making a regular library, but
   there are a few differences. First of all, you should probably
   compile your code in a position independant fashion. Here's why:
   Normally, compilers make relocatable code. Because a set of
   assembly language instructions (a program) usually needs to know
   where in memory it is being executed from but it cannot be
   predicted when a program is created where in memory it will be
   loaded when it is run, compilers must generate almost all of the
   code for a program, and leave the rest to be filled in once it
   is known where the program has been loaded, at run time. For
   this purpose, they prepare and include in the program tables of
   the locations that need adjusting.

   If a shared library uses relocatable code, then this relocation
   must be performed every time the shared library is loaded into
   a new program, at a new place in memory. Thus each copy of the
   shared library in memory is slightly different after the
   relocation has taken place.

   If relocation wasn't required, then all copies of a shared object
   in memory would be identical, and in fact, it would be possible
   for all programs simultaneously requiring the same shared library
   to share the same copy in memory (thus the name "shared" library).
   This a a very huge advantage of shared libraries.

   In fact, this is possible if position independant code is
   generated. Position Independant Code (PIC) is less efficient
   than normal relocatable code because programs must sometimes
   use alternate methods of performing the same tasks. However, no
   code needs to be modified at run time, as indicated above.

   With the Sun C compiler, supply the "-K pic" option on the cc
   command line. With the GNU compiler, supply the "-fPIC" option
   on the gcc command line.

   Finally, once your code is compiled, you can create a shared
   object file as follows. ("-z text" is optional, but usually a
   good idea. It ensures that your code os really position

   ld -G -z text -o

Q. Why should I use -R when linking programs?

A. The -R option to the linker allows you to specify directories (one
   per occurence or -R) where the program being linked should look for
   its shared libraries when it is run. It should be used whenever a
   program requires libraries stored in directories other than /usr/lib,
   so that the program will find all the libraries it needs.

   Note that a similar effect can be achieved by using the LD_LIBRARY_PATH
   variable (See "What is LD_LIBRARY_PATH"), but depending on this is
   very strongly discouraged because the program will always depend
   on this variable being set correctly and it will fail to run whenever
   it isn't!

   On a properly configured system, all programs have been linked with
   -R if they need libraries from elsewhere than /usr/lib, and
   LD_LIBRARY_PATH need not be used.

Q. What are the numerical extensions on shared objects for?

A. The numerical extensions (e.g. indicate version numbers.
   Each time a new and incompatible version of a shared library is
   created, the version is incremented. The old version should be kept
   around for the sake of programs that were linked with the previous

   When making a program, the linker will look for shared libraries by
   the extention ".so". Thus, for libraries which have numerical extensions,
   there should be a symbolic link ending in .so pointing to the desired
   version of the library (the most recent), e.g. -->

   Note that the version number of a shared library should only be
   changed when the library's interface changes. Changes in the
   implementation do not matter to programs using the library, so it
   is possible to, say, optimize the code in a library, thereby
   optimizing every program that uses the library, without changing
   the version number.

   Also, when a shared library is produced, and the above numerical
   version and symbolic link convention will be used, the -h options
   needs to be supplied to the linker. The argument to -h is the filename
   which programs linked with the new library should look for to find the
   library. It should be the name the library will be installed under.

   If a library was not made using -h, then the name under which programs
   using that library will look for it under is the name under which
   the linker found the library when those programs were produced.
   This is the .so file (since the linker only scans for .so files),
   which is a symbolic link to the most recent version. This is bad
   because the most recent version may not be the same one the program
   was linked against, and if not, it will end up trying to use an
   incompatible version. Using -h with the canonical name of the library
   forces the program to always load the same version of the library.

Q. Why does my program, statically linked under a different version of
   Solaris, dump core?

A. Statically linked programs do not comply with the Solaris Application
   Binary Interface (ABI). This means that it is not supported. The C
   library and a number of the other libraries that come with the OS
   contain code that assumes things which may change from one version
   of Solaris to another. Normally, this is reasonable because programs
   are dynamically linked and they always fetch the apropriate code
   from the libraries that exist on the system where the program is
   run. But this doesn't work for statically linked programs, because
   they use whatever code they were statically linked with.

Q. Why do I get unresolved references when trying to link statically?
Q. Why is there no "libdl.a"?

A. As described in "How are shared libraries used in Solaris?",
   functions like getpwnam() dynamically link code when they are called
   by programs, depending on which sources the system is configured
   to use. In statically linked programs, there is no dynamic linker
   available, yet these functions try to use it. This is what the
   linker complains about.

   The recommended way to circumvent this is, of course, to link
   dynamically. However, here's another workaround if you must use
   it (don't distribute programs you make like this unless you enjoy

   A command line like this will make a dynamically linked program
   but which uses functions in static system libraries:

       cc -Bstatic ....  -Bdynamic -ldl -Bstatic

   See also Question 6.21 in the Solaris FAQ

Q. Where can I find X shared library?

A. The standard shared libraries that come with Solaris follow. There
   should never be a problem locating the ones in /usr/lib. The others
   may not be found if $LD_LIBRARY_PATH does not contain their
   directory and the program does not suggest a search location itself.
   For these cases, you can add the apropriate directory to
   LD_LIBRARY_PATH (See "What is LD_LIBRARY_PATH?"). You may, of course
   have additional libraries if you've installed software other than
   the basic Solaris environment.



A library can either be: shared object (.so) OR relocatable archive (.a)
If you use the file command on your favorite a.out's,
you'll notice that they're all usually of this format:

"ELF 32-bit MSB executable SPARC Version 1, dynamically linked,

To view these dynamically linked libraries, do "ldd a.out", and you'll
get a list of these libs.

ld - combines relocatable object files, performs relocation and
resolves external symbols.

[from the man pages]

static: -dn: relocatable object files -> executable [static] obj files
		[the default when using static is -a which produces an
		 executable obj file]

	-r: relocatable obj files -> ONE relocatable obj. file
		[-a and -r cannot be used with each other]

	-dy (default for ld): relocatable obj files (given as args)
		-> combined to produce an executable dynamic obj file
		that will be linked @ execution with any shared obj
		files given as arguments

	-G: relocatable obj files are combined to produce a shared


Question: Difference b/w a shared object and an executable obj file?

Ans: you can actually execute an executable obj file. Try it! (see
below, although nothing interesting happens)


Question: How do I force compilation of my programs with static
libraries ONLY?

ANS: Compile with -static option. If you then do a file on a.out,
you'll see : ELF 32-bit MSB executable SPARC version 1, statically
linked, not stripped.


Question: What do you do with an executable object file?

ANS: Not sure but here's how you get one:
	ld -r one.o -o as {<- executable obj. file name}

[ "file as" -> ELF 32-bit MSB relocatable SPARC Version 1 ]
OR	ld -dn one.o -o as -lc 

[ "file as" -> ELF 32-bit MSB executable SPARC Version 1, statically
linked, not stripped]

OR	ld -r one.o two.o -o as (combine multiple ones)

Now try executing as! Weird, don't know how to get it to work right now.


Question: How do I get a statically linked executable?

Ans: If you have an obj file: e.g., one.o
 then you do:
	ld -dn one.o -lc [-dn links statically & -lc says which
library to link to]

[If you leave out the -lc, you'll get:
Undefined                       first referenced
 symbol                             in file
printf                              one.o
ld: fatal: Symbol referencing errors. No output written to a.out]

file a.out = ELF 32-bit MSB executable SPARC Version 1, statically
linked, not stripped

Now, try executing a.out. You'll get 
Segmentation fault (core dumped)

Not bad! You executed a program w/o a main!


Question: How do I get a dynamically linked executable from obj files?

Ans: First gcc -c one.c two.c main.c to get obj files.
	ld -dy one.o two.o main.o -lc
file a.out = ELF 32-bit MSB executable SPARC Version 1, dynamically
linked, not stripped

Now you can actually run this program but it core dumps at the end.


Question: How do I create shared libs?

Ans: Let's use one.c and two.c. Look at them below. First thing, we
make them into regular obj files using gcc. But we also use -fPIC
option to generate something called Position Independent Code.

	gcc -c one.c two.c -fPIC
 [doing file on one.o gives: ELF 32-bit MSB relocatable SPARC Version 1]

Now, we will combine both obj files into one obj file using ld:

	ld -r one.o two.o -o cool.o } combines obj files
 [doing 'file cool.o' gives: ELF 32-bit MSB relocatable SPARC Version 1]

Now, we will create the shared object:

	ld -G -z text -o cool.o
 [doing 'file' gives: ELF 32-bit MSB dynamic lib SPARC Version
1, dynamically linked, not stripped]



Now, you can use this shared lib wherever.

Ex. Take main.c below.

Do: gcc main.c -R directory/where/shared/object/is

  The -R option is used at runtime to determine where the shared
object is. OR you can just compile w/o it: gcc main.c
 but you MUST SET LD_LIBRARY_PATH equal to the directory where your
shared object is. Not doing so will result in this famous error: ./a.out: fatal: can't open file: errno=2

If you do "ldd a.out", you'll see why you get this error: =>       (not found) =>     /usr/lib/ =>    /usr/lib/

[If LD_LIBRARY_PATH is NOT set, as is the case most of the time, then
ONLY /usr/lib is searched for .so files]

Versioning shared objs:
If you're going to have multiple versions of shared libs, then best to
create them using this form of the ld command:

ld  -G -z text -z defs -h -i -L -llibs

OTHER IMPORTANT COMMANDS: ldd, ranlib, ar, gcc				

Programs used:


print_a() {




print_b() {





extern void print_a(void);

extern void print_b(void);

main() {