3

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

Alex
  • 9,891
  • 11
  • 53
  • 87
  • 1
    I'd recommend looking up `systemcall()` source in glibc source code - it may show the difference. – Dmytro Sirenko Oct 09 '12 at 09:09
  • It your system 64-bit? If so, maybe you need to use %rax registers? Your snippet is a 32-bit assembly language. – Dmytro Sirenko Oct 09 '12 at 09:46
  • 2
    See http://stackoverflow.com/questions/3730064/process-command-line-in-linux-64-bit , for 64 bit applications you can't use `int 0x80` – nos Oct 09 '12 at 10:22

2 Answers2

5

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.

Dmytro Sirenko
  • 5,003
  • 21
  • 26
  • 1
    It does "work", but only if it's ok to truncate the inputs to 32 bit (and if `CONFIG_IA32_EMULATION` is enabled). – Peter Cordes Sep 17 '18 at 07:27
2

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.

firo
  • 1,002
  • 12
  • 20
  • They're getting `-EFAULT`, not `-ENOSYS`, so we know the syscall table isn't the problem. And `-EFAULT` is a classic symptom of having the 32-bit `int 0x80` ABI truncate a 64-bit pointer. Many of the other duplicates of the dup target I used are newbies calling `read` or `write` with `int 0x80` with stack args in 64-bit mode. (And we'll probably see more with static data in PIE executables now, too.) – Peter Cordes Sep 17 '18 at 07:35
  • 1
    Oh actually, this system call doesn't have any inputs, so that's weird. Oh, no it isn't, you're right: there's an existing 32-bit syscall 312. `#define __NR_get_robust_list 312` in `unistd_32.h`, and it's unsurprising that it returns `-EFAULT` with whatever garbage is in EBX/ECX/EDX/... (Maybe not an exact dup of [What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](https://stackoverflow.com/q/46087730) after all.) – Peter Cordes Sep 17 '18 at 07:39