From fafef4230822be5b13824617786154d0a1a01ded Mon Sep 17 00:00:00 2001 From: kib Date: Sat, 13 Oct 2018 23:52:55 +0000 Subject: [PATCH] Process irelocs for statically linked binaries from crt1 on x86. This makes statically linked binaries with ifuncs operational. Reported and tested by: mjg Reviewed by: emaste, markj Sponsored by: The FreeBSD Foundation Approved by: re (rgrimes) Differential revision: https://reviews.freebsd.org/D17363 --- lib/csu/aarch64/Makefile | 1 + lib/csu/amd64/Makefile | 4 +- lib/csu/amd64/crt1.c | 6 ++- lib/csu/amd64/reloc.c | 66 +++++++++++++++++++++++++++ lib/csu/arm/Makefile | 1 + lib/csu/common/ignore_init.c | 40 +++++++++++++++- lib/csu/i386/Makefile | 3 +- lib/csu/i386/crt1_c.c | 6 ++- lib/csu/i386/reloc.c | 88 ++++++++++++++++++++++++++++++++++++ lib/csu/mips/Makefile | 1 + lib/csu/powerpc/Makefile | 1 + lib/csu/powerpc64/Makefile | 2 +- lib/csu/riscv/Makefile | 1 + lib/csu/sparc64/Makefile | 1 + 14 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 lib/csu/amd64/reloc.c create mode 100644 lib/csu/i386/reloc.c diff --git a/lib/csu/aarch64/Makefile b/lib/csu/aarch64/Makefile index 3f34ff351623..df1fe6e2343b 100644 --- a/lib/csu/aarch64/Makefile +++ b/lib/csu/aarch64/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/amd64/Makefile b/lib/csu/amd64/Makefile index a6a2d5ec658d..493ad93173b0 100644 --- a/lib/csu/amd64/Makefile +++ b/lib/csu/amd64/Makefile @@ -5,9 +5,9 @@ SRCS= crt1.c crti.S crtn.S OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o -CFLAGS+= -I${.CURDIR:H}/common \ +CFLAGS+= -I${.CURDIR} -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include -CFLAGS+= -fno-omit-frame-pointer +CFLAGS+= -fno-omit-frame-pointer -DCRT_IRELOC_RELA FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/amd64/crt1.c b/lib/csu/amd64/crt1.c index a6001b2d5851..7b9b442a4c0a 100644 --- a/lib/csu/amd64/crt1.c +++ b/lib/csu/amd64/crt1.c @@ -59,10 +59,12 @@ _start(char **ap, void (*cleanup)(void)) env = ap + 2 + argc; handle_argv(argc, argv, env); - if (&_DYNAMIC != NULL) + if (&_DYNAMIC != NULL) { atexit(cleanup); - else + } else { + process_irelocs(); _init_tls(); + } #ifdef GCRT atexit(_mcleanup); diff --git a/lib/csu/amd64/reloc.c b/lib/csu/amd64/reloc.c new file mode 100644 index 000000000000..cc4a7e73caba --- /dev/null +++ b/lib/csu/amd64/reloc.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2018 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +static void +crt1_handle_rela(const Elf_Rela *r) +{ + Elf_Addr *ptr, *where, target; + u_int p[4]; + uint32_t cpu_feature, cpu_feature2; + uint32_t cpu_stdext_feature, cpu_stdext_feature2; + + do_cpuid(1, p); + cpu_feature = p[3]; + cpu_feature2 = p[2]; + do_cpuid(0, p); + if (p[0] >= 7) { + cpuid_count(7, 0, p); + cpu_stdext_feature = p[1]; + cpu_stdext_feature2 = p[2]; + } else { + cpu_stdext_feature = 0; + cpu_stdext_feature2 = 0; + } + + switch (ELF_R_TYPE(r->r_info)) { + case R_X86_64_IRELATIVE: + ptr = (Elf_Addr *)r->r_addend; + where = (Elf_Addr *)r->r_offset; + target = ((Elf_Addr (*)(uint32_t, uint32_t, uint32_t, + uint32_t))ptr)(cpu_feature, cpu_feature2, + cpu_stdext_feature, cpu_stdext_feature2); + *where = target; + break; + } +} diff --git a/lib/csu/arm/Makefile b/lib/csu/arm/Makefile index 53775967349c..8a251f8ca09e 100644 --- a/lib/csu/arm/Makefile +++ b/lib/csu/arm/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS STATIC_CFLAGS+= -mlong-calls FILES= ${OBJS} diff --git a/lib/csu/common/ignore_init.c b/lib/csu/common/ignore_init.c index 6199c778ab52..8712661b44f7 100644 --- a/lib/csu/common/ignore_init.c +++ b/lib/csu/common/ignore_init.c @@ -2,7 +2,10 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2012 Konstantin Belousov - * All rights reserved. + * Copyright (c) 2018 The FreeBSD Foundation + * + * Parts of this software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,7 +32,9 @@ __FBSDID("$FreeBSD$"); #include +#include #include + #include "notes.h" extern int main(int, char **, char **); @@ -46,6 +51,39 @@ extern void _init(void) __hidden; extern int _DYNAMIC; #pragma weak _DYNAMIC +#if defined(CRT_IRELOC_RELA) +extern const Elf_Rela __rela_iplt_start[] __weak_symbol __hidden; +extern const Elf_Rela __rela_iplt_end[] __weak_symbol __hidden; + +#include "reloc.c" + +static void +process_irelocs(void) +{ + const Elf_Rela *r; + + for (r = &__rela_iplt_start[0]; r < &__rela_iplt_end[0]; r++) + crt1_handle_rela(r); +} +#elif defined(CRT_IRELOC_REL) +extern const Elf_Rel __rel_iplt_start[] __weak_symbol __hidden; +extern const Elf_Rel __rel_iplt_end[] __weak_symbol __hidden; + +#include "reloc.c" + +static void +process_irelocs(void) +{ + const Elf_Rel *r; + + for (r = &__rel_iplt_start[0]; r < &__rel_iplt_end[0]; r++) + crt1_handle_rel(r); +} +#elif defined(CRT_IRELOC_SUPPRESS) +#else +#error "Define platform reloc type" +#endif + char **environ; const char *__progname = ""; diff --git a/lib/csu/i386/Makefile b/lib/csu/i386/Makefile index 9ca3f1fcbd87..4e8117f350bc 100644 --- a/lib/csu/i386/Makefile +++ b/lib/csu/i386/Makefile @@ -5,8 +5,9 @@ SRCS= crti.S crtn.S OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= gcrt1.o crt1.o Scrt1.o -CFLAGS+= -I${.CURDIR:H}/common \ +CFLAGS+= -I${.CURDIR} -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_REL FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/i386/crt1_c.c b/lib/csu/i386/crt1_c.c index 8b16f160ea42..b3e6cb330c26 100644 --- a/lib/csu/i386/crt1_c.c +++ b/lib/csu/i386/crt1_c.c @@ -56,10 +56,12 @@ _start1(fptr cleanup, int argc, char *argv[]) env = argv + argc + 1; handle_argv(argc, argv, env); - if (&_DYNAMIC != NULL) + if (&_DYNAMIC != NULL) { atexit(cleanup); - else + } else { + process_irelocs(); _init_tls(); + } #ifdef GCRT atexit(_mcleanup); diff --git a/lib/csu/i386/reloc.c b/lib/csu/i386/reloc.c new file mode 100644 index 000000000000..46551ffc0c22 --- /dev/null +++ b/lib/csu/i386/reloc.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2018 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +static void +crt1_handle_rel(const Elf_Rel *r) +{ + Elf_Addr *where, target; + u_int cpuid_supported, p[4]; + uint32_t cpu_feature, cpu_feature2; + uint32_t cpu_stdext_feature, cpu_stdext_feature2; + + __asm __volatile( + " pushfl\n" + " popl %%eax\n" + " movl %%eax,%%ecx\n" + " xorl $0x200000,%%eax\n" + " pushl %%eax\n" + " popfl\n" + " pushfl\n" + " popl %%eax\n" + " xorl %%eax,%%ecx\n" + " je 1f\n" + " movl $1,%0\n" + " jmp 2f\n" + "1: movl $0,%0\n" + "2:\n" + : "=r" (cpuid_supported) : : "eax", "ecx", "cc"); + if (cpuid_supported) { + do_cpuid(1, p); + cpu_feature = p[3]; + cpu_feature2 = p[2]; + do_cpuid(0, p); + if (p[0] >= 7) { + cpuid_count(7, 0, p); + cpu_stdext_feature = p[1]; + cpu_stdext_feature2 = p[2]; + } else { + cpu_stdext_feature = 0; + cpu_stdext_feature2 = 0; + } + } else { + cpu_feature = 0; + cpu_feature2 = 0; + cpu_stdext_feature = 0; + cpu_stdext_feature2 = 0; + } + + switch (ELF_R_TYPE(r->r_info)) { + case R_386_IRELATIVE: + where = (Elf_Addr *)r->r_offset; + target = ((Elf_Addr (*)(uint32_t, uint32_t, uint32_t, + uint32_t))*where)(cpu_feature, cpu_feature2, + cpu_stdext_feature, cpu_stdext_feature2); + *where = target; + break; + } +} diff --git a/lib/csu/mips/Makefile b/lib/csu/mips/Makefile index 3f34ff351623..df1fe6e2343b 100644 --- a/lib/csu/mips/Makefile +++ b/lib/csu/mips/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/powerpc/Makefile b/lib/csu/powerpc/Makefile index 3f34ff351623..df1fe6e2343b 100644 --- a/lib/csu/powerpc/Makefile +++ b/lib/csu/powerpc/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/powerpc64/Makefile b/lib/csu/powerpc64/Makefile index afd09ca8a2f1..fcacfcb1a90e 100644 --- a/lib/csu/powerpc64/Makefile +++ b/lib/csu/powerpc64/Makefile @@ -7,7 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include \ - -mlongcall + -mlongcall -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/riscv/Makefile b/lib/csu/riscv/Makefile index 3f34ff351623..df1fe6e2343b 100644 --- a/lib/csu/riscv/Makefile +++ b/lib/csu/riscv/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE} diff --git a/lib/csu/sparc64/Makefile b/lib/csu/sparc64/Makefile index 874c377a9400..f87129b5e890 100644 --- a/lib/csu/sparc64/Makefile +++ b/lib/csu/sparc64/Makefile @@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g} OBJS+= Scrt1.o gcrt1.o CFLAGS+= -I${.CURDIR:H}/common \ -I${SRCTOP}/lib/libc/include +CFLAGS+= -DCRT_IRELOC_SUPPRESS FILES= ${OBJS} FILESMODE= ${LIBMODE}