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…

Published: November 26th, 2009 at 22:44
Categories: C, LISP, OS X