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