From owner-freebsd-amd64@FreeBSD.ORG Thu Mar 24 08:31:29 2005 Return-Path: Delivered-To: freebsd-amd64@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2D86E16A4CE; Thu, 24 Mar 2005 08:31:29 +0000 (GMT) Received: from mailout1.pacific.net.au (mailout1.pacific.net.au [61.8.0.84]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6CA0243D1F; Thu, 24 Mar 2005 08:31:28 +0000 (GMT) (envelope-from bde@zeta.org.au) Received: from mailproxy2.pacific.net.au (mailproxy2.pacific.net.au [61.8.0.87])j2O8VJA6006225; Thu, 24 Mar 2005 19:31:19 +1100 Received: from katana.zip.com.au (katana.zip.com.au [61.8.7.246]) j2O8VGMq023657; Thu, 24 Mar 2005 19:31:17 +1100 Date: Thu, 24 Mar 2005 19:31:14 +1100 (EST) From: Bruce Evans X-X-Sender: bde@delplex.bde.org To: Vinod Kashyap In-Reply-To: Message-ID: <20050324182524.J97436@delplex.bde.org> References: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed cc: freebsd-stable@freebsd.org cc: freebsd-amd64@freebsd.org Subject: Re: undefined reference to `memset' X-BeenThere: freebsd-amd64@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Porting FreeBSD to the AMD64 platform List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Mar 2005 08:31:29 -0000 On Wed, 23 Mar 2005, Vinod Kashyap wrote: > If any kernel module has the following, or a similar line in it: > ----- > char x[100] = {0}; > ----- I think you mean: ----- auto char x[100] = {0}; ----- or after fixing some style bugs: ----- char x[100] = { 0 }; ----- > building of the GENERIC kernel on FreeBSD 5 -STABLE for amd64 > as of 03/19/05, fails with the following message at the time of linking: > "undefined reference to `memset'". > > The same problem is not seen on i386. > > The problem goes away if the above line is changed to: > ----- > char x[100]; > memset(x, 0, 100); > ----- This version makes the pessimizations and potential bugs clear: - clearing 100 bytes on every entry to the function is wasteful. C90's auto initializers hide pessimizations like this. They should be used very rarely, especially in kernels. But they are often misused, even in kernels, even for read-only data that should be static. gcc doesn't optimize even "auto const x[100] = { 0 };" to a static initialization -- the programmer must declare the object as static to prevent gcc laboriously clearing it on every entry to the function. - 100 bytes may be too much to put on the kernel stack. Objects just a little larger than this must be dynamically allocated unless they can be read-only. > Adding CFLAGS+=-fbuiltin, or CFLAGS+=-fno-builtin to /sys/conf/Makefile.amd64 > does not help. -fno-builtin is already in CFLAGS, and if it has any effect on this then it should be to cause gcc to generate a call to memset() instead of doing the memory clearing inline. I think gcc has a builtin memset() which is turned off by -fno-builtin, but -fno-builtin doesn't affect cases where memset() is not referenced in the source code. -ffreestanding should prevent gcc generating calls to library functions like memset(). However, -ffreestanding is already in CFLAGS too, and there is a problem: certain initializations like the one in your example need to use an interface like memset(), and struct copies need to use and interface like memcpy(), so what is gcc to do when -fno-builtin tells it to turn off its builtins and -ffreestanding tells it that the relevant interfaces might not exist in the library? > Anyone knows what's happening? gcc is expecting that memset() is in the library, but the FreeBSD kernel is freestanding and happens not to have memset() in its library. Related bugs: - the FreeBSD kernel shouldn't have memset() at all. The kernel interface for clearing memory is bzero(). A few files misspelled bzero() as memset() and provided a macro to convert from memset() to bzero(), and instead of fixing them a low-quality memset() was added to . This gives an inline memset() so it doesn't help here. memset() is of some use for setting to nonzero, but this is rarely needed and can easily be repeated as necessary. The support for the nonzero case in is of particularly low quality -- e.g., it crashes if asked to set a length of 0. - memset() to zero and/or gcc methods for initialization to 0 might be much slower than the library's methods for clearing memory. This is not a problem in practice, although bzero() is much faster than gcc's methods in some cases, because: (a) -fno-builtin turns off builtin memset(). (b) the inline memset() just uses bzero() in the fill_byte = 0 case, so using it instead of bzero() is only a tiny pessimization. (c) large copies that bzero() can handle better than gcc's inline method (which is stosl on i386's for your example) cannot because the data would be too large to fit on the kernel statck. - there are slightly different problems for memcpy(): (a) memcpy() is in the library and is not inline, so there is no linkage problem if gcc generates a call to memcpy() for a struct copy. (b) the library memcpy() never uses bcopy(), so it is much slower than bcopy() in much cases. (c) the reason that memcpy() is in the library is to let gcc inline memcpy() for efficiency, but this reason was turned into nonsense by adding -fno-builtin to CFLAGS, and all calls to memcpy() are style bugs and ask for inefficiency. (The inefficiency is small or negative in practice because bzero() has optimizations for large copies that are small pessimizations for non-large copies.) - the FreeBSD kernel shouldn't have memcmp(). It has an inline one that has even lower quality than the inline memset(). memcmp() cannot be implemented using bcmp() since memcmp() is tri-state but bcmp() is boolean, but the inline memcmp() just calls bcmp(). This works, if at all, because nothing actually needs memcmp() and memcmp() is just a misspelling of bcmp(). Bruce