This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Disable dynamic allocation in atexit


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
      }
  }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]