3
votes

I am studying the Linux kernel and at the moment I try to implement my own system call.

In the kernel code it looks the following:

asmlinkage long sys_my_syscall()
{
     printk("My system call\n");
     return 0;
}

If I call it with a systemcall() function it works fine, but I have found another one way:

int my_syscall(void)
{
    long __res;
    __asm__ volatile (
    "movl $312, %%eax;"
    "int $0x80;"
    "movl %%eax, %0;"
    : "=m" (__res)
    :
    : "%eax"
    );
    if ((unsigned long) (__res) >= (unsigned long) (-125)) {
       errno = -(__res);
       __res = -1;
    }
    return (int)(__res);
}

But it returns the value -14 EFAULT.

What am I doing wrong?

Setup: Linux kernel 3.4, ARCH x86_64

2
I'd recommend looking up systemcall() source in glibc source code - it may show the difference.Dmytro Sirenko
It your system 64-bit? If so, maybe you need to use %rax registers? Your snippet is a 32-bit assembly language.Dmytro Sirenko
See stackoverflow.com/questions/3730064/… , for 64 bit applications you can't use int 0x80nos

2 Answers

5
votes

For 64-bit systems the Linux system call ABI is completely different from i*86 one unless there's a layer of compatibility. This may help: http://callumscode.com/blog/3

I also found the syscall source in the eglibc, it looks different indeed: http://www.eglibc.org/cgi-bin/viewvc.cgi/trunk/libc/sysdeps/unix/sysv/linux/x86_64/syscall.S?view=markup

So it looks like int $0x80 does not work for x86_64 Linux kernels, you need to use syscall instead.

2
votes

I have two ideas.

  1. Did you update the system call table?

For kernel 4.14, it's arch/x86/entry/syscalls/syscall_64.tbl

  1. Did you enbale the COMPAT_32 kernel option?

If not, int 0x80 won't work. It seems your system had enabled this option, or you would hit the #GP exception.