One approach is to have the shared object implement a well known function that is called when the object is loaded. For example, a shared object must implement a function with the prototype, char **functions(); This function returns a NULL terminated array of (C-style) strings naming the functions available in the shared object. The program loading the shared object calls this function and stores the array returned for future reference. The shared object implementer can use any mechanism to build the array of strings, even just maintaining the array by hand. To handle parameters and different return values, the strings may be augmented with the return and parameter types, but that is not required to get full credit on the question.