[PATCH 27/46] linkage, lto: use C version for SYSCALL_ALIAS() / cond_syscall()

From: Jiri Slaby (SUSE)
Date: Mon Nov 14 2022 - 06:47:31 EST


From: Andi Kleen <ak@xxxxxxxxxxxxxxx>

With LTO, aliases get largely resolved in the compiler, not in the
linker.

Implement cond_syscall() and SYSCALL_ALIAS() in C to let the compiler
understand the aliases so that it can resolve them properly.

Likely, the architecture specific versions are now not needed anymore,
but they are kept for now.

There is one subtlety here:
The assembler version didn't care whether there was a prototype or not.
This variant assumes there is no prototype because it uses a dummy
(void) signature. This works for sys_ni.c, but breaks for
kernel/time/posix-stubs.c. To avoid problems there, a second variant of
the macro (_PROTO) is added. That uses the previously declared type
(by typeof()).

I actually tried to avoid this by adding prototypes for SYS_NI() and use
only the _PROTO variant, but it resulted in very large patches and lots
of problems with all the different cases. Eventually, I gave up and just
use the prototype case in posix-stubs.c

[js] gcc >= 8 emits Wattribute-alias warning. Work around that by
__diag_*(). This is ugly, but due to gcc bug, I see no better
option. Suggestions welcome.

Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
Signed-off-by: Martin Liska <mliska@xxxxxxx>
Signed-off-by: Jiri Slaby <jslaby@xxxxxxx>
---
include/linux/linkage.h | 16 ++++++++--------
kernel/time/posix-stubs.c | 19 +++++++++++++++++--
2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 1feab6136b5b..688b9bb80e96 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -23,17 +23,17 @@
#endif

#ifndef cond_syscall
-#define cond_syscall(x) asm( \
- ".weak " __stringify(x) "\n\t" \
- ".set " __stringify(x) "," \
- __stringify(sys_ni_syscall))
+#define cond_syscall(x) \
+ extern long x(void) __attribute__((alias("sys_ni_syscall"), weak));
#endif

#ifndef SYSCALL_ALIAS
-#define SYSCALL_ALIAS(alias, name) asm( \
- ".globl " __stringify(alias) "\n\t" \
- ".set " __stringify(alias) "," \
- __stringify(name))
+#define SYSCALL_ALIAS(a, name) \
+ long a(void) __attribute__((alias(__stringify(name))))
+#define SYSCALL_ALIAS_PROTO(a, name) \
+ typeof(a) a __attribute__((alias(__stringify(name))))
+#else
+#define SYSCALL_ALIAS_PROTO(a, name) SYSCALL_ALIAS(a, name)
#endif

#define __page_aligned_data __section(".data..page_aligned") __aligned(PAGE_SIZE)
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c
index 90ea5f373e50..23e1a63adc2b 100644
--- a/kernel/time/posix-stubs.c
+++ b/kernel/time/posix-stubs.c
@@ -31,13 +31,21 @@ asmlinkage long sys_ni_posix_timers(void)
}

#ifndef SYS_NI
-#define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers)
+#define SYS_NI(name) SYSCALL_ALIAS_PROTO(sys_##name, sys_ni_posix_timers)
#endif

#ifndef COMPAT_SYS_NI
-#define COMPAT_SYS_NI(name) SYSCALL_ALIAS(compat_sys_##name, sys_ni_posix_timers)
+#define COMPAT_SYS_NI(name) \
+ SYSCALL_ALIAS_PROTO(compat_sys_##name, sys_ni_posix_timers)
#endif

+/*
+ * This cannot go to SYS_NI() or SYSCALL_ALIAS_PROTO() due to gcc bug fixed in
+ * gcc >= 13 (cf. PR 97498). I wonder how is __SYSCALL_DEFINEx() able to work?
+ */
+__diag_push();
+__diag_ignore(GCC, 8, "-Wattribute-alias", "Alias to nonimplemented syscall");
+
SYS_NI(timer_create);
SYS_NI(timer_gettime);
SYS_NI(timer_getoverrun);
@@ -51,6 +59,8 @@ SYS_NI(clock_adjtime32);
SYS_NI(alarm);
#endif

+__diag_pop();
+
/*
* We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
* as it is easy to remain compatible with little code. CLOCK_BOOTTIME
@@ -157,6 +167,9 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
which_clock);
}

+__diag_push();
+__diag_ignore(GCC, 8, "-Wattribute-alias", "Alias to nonimplemented syscall");
+
#ifdef CONFIG_COMPAT
COMPAT_SYS_NI(timer_create);
#endif
@@ -170,6 +183,8 @@ COMPAT_SYS_NI(setitimer);
SYS_NI(timer_settime32);
SYS_NI(timer_gettime32);

+__diag_pop();
+
SYSCALL_DEFINE2(clock_settime32, const clockid_t, which_clock,
struct old_timespec32 __user *, tp)
{
--
2.38.1