For a long time, adding an alias to a function required us using the "weak_alias" macro in the same file as the original function, which caused us to modify some Musl files we didn't want to modify.
In this patch I add a new mechanism for creating an alias for functions in *other* source files. Unfortunately, as this requires cooperation from the linker, we (ab)used the linker's "ifunc" (STT_GNU_IFUNC) support - already used by OSv - to copy the function's address at load time. This is a waste, but a really tiny waste. I'm putting this patch up as an RFC to see if someone can come up with a better solution - hopefully to get the static linker (which links OSv) to copy symbols. E.g., maybe doing this as a linker script would have been nicer. In any case, this patch demonstrates how being able to create aliases in a separate file (here libc/aliases.c) allows us to drop a change from musl (here res_init.c). Signed-off-by: Nadav Har'El <[email protected]> --- Makefile | 3 ++- libc/aliases.c | 31 +++++++++++++++++++++++++++++++ libc/network/res_init.c | 7 ------- 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 libc/aliases.c delete mode 100644 libc/network/res_init.c diff --git a/Makefile b/Makefile index cd490a76..9ec206b3 100644 --- a/Makefile +++ b/Makefile @@ -944,6 +944,7 @@ libc += internal/floatscan.o libc += internal/intscan.o libc += internal/libc.o libc += internal/shgetc.o +libc += aliases.o musl += ctype/__ctype_get_mb_cur_max.o musl += ctype/__ctype_tolower_loc.o @@ -1375,7 +1376,7 @@ musl += network/getservbyport.o libc += network/getifaddrs.o libc += network/if_nameindex.o musl += network/if_freenameindex.o -libc += network/res_init.o +musl += network/res_init.o musl += prng/rand.o musl += prng/rand_r.o diff --git a/libc/aliases.c b/libc/aliases.c new file mode 100644 index 00000000..2d16cd10 --- /dev/null +++ b/libc/aliases.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 ScyllaDB + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ + +// Creating function aliases using the "alias(...)" attribute or our +// weak_alias() macro (which uses alias(...)) requires the alias to be +// defined in the same source file as the original function. The reason is +// that this mechanism doesn't use any special linker trickery - it simply +// generates the same address for both functions. +// In the past this requirement forced us to modify Musl files just to add an +// alias,or to use inefficient workarounds like wrapper functions. In this file +// we use a different trick based on the linker: ifunc - functions run during +// boot when relocating these symbols. This has a runtime penalty at load time, +// unfortunately, but it's tiny. +// It would be nice if in the future we can find a different aliasing +// technique which can copy the address during the kernel's static linking, +// not at runtime. x86 has "copy relocation", for example, but it is not +// exposed to C code and is x86-only. The benefit of the ifunc technique is +// that it is standard - and we actually already use it in OSv (for choosing +// between different implementations of the string functions). + +#define QUOTE(x) #x +#define ALIAS(oldname, newname) \ + extern void oldname(void); \ + static void* resolve_##newname(void) { return oldname; } \ + void newname(void) __attribute__((ifunc(QUOTE(resolve_##newname)))); + +ALIAS(res_init, __res_init) diff --git a/libc/network/res_init.c b/libc/network/res_init.c deleted file mode 100644 index 66f3f95a..00000000 --- a/libc/network/res_init.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "libc.h" - -int res_init() -{ - return 0; -} -weak_alias(res_init, __res_init); -- 2.26.2 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20200803224006.1429719-1-nyh%40scylladb.com.
