From owner-freebsd-current@FreeBSD.ORG Fri Jul 4 14:39:00 2014 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 85DB4FD7; Fri, 4 Jul 2014 14:39:00 +0000 (UTC) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F0444208D; Fri, 4 Jul 2014 14:38:56 +0000 (UTC) Received: from tom.home (kostik@localhost [127.0.0.1]) by kib.kiev.ua (8.14.9/8.14.9) with ESMTP id s64EcpAT011045 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 4 Jul 2014 17:38:51 +0300 (EEST) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.8.3 kib.kiev.ua s64EcpAT011045 Received: (from kostik@localhost) by tom.home (8.14.9/8.14.9/Submit) id s64EcoWX011044; Fri, 4 Jul 2014 17:38:50 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Fri, 4 Jul 2014 17:38:50 +0300 From: Konstantin Belousov To: "Ivan A. Kosarev" Subject: Re: Intercepting calls in PIC mode Message-ID: <20140704143850.GH93733@kib.kiev.ua> References: <53B69A43.3000100@ivan-labs.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="JBmVoN0GeLJFe550" Content-Disposition: inline In-Reply-To: <53B69A43.3000100@ivan-labs.com> User-Agent: Mutt/1.5.23 (2014-03-12) X-Spam-Status: No, score=-2.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on tom.home Cc: toolchain@freebsd.org, freebsd-current@freebsd.org X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 04 Jul 2014 14:39:00 -0000 --JBmVoN0GeLJFe550 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Fri, Jul 04, 2014 at 04:12:51PM +0400, Ivan A. Kosarev wrote: > Hello, >=20 > Consider the following: >=20 > --- > #include > #include >=20 > extern "C" void* memset(void *block, int c, size_t size) > __attribute__((weak, alias("__int_memset"), visibility("default"))); >=20 > extern "C" __attribute__((visibility("default"))) > void* __int_memset(void *block, int c, size_t size) { > puts("Hello"); > return NULL; > } >=20 > int main() > { > void *(*F)(void *b, int c, size_t len) =3D memset; > char a[5]; > memset(a, 0, sizeof(a)); > F(a, 0, sizeof(a)); > return 0; > } > --- >=20 > It intercepts the memset() calls without issue on both x86-64 FreeBSD=20 > 9.2 and Linux. However, with the -fPIC option specified in the cc's=20 > command line, only the first (direct) call work on FreeBSD, but not the= =20 > second (indirect) one. Note is that on Linux both the calls are=20 > intercepted--no matter whether the -fPIC option is specified or not. Your example is rather convoluted, I will try to explain below why. First, I am sure that C99 does not allow to override the semantic of the standard-defined functions. That said, a call to memset(3) can be inlined by a compiler, so there could be nothing to intercept. Second, FreeBSD implementation of the weak ELF symbols is non-compliant. The dynamic linker prioritizes non-weak symbols over the weak. This at least explains why your code snippet does not segfaults: the memset(3) =66rom libc is not interposed by your memset() implementation, so libc can at least initialize itself. If you remove weak attribute from the memset(), debug version of libc fails with assertions in jemalloc, while normal build just segfaults. That said, there are also differences in the static linker behaviour. Clang generates the following code to obtain the address of the memset(3) function: movq memset@GOTPCREL(%rip), %rsi The in-tree ld from binutils 2.17.redhat generates the R_X86_64_GLOB_DAT relocation to fill the GOT entry for the memset symbol. Processor of the GLOB_DAT in the rtld-elf always starts the lookup of the requested symbol in the object next from main. For your code, this means libc is searched for memset to fill the slot, and you get a libc symbol. The ld from the stock build of binutils 2.24, on the other hand, does not generate a relocation at all, it resolves memset internally from the same object file and fills the offset directly into instruction. I.e., when the program is linked with new ld, it works as you intend. This is probably the reason why it worked for you on Linux. I am not sure what conclusion could be made from the story I just told you. Might be, 'do not try to interpose std C functions' and 'put interposers into the LD_PRELOADed objects' ? --JBmVoN0GeLJFe550 Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBAgAGBQJTtrx6AAoJEJDCuSvBvK1B42YP/21lu2qUek1o0EsT/ePohCSX f32abyLwhhZkG1RGlpoeHvOtGBsJhZ2xSHFVgLd+zMbvJ2Yx4H9U+7+zcybSGTB3 J9g2FmkOH4/SXN+SkSijt/T8gVz+JKdcb8nB/EhPcZBxVBrvv7VSs3e62yFLC7aJ bil4OkAvEqQvi0w7Qw0Jj2IDjSgqIQkBg5l+rBeayCS695oSxsgIFXz0+Nz8jhqY U0VizVeLwYuUbczqsvItoyMQM/JTKyuqEb/yGK/iMR0bNoR85wyp4nM+bawYmjkr abF2fGmoshDafbAemDpWc2KCGds76O+RBtpGTY5nIKt/BmgRw8gBHlCzkA5DRjjU uEAG5c4M23IST0G1u44feuk6k+6fcxmNgPX+H/k6iTA01mNlfMI2jIaoC6RvIUKL MHtQijVZXtnrlgDkgVaE/8lYz+SeK7q38GmD72f/s7LIBh/UVSo9NCzKe1MAEGe2 +Nqhz34Hby5L+bsYKVSS4O8EeP04qH9Y21Pa7YXWzAA+ynsGcShBl/H//L/gX55g v2JTRAAPjkJ5MB8ypiOig0KxE1fB33GNmK193eYqWOCK50wL6dYW9zpaVf2U1lRP WFM2aUBK6iJQqxSE81NhzZpIlHVWlvJWoA2oG9Eyl8fZgsyocOjrKynyz4ZBiIiA kAmd9HTGfvPuxzjo8ixp =GF6d -----END PGP SIGNATURE----- --JBmVoN0GeLJFe550--