Team LiB
Previous Section Next Section

Finding Information About Libraries

Okay, so now that you know about libraries, the question is, how do you find out what libraries you have on your system and what they do? Well, let's skip that question for a minute and ask another question: How do programmers describe functions to each other in their documentation? Let's take a look at the function printf. Its calling interface (usually referred to as a prototype) looks like this:

int printf(char *string, ...);

In Linux, functions are described in the C programming language. In fact, most Linux programs are written in C. That is why most documentation and binary compatibility is defined using the C language. The interface to the printf function above is described using the C programming language.

This definition means that there is a function printf. The things inside the parenthesis are the function's parameters or arguments. The first parameter here is char *string. This means there is a parameter named string (the name isn't important, except to use for talking about it), which has a type char *.char means that it wants a single-byte character. The * after it means that it doesn't actually want a character as an argument, but instead it wants the address of a character or sequence of characters. If you look back at our helloworld program, you will notice that the function call looked like this:

 pushl $hello
 call  printf

So, we pushed the address of the hello string, rather than the actual characters. You might notice that we didn't push the length of the string. The way that printf found the end of the string was because we ended it with a null character (\0). Many functions work that way, especially C language functions. The int before the function definition tell what type of value the function will return in %eax when it returns. printf will return an int when it's through. Now, after the char *string, we have a series of periods, .... This means that it can take an indefinite number of additional arguments after the string. Most functions can only take a specified number of arguments. printf, however, can take many. It will look into the string parameter, and everywhere it sees the characters %s, it will look for another string from the stack to insert, and everywhere it sees %d it will look for a number from the stack to insert. This is best described using an example:

#PURPOSE:  This program is to demonstrate how to call printf
#

 .section .data

#This string is called the format string.  It's the first
#parameter, and printf uses it to find out how many parameters
#it was given, and what kind they are.
firststring:
 .ascii "Hello! %s is a %s who loves the number %d\n\0"
name:
 .ascii "Jonathan\0"
personstring:
 .ascii "person\0"
#This could also have been an .equ, but we decided to give it
#a real memory location just for kicks
numberloved:
 .long 3

 .section .text
 .globl _start
_start:
 #note that the parameters are passed in the
 #reverse order that they are listed in the
 #function's prototype.
 pushl numberloved    #This is the %d
 pushl $personstring  #This is the second %s
 pushl $name          #This is the first %s
 pushl $firststring   #This is the format string
                      #in the prototype
 call printf

 pushl $0
 call  exit

Type it in with the filename printf-example.s, and then do the following commands:

as printf-example.s -o printf-example.o
ld printf-example.o -o printf-example -lc \
   -dynamic-linker /lib/ld-linux.so.2

Then run the program with ./printf-example, and it should say this:

Hello! Jonathan is a person who loves the number 3

Now, if you look at the code, you'll see that we actually push the format string last, even though it's the first parameter listed. You always push a functions parameters in reverse order.[2] You may be wondering how the printf function knows how many parameters there are. Well, it searches through your string, and counts how many %ds and %ss it finds, and then grabs that number of parameters from the stack. If the parameter matches a %d, it treats it as a number, and if it matches a %s, it treats it as a pointer to a null-terminated string. printf has many more features than this, but these are the most-used ones. So, as you can see, printf can make output a lot easier, but it also has a lot of overhead, because it has to count the number of characters in the string, look through it for all of the control characters it needs to replace, pull them off the stack, convert them to a suitable representation (numbers have to be converted to strings, etc), and stick them all together appropriately.

We've seen how to use the C programming language prototypes to call library functions. To use them effectively, however, you need to know several more of the possible data types for reading functions. Here are the main ones:

int

long

long long

short

char

float

.double

unsigned

*

struct

typedef

That's how to read function documentation. Now, let's get back to the question of how to find out about libraries. Most of your system libraries are in /usr/lib or /lib. If you want to just see what symbols they define, just run objdump -R FILENAME where FILENAME is the full path to the library. The output of that isn't too helpful, though, for finding an interface that you might need. Usually, you have to know what library you want at the beginning, and then just read the documentation. Most libraries have manuals or man pages for their functions. The web is the best source of documentation for libraries. Most libraries from the GNU project also have info pages on them, which are a little more thorough than man pages.

[2]The reason that parameters are pushed in the reverse order is because of functions which take a variable number of parameters like printf. The parameters pushed in last will be in a known position relative to the top of the stack. The program can then use these parameters to determine where on the stack the additional arguments are, and what type they are. For example, printf uses the format string to determine how many other parameters are being sent. If we pushed the known arguments first, you wouldn't be able to tell where they were on the stack.


Team LiB
Previous Section Next Section