One of my favorite passions from my teenage days was assembly language programming. Don't laugh.
It embodies a lot of my favorite things about programming: I have total control, it is clean and simple, and it is just and fast and functional as I am capable of making it. The only thing standing in the way of me and world domination is how well I can program.
Well, with some minor exceptions. Having a decent assembler is really key, and for x86 architectures, there are many choices. If you are hacking a small function together to support some higher-level language, then maybe you can get by using MASM (for Windows/DOS), or, if you really hate yourself, gas (for every platform).
But, if you intend to spend some time programming in assembly and not hating every minute of it, then you need to use NASM, probably the best assembler for the x86 family, ever (or possibly Yasm, a NASM clone that I have no experience with).
So, this past week I was interested in playing some more with NASM, and so I thought that I would see how what I could do under OS X (I previously worked primarily in DOS). Unfortunately, assembly language support in OS X is fairly hampered if you want follow its standard calling conventions for 32-bit x86 code. The innocuous-looking statement "The stack is 16-byte aligned at the point of function calls" seems innocent, but is a nightmare if you using external calls.
Basically, this means that you have to keep very close track of your stack size when calling functions. And even worse is that your stack never enters your function correctly aligned: the return address is always 4 bytes long, meaning you are always 12 bytes off when you start.
What this means is that I may have to use a VM with Linux to have any fun with assembly language programming again.
If anyone is interested, here is a quick NASM file I threw together that demonstrates how to use NASM on OS X to call glibc functions. I tested it with the latest NASM (2.07) on Snow Leopard (you'll probably need XCode installed to get this to work). This program prints "Hello World", allocates some memory using
malloc, uses that memory to write 10 letters of the alphabet on the screen (using
frees the memory, and returns.
; ; Basic OS X calls to glibc ; ; compile with: ; nasm -g -f macho malloc.asm ; gcc -o a.out malloc.o ; ; glibc stuff extern _puts, _printf, _malloc, _free ; static data segment .data hello_world_str db "Hello world!", 10, 0 int_str db "Address %x", 10, 0 ; code segment .text global _main _main: push ebp ; setup the frame mov ebp, esp sub esp, 4 ; align the stack push dword hello_world_str call _puts add esp, 4 ; malloc 16 bytes push dword 16 call _malloc add esp, 4 ; check if the malloc failed test eax, eax jz fail_exit sub esp, 0xC ; align the stack mov ebx, eax push ebx push dword int_str call _printf add esp, 8 add esp, 0xC ; print "A\nB\n..." mov [ebx], dword 0xD41 ; 'A\n' mov edi, 10 push ebx _loop: call _puts inc dword [ebx] dec edi jnz _loop add esp, 4 ; free the malloc'd memory push ebx call _free add esp, 4 add esp, 4 ; cleanup the stack pop ebp ret fail_exit: mov eax, 1 pop ebp ret
The output should look something like this:
Hello world! Address 100130 A B C D E F G H I J
Am I the only one who likes assembly language programming these days?