OSX, SBCL and FFI, Part 1.
This is the first post in the quest for a better understanding of how SBCL and its FFI (foreign function interface) mechanism allows it to dynamically load any qualifying library and then be able to wrap it and call it. This is an extremely powerful feature that pretty much every modern LISP has and it means that with a bit of effort to generate a suitable binding, you can leverage thousands of existing C libraries. You only have to visit cliki.net to see what I mean.
A Simple Library
The first step in the chain is to be able to have a small library with a couple of functions in it that we can play with and ultimately wrap with the FFI mechanism, so to that end I present this little snippet that has just two functions, one that increments a number and one that adds two numbers together. I have deliberately kept it simple and avoided any functions that use strings or that allocate memory; those things are not the purpose of this post or the follow-ups.
Create a file called “libtest.c” and paste the following code into it :-
1 2 3 4 5 6 7 8 9 | int add1( int n ) { return n+1; } int add2( int n1, int n2 ) { return n1+n2; } |
Building the library…
To compile and build a dynamic library (dylib) on OS X, use the following gcc invocation:
gcc -arch i386 -c libtest.c
This will result in a file called “libtest.o” being created, and then to convert that object file into a dynamic library issue this command:
gcc -arch i386 -dynamiclib -o libtest.dylib libtest.o
If all has gone well then you should have a file called libtest.dylib in the same folder. If you want to see what it contains then you can issue this command and see the following output :-
[scharles]cffi $ otool -tv libtest.dylib libtest.dylib: (__TEXT,__text) section dyld_stub_binding_helper: 00000fc4 calll 0x00000fc9 00000fc9 popl %eax 00000fca pushl 0x00000037(%eax) 00000fd0 movl 0x0000003b(%eax),%eax 00000fd6 jmp *%eax __dyld_func_lookup: 00000fd8 calll 0x00000fdd 00000fdd popl %eax 00000fde movl 0x0000002b(%eax),%eax 00000fe4 jmp *%eax _add1: 00000fe6 pushl %ebp 00000fe7 movl %esp,%ebp 00000fe9 subl $0x08,%esp 00000fec movl 0x08(%ebp),%eax 00000fef incl %eax 00000ff0 leave 00000ff1 ret _add2: 00000ff2 pushl %ebp 00000ff3 movl %esp,%ebp 00000ff5 subl $0x08,%esp 00000ff8 movl 0x0c(%ebp),%eax 00000ffb addl 0x08(%ebp),%eax 00000ffe leave 00000fff ret
So there it is, the disassembled output of the shared library, there are our two functions which have been name mangled into “_add1″ and “_add2″ and there are two utility functions that are used by the dlopen() and dlsym() functions to load and locate entry points.
Summary
So in this lesson we have learned how to create a really simple shared library that could be loaded into an SBCL session… but first, just to prove that it is in fact usable I thought it would be good to write a tiny little C program that can dynamically load this library and test that the functions actually do what they say on the tin, that way we can have complete confidence in the underlying shared library when we are in SBCL.
So, on to part 2, where we test the library…