PATCH: Disable dynamic allocation in atexit

Jeff Johnston jjohnstn@redhat.com
Mon Mar 20 22:26:00 GMT 2006


Mark,

   The patch is fine, but it's got me thinking I want to do a bit more. 
  I have Nick Clifton's problem from a week ago to contend with.  I am 
not happy with his patch as the code becomes incredibly ugly.

   What I am thinking of doing is rewriting atexit and not having 
separate logic for _REENT_SMALL.  The code will simply use the static 
list first and then allocate, if enabled.  By default, _REENT_SMALL will 
have a small number of static entries (e.g. 3) and will by default 
support dynamic allocation of remaining entries (e.g. 3 at a time).  The 
code for atexit, etc.. becomes more simplified and the platforms can 
tune their settings accordingly by setting the initial atexit list size.

   The one question I am pondering is whether to make 
static-only-32-entry, the default for non-_REENT_SMALL platforms. 
Normally I preach backwards-compatibility, but I can't think of any 
applications off-hand that should require more than 32 entries.  This 
makes the empty program compact by default which I think is a good thing.

   Enablement/disablement must be accessible in configure.host so 
platforms can set a default accordingly.

   Comments?

-- Jeff J.

Mark Mitchell wrote:
> I noticed recently that "int main() {}" was a 9K program for an ARM
> Thumb-2 configuration.  Since some target hardware in this space is
> extremely memory constrained (e.g., 8K ROM), I looked a little bit at
> the issues.  With the patches in my tree, I got that 9K down to about
> 800 bytes.  Lest you then ask "So, why use newlib at all?", string
> routines, basic math routines, etc., are all relatively small.
> 
> By far the biggest issue was that we're pulling in malloc, and the
> primary reason for that (outside of some ARM-specific issues that I
> will post as follow-on patches) is that crt0 registers fini via
> atexit, and atexit calls malloc, and malloc is big.  This patch
> provides a configure option to limit atexit to the 32 routines
> required by ISO C and provided via static allocation in newlib.
> 
> Since these systems generally don't exit, it might be even better just
> to dispense with registration of finalizers entirely, possibly based
> on some kind of automatic detection.  It might also be better for
> _exit to directly call a "system finalizer" (e.g., _fini), rather than
> relying on atexit (we *know* that _fini is the last finalizer to
> call), which would also avoid pulling in atexit.  However, we still
> need the attached patch so that routines register with atexit by the
> user do not pull in malloc/free.  So, I think this is unambiguosly
> useful, on its own, even if we decide to get more clever later.
> 
> OK to commit?
> 
> --
> Mark Mitchell
> CodeSourcery
> mark@codesourcery.com
> (650) 331-3385 x713
> 
> 2006-03-17  Mark Mitchell  <mark@codesourcery.com>
> 
> 	* acconfig.h (_ATEXIT_DYNAMIC_ALLOC): Undef.
> 	* configure.in (--disable-newlib-atexit-dynamic-alloc): New
> 	option. 
> 	* configure: Regenerated.
> 	* newlib.hin: Regenerated.
> 	* libc/stdlib/__atexit.c (__register_exitproc): Don't call malloc
> 	if _ATEXIT_DYNAMIC_ALLOC is undefined.
> 	* libc/stdlib/__call_atexit.c (__call_exitprocs): Don't call free
> 	if _ATEXIT_DYNAMIC_ALLOC is undefined.
> 
> Index: acconfig.h
> ===================================================================
> RCS file: /cvs/src/src/newlib/acconfig.h,v
> retrieving revision 1.1
> diff -c -5 -p -r1.1 acconfig.h
> *** acconfig.h	20 Jan 2006 22:42:45 -0000	1.1
> --- acconfig.h	18 Mar 2006 01:20:00 -0000
> ***************
> *** 32,41 ****
> --- 32,45 ----
>   
>   /* Define if the linker supports .preinit_array/.init_array/.fini_array
>    * sections.  */
>   #undef  HAVE_INITFINI_ARRAY
>   
> + /* True if atexit() may dynamically allocate space for cleanup
> +    functions.  */
> + #undef  _ATEXIT_DYNAMIC_ALLOC
> + 
>   /* Define if the compiler supports aliasing an array to an address.  */
>   #undef  _HAVE_ARRAY_ALIASING
>   @BOTTOM@
>   /*
>    * Iconv encodings enabled ("to" direction)
> Index: configure.in
> ===================================================================
> RCS file: /cvs/src/src/newlib/configure.in,v
> retrieving revision 1.28
> diff -c -5 -p -r1.28 configure.in
> *** configure.in	31 Aug 2005 20:39:40 -0000	1.28
> --- configure.in	18 Mar 2006 01:20:00 -0000
> *************** AC_ARG_ENABLE(newlib-iconv-external-ccs,
> *** 83,92 ****
> --- 83,103 ----
>        no)  newlib_iconv_external_ccs=no ;;
>        *)   AC_MSG_ERROR(bad value ${enableval} for newlib-iconv-external-ccs option) ;;
>      esac
>    fi], [newlib_iconv_external_ccs=${newlib_iconv_external_ccs}])dnl
>   
> + dnl Support --disable-newlib-atexit-dynamic-alloc
> + AC_ARG_ENABLE(newlib-atexit-dynamic-alloc,
> + [  --disable-newlib-atexit-alloc    disable dynamic allocation of atexit entries],
> + [if test "${newlib_atexit_dynamic_alloc+set}" != set; then
> +   case "${enableval}" in
> +     yes) newlib_atexit_dynamic_alloc=yes ;;
> +     no)  newlib_atexit_dynamic_alloc=no  ;;
> +     *)   AC_MSG_ERROR(bad value ${enableval} for newlib-atexit-dynamic-alloc option) ;;
> +   esac
> +  fi], [newlib_atexit_dynamic_alloc=yes])dnl
> + 
>   NEWLIB_CONFIGURE(.)
>   
>   dnl We have to enable libtool after NEWLIB_CONFIGURE because if we try and
>   dnl add it into NEWLIB_CONFIGURE, executable tests are made before the first
>   dnl line of the macro which fail because appropriate LDFLAGS are not set.
> *************** fi
> *** 230,239 ****
> --- 241,254 ----
>   
>   if test "${newlib_iconv_external_ccs}" = "yes"; then
>   AC_DEFINE_UNQUOTED(_ICONV_ENABLE_EXTERNAL_CCS)
>   fi
>   
> + if test "${newlib_atexit_dynamic_alloc}" = "yes"; then
> + AC_DEFINE_UNQUOTED(_ATEXIT_DYNAMIC_ALLOC)
> + fi
> + 
>   AC_DEFINE_UNQUOTED(_NEWLIB_VERSION,"$VERSION")
>   
>   if test "${multilib}" = "yes"; then
>     multilib_arg="--enable-multilib"
>   else
> Index: libc/stdlib/__atexit.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdlib/__atexit.c,v
> retrieving revision 1.3
> diff -c -5 -p -r1.3 __atexit.c
> *** libc/stdlib/__atexit.c	15 Sep 2004 20:50:07 -0000	1.3
> --- libc/stdlib/__atexit.c	18 Mar 2006 01:20:00 -0000
> *************** _DEFUN (__register_exitproc,
> *** 33,42 ****
> --- 33,45 ----
>     p = _GLOBAL_REENT->_atexit;
>     if (p == NULL)
>       _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0;
>     if (p->_ind >= _ATEXIT_SIZE)
>       {
> + #ifndef _ATEXIT_DYNAMIC_ALLOC
> +       return -1;
> + #else
>         p = (struct _atexit *) malloc (sizeof *p);
>         if (p == NULL)
>   	{
>   #ifndef __SINGLE_THREAD__
>   	  __lock_release(lock);
> *************** _DEFUN (__register_exitproc,
> *** 48,57 ****
> --- 51,61 ----
>         _GLOBAL_REENT->_atexit = p;
>   #ifndef _REENT_SMALL
>         p->_on_exit_args._fntypes = 0;
>         p->_on_exit_args._is_cxa = 0;
>   #endif
> + #endif
>       }
>   
>     if (type != __et_atexit)
>       {
>   #ifdef _REENT_SMALL
> Index: libc/stdlib/__call_atexit.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdlib/__call_atexit.c,v
> retrieving revision 1.3
> diff -c -5 -p -r1.3 __call_atexit.c
> *** libc/stdlib/__call_atexit.c	15 Sep 2004 20:50:07 -0000	1.3
> --- libc/stdlib/__call_atexit.c	18 Mar 2006 01:20:00 -0000
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 59,68 ****
> --- 59,71 ----
>   	    (*((void (*)(int, _PTR)) fn))(code, args->_fnargs[n]);
>   	  else
>   	    (*((void (*)(_PTR)) fn))(args->_fnargs[n]);
>   	}
>   
> + #ifndef _ATEXIT_DYNAMIC_ALLOC
> +       break;
> + #else
>         /* Move to the next block.  Free empty blocks except the last one,
>   	 which is part of _GLOBAL_REENT.  */
>         if (p->_ind == 0 && p->_next)
>   	{
>   	  /* Remove empty block from the list.  */
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 77,83 ****
> --- 80,87 ----
>         else
>   	{
>   	  lastp = &p->_next;
>   	  p = p->_next;
>   	}
> + #endif
>       }
>   }



More information about the Newlib mailing list