Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Feb 2015 22:10:33 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Konstantin Belousov <kostikbel@gmail.com>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, Bruce Evans <brde@optusnet.com.au>, Bryan Drewery <bdrewery@freebsd.org>
Subject:   Re: svn commit: r278889 - head/lib/libc/include
Message-ID:  <20150219213224.G4526@besplex.bde.org>
In-Reply-To: <20150219092355.GE34251@kib.kiev.ua>
References:  <201502170854.t1H8s4TL085174@svn.freebsd.org> <54E52019.8080009@FreeBSD.org> <20150219113226.K2984@besplex.bde.org> <20150219092355.GE34251@kib.kiev.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 19 Feb 2015, Konstantin Belousov wrote:

> On Thu, Feb 19, 2015 at 11:58:48AM +1100, Bruce Evans wrote:
>>
>> BTW, the reason for existence of __cleanup() has been broken by malloc()
>> and other bloatware.  It is to avoid linking anything in stdio when
>> only exit() is used.  But crtso now links to malloc() and malloc()
>> links to stdio and much more.  When correctly (that is, statically)
>> linked, this bloats the size of a minimal C program from to 440K + 80K
>> symbols on amd64 and to 390K + 60K symbols on i386.  In FreeBSD-4 and
>> in my version of FreeBSD-5, __cleanup still works and the minimal C
>> program has size 2K + 1.5K symbols.  In FreeBSD-5, malloc() is
>> relatively unbloated, so crtso's linking to it costs only 9K + 9K
>> symbols instead of 400+K.  The same program written in asm takes about
>> 10 bytes in all versions of FreeBSD-x86.  When dynamically linked,
>> __cleanup() has little effect.
>
> I briefly looked at the possibility of removing __cleanup (*).  Besides
> ensuring that all stdio FILEs are flushed at exit(3), it also ensures
> that stdio finalization is performed as the last action, after the whole
> chain of atexit(3) handlers was called.  To repeat this behaviour, the
> flush handler must be registered very early, which would just mirror
> special behaviour of __cleanup, but at the startup.
>
> * Bruce, I do understand that your response is that we should fix malloc
> to not depend on stdio instead.

Also, malloc to not be so difficult to replace, and atexit() and possibly
other things called by crtso to not be so large and/or not have such a
large closure including calling malloc().

I use this hack for atexit():

X Index: atexit.c
X ===================================================================
X RCS file: /home/ncvs/src/lib/libc/stdlib/atexit.c,v
X retrieving revision 1.7
X diff -u -2 -r1.7 atexit.c
X --- atexit.c	19 Dec 2003 17:11:20 -0000	1.7
X +++ atexit.c	21 Dec 2003 15:20:28 -0000
X @@ -55,8 +55,15 @@
X  #define	ATEXIT_FN_CXA	2
X 
X +/* XXX how to remove this in non-threaded case? */
X  static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
X 
X -#define _MUTEX_LOCK(x)		if (__isthreaded) _pthread_mutex_lock(x)
X -#define _MUTEX_UNLOCK(x)	if (__isthreaded) _pthread_mutex_unlock(x)
X +#define	_MUTEX_LOCK(x) do {				\
X +	if (__isthreaded)				\
X +		_pthread_mutex_lock(x);			\
X +} while (0)
X +#define _MUTEX_UNLOCK(x) do {				\
X +	if (__isthreaded)				\
X +		_pthread_mutex_unlock(x);		\
X +} while (0)
X 
X  struct atexit {
X @@ -76,4 +83,10 @@
X  static struct atexit *__atexit;		/* points to head of LIFO stack */
X 
X +#pragma weak malloc
X +#pragma weak free
X +#pragma weak __isthreaded
X +#pragma weak _pthread_mutex_lock
X +#pragma weak _pthread_mutex_unlock
X +
X  /*
X   * Register the function described by 'fptr' to be called at application
X @@ -94,6 +107,13 @@
X  		old__atexit = __atexit;
X  	        _MUTEX_UNLOCK(&atexit_mutex);
X -		if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
X -			return (-1);
X +		if (&malloc == NULL) {
X +			p = sbrk(sizeof(*p));
X +			if (p == (struct atexit *)-1)
X +				return (-1);
X +		} else {
X +			p = malloc(sizeof(*p));
X +			if (p == NULL)
X +				return (-1);
X +		}
X  		_MUTEX_LOCK(&atexit_mutex);
X  		if (old__atexit != __atexit) {

BTW, atexit() has uses a space-saving feature that has been broken by
it calling malloc().  This is the static allocation of ATEXIT_SIZE =
32 entries.  Each entry takes 16 bytes on i386.  Most programs should
never call atexit(), so if malloc() is linked then the static table
just wastes the size of 32 entries.  But crtso calls atexit(), so all
C programs except ones linked with -nostdlib call atexit(), and a
couple of statically allocated entries are useful.  However, these
shouldn't be full entries.  Note that __cleanup() is essentially a
specialized version of atexit().  It plus code to call it costs just
a little more than the space for 1 atexit entry, and costs less to set
up.  for 1 entry.  Perhaps all the atexit() calls in crtso can be
handled similarly, so that atexit() is only linked if the application
proper calls it.  Simply place them in exit() in the correct order
relative to __cxa_finalize() and __cleanup().

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150219213224.G4526>