Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Email:

Dissecting Shared Libraries

By Peter Seebach
2005-03-22


To debug, first you must know how to compile

To debug problems with shared libraries, it's useful to know a little more about how they're compiled.

In a traditional static library, the code generated is usually bound together into a library file with a name ending in .a and then it's passed to the linker. In a dynamic library, the library file's name generally ends in .so. The file structures are somewhat different.

A normal static library is in a format created by the ar utility, which is basically a very simple-minded archive program, similar to tar but simpler. In contrast, shared libraries are generally stored in more complicated file formats.

On modern Linux systems, this generally means the ELF binary format (Executable and Linkable Format). In ELF, each file is made up of one ELF header followed by zero or some segments and zero or some sections. The segments contain information necessary for runtime execution of the file, while sections contain important data for linking and relocation. Each byte in the entire file is taken by no more than one section at a time, but there can be orphan bytes that are not covered by a section. Normally in a UNIX executable, one or more sections are enclosed in one segment.

The ELF format has specifications for applications and libraries. The library format is a lot more complicated than just a simple archive of object modules, though.

The linker sorts through references to symbols, making notes about in which libraries they were found. Symbols from static libraries are added to the final executable; symbols from shared libraries are put into the PLT, and references to the PLT are created. Once those tasks are done, the resulting executable has a list of symbols it plans to look up from libraries it will load at runtime.

At runtime, the application loads the dynamic linker. In fact, the dynamic linker itself uses the same kind of versioning as the shared libraries. On SUSE Linux 9.1, for instance, the file /lib/ld-linux.so.2 is a symbolic link to /lib/ld-linux.so.2.3.3. On the other hand, a program looking for /lib/ld-linux.so.1 won't try to use the new version.

The dynamic linker then gets to do all the fun work. It looks to see which libraries (and which versions) a program was originally linked to and then loads them. Loading a library consists of:

• Finding it (and it may be in any of several directories on a system)
• Mapping it into the program's address space
• Allocating blocks of zero-filled memory the library may need
• Attaching the library's symbol table

Debugging this process can be difficult. There are a few kinds of problems you can encounter. For example, if the dynamic linker can't find a given library, it will abort loading the program. If it finds all the libraries it wants but can't find a symbol, it can abort for that too (but it may not act until the actual attempt to reference that symbol occurs) -- this is rare case though because normally, if the symbol isn't there, it will be noticed during the initial link.

Tutorial Pages:
» Get to know your shared library
» How shared libraries work
» Compatibility's not just for relationships
» To debug, first you must know how to compile
» Modifying the dynamic linker search path
» Linking Mozilla
» Learning more about shared libraries
» Resources


First published by IBM DeveloperWorks


 | Bookmark
Related Tutorials:
» How to Install PHP 5 on Linux
» How to Install Apache 2 on Linux
» How to Install MySQL 5.0 on Linux
» SMB Caching
» Mound --Bind
» Tar Wild Card Interpretation

Ask A Question
characters left.