diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index de7a99f0c6..41dd887dbc 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -31,6 +31,10 @@ SYSCALL_DEF(fork);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
+#ifdef TARGET_NR_link
+SYSCALL_DEF(link, ARG_STR, ARG_STR);
+#endif
+SYSCALL_DEF(linkat, ARG_ATDIRFD, ARG_STR, ARG_ATDIRFD, ARG_STR, ARG_ATFLAG);
 SYSCALL_DEF(mlock, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(mlockall, ARG_HEX);
 #ifdef TARGET_NR_mmap
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5cb77223fd..5b78eb137b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1357,35 +1357,6 @@ print_futimesat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_link
-static void
-print_link(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_string(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_linkat
-static void
-print_linkat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_at_dirfd(arg2, 0);
-    print_string(arg3, 0);
-    print_flags(at_file_flags, arg4, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR__llseek
 static void
 print__llseek(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 62e1790e3b..c6ca80955b 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -40,6 +40,34 @@ SYSCALL_IMPL(creat)
 }
 #endif
 
+static abi_long do_linkat(int olddirfd, abi_ulong target_oldpath,
+                          int newdirfd, abi_ulong target_newpath,
+                          int flags)
+{
+    char *oldpath = lock_user_string(target_oldpath);
+    char *newpath = lock_user_string(target_newpath);
+    abi_long ret = -TARGET_EFAULT;
+
+    if (oldpath && newpath) {
+        ret = get_errno(linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+    }
+    unlock_user(oldpath, target_oldpath, 0);
+    unlock_user(newpath, target_newpath, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_link
+SYSCALL_IMPL(link)
+{
+    return do_linkat(AT_FDCWD, arg1, AT_FDCWD, arg2, 0);
+}
+#endif
+
+SYSCALL_IMPL(linkat)
+{
+    return do_linkat(arg1, arg2, arg3, arg4, arg5);
+}
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1e9478611c..f1e8d06996 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5330,38 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_link
-    case TARGET_NR_link:
-        {
-            void * p2;
-            p = lock_user_string(arg1);
-            p2 = lock_user_string(arg2);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(link(p, p2));
-            unlock_user(p2, arg2, 0);
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_linkat)
-    case TARGET_NR_linkat:
-        {
-            void * p2 = NULL;
-            if (!arg2 || !arg4)
-                return -TARGET_EFAULT;
-            p  = lock_user_string(arg2);
-            p2 = lock_user_string(arg4);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
-            unlock_user(p, arg2, 0);
-            unlock_user(p2, arg4, 0);
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_unlink
     case TARGET_NR_unlink:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index be0392810c..c369915759 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -461,12 +461,6 @@
 #ifdef TARGET_NR_lgetxattr
 { TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_link
-{ TARGET_NR_link, "link" , NULL, print_link, NULL },
-#endif
-#ifdef TARGET_NR_linkat
-{ TARGET_NR_linkat, "linkat" , NULL, print_linkat, NULL },
-#endif
 #ifdef TARGET_NR_Linux
 { TARGET_NR_Linux, "Linux" , NULL, NULL, NULL },
 #endif
