System calls aren't handled like regular function calls. It takes special code to make the transition from user space to kernel space, basically a bit of inline assembly code injected into your program at the call site. The kernel side code that "catches" the system call is also low-level stuff you probably don't need to understand deeply, at least at first.
include/linux/syscalls.h under your kernel source directory, you find this:
asmlinkage long sys_mkdir(const char __user *pathname, int mode);
/usr/include/asm*/unistd.h, you find this:
#define __NR_mkdir 83 __SYSCALL(__NR_mkdir, sys_mkdir)
This code is saying
mkdir(2) is system call #83. That is to say, system calls are called by number, not by address as with a normal function call within your own program or to a function in a library linked to your program. The inline assembly glue code I mentioned above uses this to make the transition from user to kernel space, taking your parameters along with it.
Another bit of evidence that things are a little weird here is that there isn't always a strict parameter list for system calls:
open(2), for instance, can take either 2 or 3 parameters. That means
open(2) is overloaded, a feature of C++, not C, yet the syscall interface is C-compatible. (This is not the same thing as C's varargs feature, which allows a single function to take a variable number of arguments.)