Wednesday, April 30, 2008

Creating and Using .so Files With gcc

And what is an .so file you might ask? Those from a Windows background might know them as .dll files, but that still doesn't answer the question.

Normally, when you compile a program, the system takes all of the pieces of code that you've written, converts them into something the computer can understand (machine code) and glues them together. You might compare the process to building a pyramid. All of the stones that you've sculpted are joined together and stacked up. Just like with a pyramid, if you want to change one of the stones, everything that sits on top of it needs to be adjusted. With a C program, making changes in a piece of code means lots of pieces need to be recompiled and reglued together.

If you use dynamic linking, shared libraries, whatever you'd like to call them, things work a bit differently. With dynamic linking, the pieces are not all glued together or stacked up, instead they are plugged in when they are needed. As a result, changes to a piece of code don't require that lots of other pieces get reshaped (recompiled) to fit. With dynamic linking, it is possible to change a piece of code while the program is running. Funny, that sounds a bit like a scripting language.

Here's an example. Let's say I wrote a library with a function called SpecialPrint. (It's like printf but different!) Here is the code for speciallib.c:

void SpecialPrint(char* payload) {
printf("Special Print:%s\n", payload);
Now I write a program that uses this library. Here's the normal, non-dynamic, static linking, built like a pyramid way of using the library.

int main() {
printf("normal printf argument\n");
SpecialPrint("special print's argument");
With the above code, I compile the SpecialPrint library with my main code and link them together, producing a single executable file. However, I can use the same speciallib file with code that loads the library dynamically while the program is running. The code might look something like this:

void ShowError() {
char *dlError = dlerror();
if(dlError) printf("Error with dl function: %s\n", dlError);

int main() {
void *SharedObjectFile;
void (*SpecialPrintFunction)(char*);

// Load the shared libary;
SharedObjectFile = dlopen("./", RTLD_LAZY);
// Obtain the address of a function in the shared library.
SpecialPrintFunction = dlsym(SharedObjectFile, "SpecialPrint");

printf("normal printf argument\n");
// Use the dynamically loaded function.
(*SpecialPrintFunction)("special print's argument");

In the above, the show error function is optional, I added it so that any errors that occur would be displayed. When you compile the above code, you'll need to make the speciallib into an .so file and make sure that the speciallib's directory (the current directory in my example) is listed as one of the places that we should look for shared object files. Here's what the steps to compile look like:
export LD_LIBRARY_PATH=`pwd`
gcc -c -fpic speciallib.c
gcc -shared -lc -o speciallib.o
gcc main.c -ldl
For an explanation of what the above compiler options mean, and further explanation on .so files, see these two IBM articles on using shared object files on Solaris and linux.

Learning about .so files has been very interesting to me, because they bring a new level of flexibility to a traditionally rigid environment like C.


amcclosky said...

more fun with function pointers I see. Now it would be nice if someone would make this stuff easy to use in C or at least prettier. :)

Jeff Scudder said...

I've thought that too, perhaps something called easy C. In languages like Java and Python, most identifiers are actually more like pointers, but C allows/forces you to make an explicit distinction. Maybe the easy thing to do would be to make all identifiers pointers, but I'm very curious to see the impact this would have on performance.

Anon said...

thanks for the article,
i am also writing about coding in my blog and stuff, its

i'm not really going for self-promotion, but it would be cool to have someone read the damn thing, and I liked your post, so maybe you'll enjoy some of mine.