April 10, 2014 - System Calls from C

April 12, 2014
System Calls from C
A few days ago I wrote a super simple program that read data coming from the Hanvon Graphicpal and interpreted the data, outputing the coordinates of the stylus on the pad.
I wrote the program to use no standard C library calls except for __syscall().
__syscall() is part of the FreeBSD libc, and is used to make an indirect system call.
This is a cool, interesting, and fun way of programming, but I wanted to do more with it. That’s today’s project. I’ve been working on it while baking a cake for my fiancee’s birthday.
Basically, my C code starts in main() and makes use of only one library function. I defined a few other functions in my C code and called them from there, but that doesn’t really matter much for what I wanted to do.
What I did was take all the C code that I wrote before and leave it exactly the way it is, didn’t change even one line.
Then, I wrote a small bit of ASM code.
The ASM code does two things:
1. Calls main()
2. Implements __syscall()
With that code, I can compile and assemble my C code and ASM code, then I can link the resulting object code together with each other and NOT with any other code. No more standard C library, no more startup code.
The result: It does exactly the same thing!
Now, I know what you are thinking: that’s a really hard way to something very simple.
Which is of course true. Although really the code is so simple, so it’s hard to say that it’s “a really hard way”, but comparitively, it’s much more complicated than just writing C code calling the standard C library. However, if we take a look at something simple and measurable, like say executable file sizes, we might notice some differences.
The file size of the C code calling __syscall() from the FreeBSD standard C library, statically linked and stripped, is 356 kilobytes. Hmm.. that’s pretty small, right? Seems like it would be hard to beat that.
Let’s just take a look at our C code linked with the ASM glue. The C code linked with only the ASM __syscall glue ends up being 2.3 kilobytes.
That’s 2.3K! That’s over 150 times smaller than the code using the standard C library!
Now I know that comparing file sizes is not really a good measure of anything, but it helps show that there is a significant difference between the the two methods. I’m sure you get the picture.
Now finally, let’s get to the code. Now you should know that I go lucky with this code; Basically all it does it move the values in registers around. This works because FreeBSD amd64 calling convention and syscall convention both use registers to pass arguments. This will NOT work in 32 bit FreeBSD because 32 bit FreeBSD passes arguments on the stack.
Here is the code:
section .text
global _start, __syscall
extern main
mov rax,rdi;
mov rdi,rsi;
mov rsi,rdx;
mov rdx,rcx;
call main;
mov rax,1;
We can assemble this code with yasm using the following command line:
yasm -felf64 syscall_amd64.s
Which will create syscall_amd64.o, which we can then link with hanvon.o like this:
ld hanvon.o syscall_amd64.o -o hanvon
Which will create the hanvon executable.
That's all I have today, enjoy!