Search code examples
cassemblyvolatilesystem-calls

Inline Assembler for wrapper function doesn't work for some reason


I'm trying to write a wrapper function for read() system call , using asm volatile , but it won't work , since the res doesn't change its value .

Here's the code :

ssize_t my_read(int fd, void *buf, size_t count)

{

      ssize_t res;

      __asm__ volatile(
        "int $0x80"        /* make the request to the OS */
        : "=a" (res),       /* return result in eax ("a") */
          "+b" (fd),     /* pass arg1 in ebx ("b") */
          "+c" (buf),     /* pass arg2 in ecx ("c") */
          "+d" (count)      /* pass arg3 in edx ("d") */
        : "a"  (5)          /* passing the system call for read to %eax , with call number 5  */
        : "memory", "cc"); /* announce to the compiler that the memory and condition codes have been modified */

      /* The operating system will return a negative value on error;
       * wrappers return -1 on error and set the errno global variable */

      if (-125 <= res && res < 0)
      {
        errno = -res;
        res   = -1;
      }

      return res;

}

and here is int main () :

 int main() {
     int fd = 432423;
     char buf[128];
     size_t count = 128;
     my_read(fd, buf, count);

     return 0;
 }

Am I doing something wrong ? maybe it's because of the volatile ?

I've tried to debug the code , and when Eclipse goes into my_read(fd, buf, count); and gets to the line __asm__ volatile( in my_read , it fails and goes into if (-125 <= res && res < 0) ...

EDIT :

ssize_t my_read(int fd, void *buf, size_t count)

{

      ssize_t res;

      __asm__ volatile(
        "int $0x80"        /* make the request to the OS */
        : "=a" (res)       /* return result in eax ("a") */

        : "a"  (5) ,      /* passing the system call for read to %eax , with call number 5  */
          "b" (fd),     /* pass arg1 in ebx ("b") */
          "c" (buf),     /* pass arg2 in ecx ("c") */
          "d" (count)      /* pass arg3 in edx ("d") */

        : "memory", "cc"); /* announce to the compiler that the memory and condition codes have been modified */

      /* The operating system will return a negative value on error;
       * wrappers return -1 on error and set the errno global variable */

      if (-125 <= res && res < 0)
      {
        errno = -res;
        res   = -1;
      }

      return res;

}

and main :

 int main() {
     int fd = 0;
     char buf[128];
     size_t count = 128;
     my_read(fd, buf, count);

     return 0;
 }

Solution

  • it fails and goes into if (-125 <= res && res < 0)

    Where did you expect it to go?

    I expect the read system call to fail with -EINVAL, as you are not pasing in a valid file descriptor to it.

    Update:

    Where did you get an idea that SYS_read is 5?

    On my system, SYS_read is 3 in 32-bit mode, and 0 in 64-bit mode:

    echo "#include <syscall.h>" | gcc -xc - -dD -E | grep ' __NR_read '
    #define __NR_read 0
    
    echo "#include <syscall.h>" | gcc -xc - -dD -E -m32 | grep ' __NR_read '
    #define __NR_read 3
    

    Assuming you are on 32-bit system, you are invoking SYS_open, which is failing with -EFAULT (-14) because the first parameter to the open system call is supposed to be a filename and 0 (NULL) isn't a valid filename.