From patchwork Sat May 26 13:52:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 920975 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92778-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="i9KcxkEJ"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40tPgp4R8bz9s0t for ; Sat, 26 May 2018 23:52:21 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:reply-to :mime-version:content-type; q=dns; s=default; b=qVqD9/mWf0VoB6KQ nXDTpgQ+EmRUjCD64o97AArpqLC1lhD69Xkb1vohDfkd9yG44hxH321S9cVDumid xLGPmakqcC0AN3Zrun6uaZAo6ggYw3IQIbaBVQcVNTRAJ1a6oBVNMn5SZtQYWq2F e6FbHLD1zEIjRS93Ab1GHoqtSv0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:reply-to :mime-version:content-type; s=default; bh=cmz9/q+u2BcZLKLgzyICZe nME28=; b=i9KcxkEJfogRk48xpRZa5o24zOy+z1q+MPgyL5nobwoUttbrsb1Ylq lifQ/eFreLbbedYHS3yhQMd7DUTzXvGaBGBK3pkd+nZQuGLBca2bAEQNQOKV7WcO GeGDnrJcUbVP2jbYcW1quL9AByyBC8asHLjXYk+lFCURWVjRPOuJk= Received: (qmail 20465 invoked by alias); 26 May 2018 13:52:14 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 20450 invoked by uid 89); 26 May 2018 13:52:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, NO_DNS_FOR_FROM autolearn=ham version=3.3.2 spammy=do_test, relocated X-HELO: mga14.intel.com X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False X-ExtLoop1: 1 Date: Sat, 26 May 2018 06:52:09 -0700 From: "H.J. Lu" To: GNU C Library Subject: RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240] Message-ID: <20180526135209.GA23818@intel.com> Reply-To: "H.J. Lu" MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.5 (2018-04-13) Since we can't call unrelocated IFUNC function to get the real function addresss, this patch falls back to lazy binding for unrelocated IFUNC symbol. Any comments? H.J. --- [BZ #23240] * elf/Makefile (tests-internal): Add ifuncpreload1 (modules-names): Add ifuncpreloadmod1a and ifuncpreloadmod1b. ($(objpfx)ifuncpreload1): New. ($(objpfx)ifuncpreload1.out): Likewise. (ifuncpreload1-ENV): Likewise. * elf/ifuncpreload1.c: New file. * elf/ifuncpreloadmod1a.c: Likewise. * elf/ifuncpreloadmod1b.c: Likewise. * sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Always set up GOT. (elf_machine_rel): Fall back to lazy binding for unrelocated IFUNC symbol. * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Always set up GOT. (elf_machine_rela): Fall back to lazy binding for unrelocated IFUNC symbol. --- elf/Makefile | 10 ++++++-- elf/ifuncpreload1.c | 39 +++++++++++++++++++++++++++++ elf/ifuncpreloadmod1a.c | 23 +++++++++++++++++ elf/ifuncpreloadmod1b.c | 49 +++++++++++++++++++++++++++++++++++++ sysdeps/i386/dl-machine.h | 22 ++++++++++------- sysdeps/x86_64/dl-machine.h | 22 ++++++++++------- 6 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 elf/ifuncpreload1.c create mode 100644 elf/ifuncpreloadmod1a.c create mode 100644 elf/ifuncpreloadmod1b.c diff --git a/elf/Makefile b/elf/Makefile index 2dcd2b88e0..cb203d58b4 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -328,7 +328,7 @@ tests-internal += \ ifuncmain1staticpic \ ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \ ifuncmain5 ifuncmain5pic ifuncmain5staticpic \ - ifuncmain7 ifuncmain7pic + ifuncmain7 ifuncmain7pic ifuncpreload1 ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \ ifuncdep5 ifuncdep5pic extra-test-objs += $(ifunc-test-modules:=.o) @@ -339,7 +339,8 @@ ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \ tests-internal += $(ifunc-pie-tests) tests-pie += $(ifunc-pie-tests) endif -modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 +modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 \ + ifuncpreloadmod1a ifuncpreloadmod1b endif endif @@ -1454,3 +1455,8 @@ tst-libc_dlvsym-static-ENV = \ $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so + +$(objpfx)ifuncpreload1: $(objpfx)ifuncpreloadmod1a.so +$(objpfx)ifuncpreload1.out: $(objpfx)ifuncpreloadmod1b.so +ifuncpreload1-ENV = \ + LD_PRELOAD=$(objpfx)ifuncpreloadmod1b.so LD_BIND_NOW=1 diff --git a/elf/ifuncpreload1.c b/elf/ifuncpreload1.c new file mode 100644 index 0000000000..172df33ac3 --- /dev/null +++ b/elf/ifuncpreload1.c @@ -0,0 +1,39 @@ +/* Test for relocation over with IFUNC symbols. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +extern void bar (char *, const char *, unsigned int); + +static int +do_test (void) +{ + char dst[50]; + const char src[] = + { + "This is a test" + }; + bar (dst, src, sizeof (src)); + if (__builtin_memcmp (dst, src, sizeof (src)) != 0) + __builtin_abort (); + return 0; +} + +#include diff --git a/elf/ifuncpreloadmod1a.c b/elf/ifuncpreloadmod1a.c new file mode 100644 index 0000000000..be9f8832b8 --- /dev/null +++ b/elf/ifuncpreloadmod1a.c @@ -0,0 +1,23 @@ +/* Shared module to test for relocation over with IFUNC symbols. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +void +bar (char *dst, const char *src, unsigned int size) +{ + __builtin_memmove (dst, src, size); +} diff --git a/elf/ifuncpreloadmod1b.c b/elf/ifuncpreloadmod1b.c new file mode 100644 index 0000000000..1194ae20e4 --- /dev/null +++ b/elf/ifuncpreloadmod1b.c @@ -0,0 +1,49 @@ +/* Shared module to test for relocation over with IFUNC symbols. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void * +my_memmove(void *dst_p, const void *src_p, size_t n) +{ + const char *src = src_p; + char *dst = dst_p; + char *ret = dst; + if (src < dst) + { + dst += n; + src += n; + while (n--) + *--dst = *--src; + } + else + while (n--) + *dst++ = *src++; + return ret; +} + +void *memmove (void *, const void *, size_t) + __attribute__ ((ifunc ("resolve_memmove"))); + +typedef void *(*memmove_t) (void *, const void *, size_t); + +static memmove_t +resolve_memmove (void) +{ + return my_memmove; +} diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index 1afdcbd9ea..4d0afad074 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.h @@ -68,7 +68,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; - if (l->l_info[DT_JMPREL] && lazy) + /* Always set up GOT since we may have to fall back to lazy binding + even with non-lazy binding is requested. */ + if (l->l_info[DT_JMPREL]) { /* The GOT entries for functions in the PLT have not yet been filled in. Their initial contents will arrange when called to push an @@ -332,16 +334,18 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, && sym_map->l_type != lt_executable && !sym_map->l_relocated) { - const char *strtab - = (const char *) D_PTR (map, l_info[DT_STRTAB]); - _dl_error_printf ("\ -%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", - RTLD_PROGNAME, map->l_name, - sym_map->l_name, - strtab + refsym->st_name); + /* NB: The symbol reference is resolved to IFUNC symbol + from a shared object which hasn't been relocated yet. + Relocate the GOT entry to enable lazy binding. */ + value = map->l_addr + *reloc_addr; + /* Disable RELRO so that the GOT entry can updated by lazy + binding later. */ + if (map->l_info[DT_BIND_NOW] != NULL) + map->l_relro_size = 0; } + else # endif - value = ((Elf32_Addr (*) (void)) value) (); + value = ((Elf32_Addr (*) (void)) value) (); } switch (r_type) diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index 1942ed5061..2aff922f96 100644 --- a/sysdeps/x86_64/dl-machine.h +++ b/sysdeps/x86_64/dl-machine.h @@ -73,7 +73,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden; - if (l->l_info[DT_JMPREL] && lazy) + /* Always set up GOT since we may have to fall back to lazy binding + even with non-lazy binding is requested. */ + if (l->l_info[DT_JMPREL]) { /* The GOT entries for functions in the PLT have not yet been filled in. Their initial contents will arrange when called to push an @@ -318,16 +320,18 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, && sym_map->l_type != lt_executable && !sym_map->l_relocated) { - const char *strtab - = (const char *) D_PTR (map, l_info[DT_STRTAB]); - _dl_error_printf ("\ -%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", - RTLD_PROGNAME, map->l_name, - sym_map->l_name, - strtab + refsym->st_name); + /* NB: The symbol reference is resolved to IFUNC symbol + from a shared object which hasn't been relocated yet. + Relocate the GOT entry to enable lazy binding. */ + value = map->l_addr + *reloc_addr; + /* Disable RELRO so that the GOT entry can updated by lazy + binding later. */ + if (map->l_info[DT_BIND_NOW] != NULL) + map->l_relro_size = 0; } + else # endif - value = ((ElfW(Addr) (*) (void)) value) (); + value = ((ElfW(Addr) (*) (void)) value) (); } switch (r_type)