atexit.c has several issues which are fixed by the patch below:


i)
Issuance of calls to functions as registered by atexit() is located in section .fini6a. As the current linker description does not handle that section it's treated as orphan and located conflicting with other sections:

$ avr-gcc main.c -mmcu=atmega128
$INSTALL/lib/gcc/avr/$VERSION/../../../../avr/bin/ld: section .fini6a loaded at [00000390,000003b7] overlaps section .data loaded at [00000390,00000395]
collect2: error: ld returned 1 exit status

The patch moves that code to .fini7 so that atexit functions are sequenced before static destructors which is closest to C++ spec.


ii)
__atexit_fini is not naked thus will crash the program as it is returning.



iii)
In order to arrange the hypothetical case that the code generated by atexit_fini would need a frame it's now in a proper (non-naked) function called by now naked atexit_fini.


iv)
Except atexit, nothing in atexit.c needs to be global --> make static.


Even though atexit is exotic in non-hosted contexts it's nice to see it working, e.g. to reduce testsuite fallout.


Johann

        * libc/stdlib/atexit.c (__atexit_fini): Rename to...
        (atexit_fini): ...this.  Make static, naked, and used.
        Move to section .fini7.  Outsource worker code to...
        (atexit_finido): ...this new function.
        (atexit_p): Renamed from __atexit_p.  Make static.
Index: libc/stdlib/atexit.c
===================================================================
--- libc/stdlib/atexit.c	(revision 2452)
+++ libc/stdlib/atexit.c	(working copy)
@@ -28,7 +28,11 @@
 
 #include <stdlib.h>
 
-struct atexit_s { void (*fun) (void); struct atexit_s *next; } *__atexit_p;
+static struct atexit_s
+{
+  void (*fun) (void);
+  struct atexit_s *next;
+} *atexit_p;
 
 int
 atexit (void (*fun) (void))
@@ -37,18 +41,29 @@ atexit (void (*fun) (void))
   if (!new_as)
     return 1;
   new_as->fun = fun;
-  new_as->next = __atexit_p;
-  __atexit_p = new_as;
+  new_as->next = atexit_p;
+  atexit_p = new_as;
   return 0;
 }
 
-void __attribute__((section(".fini6a")))
-__atexit_fini (void)
+/* Don't inline this code as naked to arrange for the very unlikely case
+   that it needs a frame.   This won't work as naked function.  */
+
+static void __attribute__((__noinline__))
+atexit_finido (void)
 {
-  while (__atexit_p)
+  while (atexit_p)
     {
-      void (*fun) (void) = __atexit_p->fun;
-      __atexit_p = __atexit_p->next;
-      (*fun) ();
+      atexit_p->fun();
+      atexit_p = atexit_p->next;
     }
 }
+
+/* Run functions registered by atexit in .fini7 so that they are
+   sequenced before static destructors which run in .fini6.  */
+
+static void __attribute__((__naked__, __used__, __section__(".fini7")))
+atexit_fini (void)
+{
+  atexit_finido ();
+}
_______________________________________________
AVR-GCC-list mailing list
AVR-GCC-list@nongnu.org
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list

Reply via email to