[PATCH 1/1] Only pass the minimum number of syscall arguments

Georg Sauthoff <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Previously, __internal_syscall() compiled into asm-code that unconditionally
sets the syscall argument registers a0 to a5.

For example, the instruction sequence for a exit syscall looked like
this:

    li    a0, 1   # in ther caller of exit()
    # ...         # in newlib:
    li    a1, 0   # unused arguments
    li    a2, 0
    li    a3, 0
    li    a4, 0
    li    a5, 0
    li    a7, 93  # exit syscall number

(i.e. the binary contains then 5 superfluous instructions for this
one argument syscall)

This commit changes the RISC-V syscall code such that only the required
syscall argument registers are set.

GCC detects that argc is known at compile time and thus evaluates all the
if-statements where argc is used at compile time (tested with -O2 and -Os).
---
 libgloss/riscv/internal_syscall.h | 41 ++++++++++++++++++++++---------
 libgloss/riscv/sys_access.c       |  2 +-
 libgloss/riscv/sys_close.c        |  2 +-
 libgloss/riscv/sys_exit.c         |  2 +-
 libgloss/riscv/sys_faccessat.c    |  2 +-
 libgloss/riscv/sys_fstat.c        |  2 +-
 libgloss/riscv/sys_fstatat.c      |  2 +-
 libgloss/riscv/sys_gettimeofday.c |  2 +-
 libgloss/riscv/sys_link.c         |  2 +-
 libgloss/riscv/sys_lseek.c        |  2 +-
 libgloss/riscv/sys_lstat.c        |  2 +-
 libgloss/riscv/sys_open.c         |  2 +-
 libgloss/riscv/sys_openat.c       |  2 +-
 libgloss/riscv/sys_read.c         |  2 +-
 libgloss/riscv/sys_sbrk.c         |  4 +--
 libgloss/riscv/sys_stat.c         |  2 +-
 libgloss/riscv/sys_unlink.c       |  2 +-
 libgloss/riscv/sys_write.c        |  2 +-
 18 files changed, 48 insertions(+), 29 deletions(-)

diff --git a/libgloss/riscv/internal_syscall.h b/libgloss/riscv/internal_syscall.h
index e5d5594..1f1f42f 100644
--- a/libgloss/riscv/internal_syscall.h
+++ b/libgloss/riscv/internal_syscall.h
@@ -22,31 +22,50 @@ __syscall_error(long a0)
 }
 
 static inline long
-__internal_syscall(long n, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
+__internal_syscall(long n, int argc, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
 {
+#ifdef __riscv_32e
+  register long syscall_id asm("t0") = n;
+#else
+  register long syscall_id asm("a7") = n;
+#endif
+
   register long a0 asm("a0") = _a0;
+  if (argc < 2) {
+      asm volatile ("ecall" : "+r"(a0) : "r"(syscall_id));
+      return a0;
+  }
   register long a1 asm("a1") = _a1;
+  if (argc == 2) {
+      asm volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(syscall_id));
+      return a0;
+  }
   register long a2 asm("a2") = _a2;
+  if (argc == 3) {
+      asm volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(a2), "r"(syscall_id));
+      return a0;
+  }
   register long a3 asm("a3") = _a3;
+  if (argc == 4) {
+      asm volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(syscall_id));
+      return a0;
+  }
   register long a4 asm("a4") = _a4;
+  if (argc == 5) {
+      asm volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(syscall_id));
+      return a0;
+  }
   register long a5 asm("a5") = _a5;
 
-#ifdef __riscv_32e
-  register long syscall_id asm("t0") = n;
-#else
-  register long syscall_id asm("a7") = n;
-#endif
-
-  asm volatile ("scall"
-		: "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id));
+  asm volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id));
 
   return a0;
 }
 
 static inline long
