Asish K Sahadevan
Asish K Sahadevan

Reputation: 51

Trouble calling syscall by name

I am in process of adding system calls to linux Kernel 3.19. Tried out the following for adding a syscall 'add' for x86 arch in Ubuntu 14.04 LTS. src=3.19 source

  1. Added entry to src/arch/x86/syscalls/syscall_64.tbl.

    323 common add sys_add
    
  2. Added syscall prototype to src/include/syscalls.h.

    asmlinakge sys_add(int i,int j);
    
  3. Wrote add.c in fs directory, added add.o in fs/Makefile .

  4. In file src/include/uapi/asm-generic/unistd.h

Added lines

    #define __NR_add 323

  __SYSCALL(__NR_add, sys_add);
  1. Compiled and built the kernel. It was success. The output of uname -r gives 3.19.

  2. Created a program to test new syscall.

    6.1 Used the function syscall(323,10,15). It was success as the sum of values(25) was printed.

    6.2 When trying to call syscall by name, it gives

      /tmp/ccpxRp8C.o: In function `main':
       testadd1.c:(.text+0x18): undefined reference to `add'
       collect2: error: ld returned 1 exit status
    

What am I missing??

Upvotes: 4

Views: 1071

Answers (1)

user208139
user208139

Reputation:

You are missing the little piece of assembly code that, when assembled, shows up as a C-linkable symbol.

If you do this:

ar t /usr/lib/libc.a | grep write.o

you will see that the (statically-linkable) C library has a small file named "write.o". This contains a little piece of assembled code that defines a symbol __libc_write that's visible outside of write.o. That little piece of assembled code puts the value 1 in a specific register, which is the number that Linux and Unix kernels know as the "write" system call, sets up other registers very carefully, then executes a syscall instruction (on my x86_64 machine).

You will have to create just such a piece of assembly code for your "add" system call. Or, you can you the syscall system call, just as you have been doing, writing a plain C function to make it look lke you've got an add() system call.

You don't say what architecture (x86 or x86_64) you're using, but here's an x86_64 implementation of write(2). It does set errno correctly, and it returns the number of bytes written, but the argument types aren't correct.

int
linux_write(int fd, const void *data, unsigned long len)
{

    long ret;
    asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write),
              "D" (fd), "S" (data), "d" (len) :
              "cc", "memory", "rcx",
              "r8", "r9", "r10", "r11" );
    if (ret < 0)
    {
        errno = -ret;
        ret = -1;
    }
    return (int)ret;
}

Upvotes: 1

Related Questions