Thursday 3 June 2010

The Quest for a Small Mach-O

For my sins I have recently actually enjoyed using OS X. There is just something about its unix'ness which appeals to me (though I would rather not have to pay for it to begin with). Anyway one of the first things I tend to do on an OS is to try and write as small an executable as possible and this is not the time to change that.

So this is maybe the first post of many on creating something small :) Note: I am working on Snow Leopard and producing 32bit code, YMMV.

Step 1: What can we do with basic tools?

So lets start with a normal development environment to see what we can get without having to writing anything custom. Before we can do anything we need some code, here is a simple entry point with no reliance on external libraries, just straight into the exit syscall.
void start(void) {
// Call exit(0)
__asm__ volatile (
"push $0\n"
"movl $1, %eax\n"
"int $0x80\n"
);
}
It is worth pointing out that without this exit syscall your new application will just SIGBUS, not exactly optimal.

Now just need to link it, we will choose to link statically (which should get rid of anything to do with the dynamic linker, which might have to change as we go along).
all: test1

test1: test1.c
$(CC) -c -o test1.o test1.c
$(LD) -o test1 -s -static -e _start test1.o

clean:
rm -f test1 *.o
And our survey says? 4096 bytes, bugger. Well I guess page alignment is a killer. Of course using hexdump shows that over 3/4 of the file is empty. Still there is some hope for the future, running otool -lv over the output application shows that the entire 4k is being loaded into memory, a classic trick in making small binaries. Some nice sounding options in the ld man page (such as -pagezero_size and -seg_page_size) just don't seem to work as expected so no doubt something more custom is required next time.

Onwards and upwards.