-syscall_errno(long n, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
+syscall_errno(long n, int argc, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
 {
-  long a0 = __internal_syscall (n, _a0, _a1, _a2, _a3, _a4, _a5);
+  long a0 = __internal_syscall (n, argc, _a0, _a1, _a2, _a3, _a4, _a5);
 
   if (a0 < 0)
     return __syscall_error (a0);
diff --git a/libgloss/riscv/sys_access.c b/libgloss/riscv/sys_access.c
index ef446d2..45bedb3 100644
--- a/libgloss/riscv/sys_access.c
+++ b/libgloss/riscv/sys_access.c
@@ -5,5 +5,5 @@
 int
 _access(const char *file, int mode)
 {
-  return syscall_errno (SYS_access, file, mode, 0, 0, 0, 0);
+  return syscall_errno (SYS_access, 2, file, mode, 0, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_close.c b/libgloss/riscv/sys_close.c
index 80b10c6..c1691d8 100644
--- a/libgloss/riscv/sys_close.c
+++ b/libgloss/riscv/sys_close.c
@@ -5,5 +5,5 @@
 int
 _close(int file)
 {
-  return syscall_errno (SYS_close, file, 0, 0, 0, 0, 0);
+  return syscall_errno (SYS_close, 1, file, 0, 0, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_exit.c b/libgloss/riscv/sys_exit.c
index 03e1c34..995dd65 100644
--- a/libgloss/riscv/sys_exit.c
+++ b/libgloss/riscv/sys_exit.c
@@ -5,6 +5,6 @@
 void
 _exit(int exit_status)
 {
-  syscall_errno (SYS_exit, exit_status, 0, 0, 0, 0, 0);
+  syscall_errno (SYS_exit, 1, exit_status, 0, 0, 0, 0, 0);
   while (1);
 }
diff --git a/libgloss/riscv/sys_faccessat.c b/libgloss/riscv/sys_faccessat.c
index e966a4a..6418ef4 100644
--- a/libgloss/riscv/sys_faccessat.c
+++ b/libgloss/riscv/sys_faccessat.c
@@ -4,5 +4,5 @@
 /* Permissions of a file (by name) in a given directory.  */
 int _faccessat(int dirfd, const char *file, int mode, int flags)
 {
-  return syscall_errno (SYS_faccessat, dirfd, file, mode, flags, 0, 0);
+  return syscall_errno (SYS_faccessat, 4, dirfd, file, mode, flags, 0, 0);
 }
diff --git a/libgloss/riscv/sys_fstat.c b/libgloss/riscv/sys_fstat.c
index 13a0bca..d97ba44 100644
--- a/libgloss/riscv/sys_fstat.c
+++ b/libgloss/riscv/sys_fstat.c
@@ -9,7 +9,7 @@ int
 _fstat(int file, struct stat *st)
 {
   struct kernel_stat kst;
-  int rv = syscall_errno (SYS_fstat, file, &kst, 0, 0, 0, 0);
+  int rv = syscall_errno (SYS_fstat, 2, file, &kst, 0, 0, 0, 0);
   _conv_stat (st, &kst);
   return rv;
 }
diff --git a/libgloss/riscv/sys_fstatat.c b/libgloss/riscv/sys_fstatat.c
index 0e4ea42..bf03355 100644
--- a/libgloss/riscv/sys_fstatat.c
+++ b/libgloss/riscv/sys_fstatat.c
@@ -8,7 +8,7 @@ int
 _fstatat(int dirfd, const char *file, struct stat *st, int flags)
 {
   struct kernel_stat kst;
-  int rv = syscall_errno (SYS_fstatat, dirfd, file, &kst, flags, 0, 0);
+  int rv = syscall_errno (SYS_fstatat, 4, dirfd, file, &kst, flags, 0, 0);
   _conv_stat (st, &kst);
   return rv;
 }
diff --git a/libgloss/riscv/sys_gettimeofday.c b/libgloss/riscv/sys_gettimeofday.c
index 457dcbc..daa14e4 100644
--- a/libgloss/riscv/sys_gettimeofday.c
+++ b/libgloss/riscv/sys_gettimeofday.c
@@ -6,5 +6,5 @@
 int
 _gettimeofday(struct timeval *tp, void *tzp)
 {
-  return syscall_errno (SYS_gettimeofday, tp, 0, 0, 0, 0, 0);
+  return syscall_errno (SYS_gettimeofday, 1, tp, 0, 0, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_link.c b/libgloss/riscv/sys_link.c
index eaeb22b..83cd1b2 100644
--- a/libgloss/riscv/sys_link.c
+++ b/libgloss/riscv/sys_link.c
@@ -4,5 +4,5 @@
 /* Establish a new name for an existing file.  */
 int _link(const char *old_name, const char *new_name)
 {
-  return syscall_errno (SYS_link, old_name, new_name, 0, 0, 0, 0);
+  return syscall_errno (SYS_link, 2, old_name, new_name, 0, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_lseek.c b/libgloss/riscv/sys_lseek.c
index 7486a3a..8eb8b81 100644
--- a/libgloss/riscv/sys_lseek.c
+++ b/libgloss/riscv/sys_lseek.c
@@ -6,5 +6,5 @@
 off_t
 _lseek(int file, off_t ptr, int dir)
 {
-  return syscall_errno (SYS_lseek, file, ptr, dir, 0, 0, 0);
+  return syscall_errno (SYS_lseek, 3, file, ptr, dir, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_lstat.c b/libgloss/riscv/sys_lstat.c
index 2eeabcc..dd5dc52 100644
--- a/libgloss/riscv/sys_lstat.c
+++ b/libgloss/riscv/sys_lstat.c
@@ -7,7 +7,7 @@
 int _lstat(const char *file, struct stat *st)
 {
   struct kernel_stat kst;
-  int rv = syscall_errno (SYS_lstat, file, &kst, 0, 0, 0, 0);
+  int rv = syscall_errno (SYS_lstat, 2, file, &kst, 0, 0, 0, 0);
   _conv_stat (st, &kst);
   return rv;
 }
diff --git a/libgloss/riscv/sys_open.c b/libgloss/riscv/sys_open.c
index 4fd5d67..eb1a99b 100644
--- a/libgloss/riscv/sys_open.c
+++ b/libgloss/riscv/sys_open.c
@@ -5,5 +5,5 @@
 int
 _open(const char *name, int flags, int mode)
 {
-  return syscall_errno (SYS_open, name, flags, mode, 0, 0, 0);
+  return syscall_errno (SYS_open, 3, name, flags, mode, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_openat.c b/libgloss/riscv/sys_openat.c
index cf429b7..652ab2e 100644
--- a/libgloss/riscv/sys_openat.c
+++ b/libgloss/riscv/sys_openat.c
@@ -4,5 +4,5 @@
 /* Open file relative to given directory.  */
 int _openat(int dirfd, const char *name, int flags, int mode)
 {
-  return syscall_errno (SYS_openat, dirfd, name, flags, mode, 0, 0);
+  return syscall_errno (SYS_openat, 4, dirfd, name, flags, mode, 0, 0);
 }
diff --git a/libgloss/riscv/sys_read.c b/libgloss/riscv/sys_read.c
index 7367e26..dd3bc33 100644
--- a/libgloss/riscv/sys_read.c
+++ b/libgloss/riscv/sys_read.c
@@ -5,5 +5,5 @@
 /* Read from a file.  */
 ssize_t _read(int file, void *ptr, size_t len)
 {
-  return syscall_errno (SYS_read, file, ptr, len, 0, 0, 0);
+  return syscall_errno (SYS_read, 3, file, ptr, len, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_sbrk.c b/libgloss/riscv/sys_sbrk.c
index f91c2c5..086509e 100644
--- a/libgloss/riscv/sys_sbrk.c
+++ b/libgloss/riscv/sys_sbrk.c
@@ -41,13 +41,13 @@ _sbrk(ptrdiff_t incr)
 
   if (heap_end == 0)
     {
-      long brk = __internal_syscall (SYS_brk, 0, 0, 0, 0, 0, 0);
+      long brk = __internal_syscall (SYS_brk, 1, 0, 0, 0, 0, 0, 0);
       if (brk == -1)
         return (void *)__syscall_error (-ENOMEM);
       heap_end = brk;
     }
 
-  if (__internal_syscall (SYS_brk, heap_end + incr, 0, 0, 0, 0, 0) != heap_end + incr)
+  if (__internal_syscall (SYS_brk, 1, heap_end + incr, 0, 0, 0, 0, 0) != heap_end + incr)
     return (void *)__syscall_error (-ENOMEM);
 
   heap_end += incr;
diff --git a/libgloss/riscv/sys_stat.c b/libgloss/riscv/sys_stat.c
index a193b10..1e03700 100644
--- a/libgloss/riscv/sys_stat.c
+++ b/libgloss/riscv/sys_stat.c
@@ -8,7 +8,7 @@ int
 _stat(const char *file, struct stat *st)
 {
   struct kernel_stat kst;
-  int rv = syscall_errno (SYS_stat, file, &kst, 0, 0, 0, 0);
+  int rv = syscall_errno (SYS_stat, 2, file, &kst, 0, 0, 0, 0);
   _conv_stat (st, &kst);
   return rv;
 }
diff --git a/libgloss/riscv/sys_unlink.c b/libgloss/riscv/sys_unlink.c
index b55fe1e..1cf6bbe 100644
--- a/libgloss/riscv/sys_unlink.c
+++ b/libgloss/riscv/sys_unlink.c
@@ -5,5 +5,5 @@
 int
 _unlink(const char *name)
 {
-  return syscall_errno (SYS_unlink, name, 0, 0, 0, 0, 0);
+  return syscall_errno (SYS_unlink, 1, name, 0, 0, 0, 0, 0);
 }
diff --git a/libgloss/riscv/sys_write.c b/libgloss/riscv/sys_write.c
index b972734..ce2edd3 100644
--- a/libgloss/riscv/sys_write.c
+++ b/libgloss/riscv/sys_write.c
@@ -6,5 +6,5 @@
 ssize_t
 _write(int file, const void *ptr, size_t len)
 {
-  return syscall_errno (SYS_write, file, ptr, len, 0, 0, 0);
+  return syscall_errno (SYS_write, 3, file, ptr, len, 0, 0, 0);
 }
-- 
2.24.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.