[Git][ghc/ghc][wip/T21847] rts/linker: Consolidate initializer/finalizer handling

Ben Gamari (@bgamari) gitlab at gitlab.haskell.org
Fri Aug 12 17:01:31 UTC 2022



Ben Gamari pushed to branch wip/T21847 at Glasgow Haskell Compiler / GHC


Commits:
9ae87307 by Ben Gamari at 2022-08-12T13:01:20-04:00
rts/linker: Consolidate initializer/finalizer handling

Here we extend our treatment of initializer/finalizer priorities to
include ELF and in so doing refactor things to share the implementation
with PEi386. As well, I fix a subtle misconception of the ordering
behavior for `.ctors`.

Fixes #21847.

- - - - -


7 changed files:

- rts/linker/Elf.c
- rts/linker/ElfTypes.h
- + rts/linker/InitFini.c
- + rts/linker/InitFini.h
- rts/linker/PEi386.c
- rts/linker/PEi386Types.h
- rts/rts.cabal.in


Changes:

=====================================
rts/linker/Elf.c
=====================================
@@ -25,7 +25,6 @@
 #include "ForeignExports.h"
 #include "Profiling.h"
 #include "sm/OSMem.h"
-#include "GetEnv.h"
 #include "linker/util.h"
 #include "linker/elf_util.h"
 
@@ -710,6 +709,63 @@ ocGetNames_ELF ( ObjectCode* oc )
       StgWord size = shdr[i].sh_size;
       StgWord offset = shdr[i].sh_offset;
       StgWord align = shdr[i].sh_addralign;
+      const char *sh_name = oc->info->sectionHeaderStrtab + shdr[i].sh_name;
+
+      /*
+       * Identify initializer and finalizer lists
+       *
+       * See Note [Initializers and finalizers (ELF)].
+       */
+      if (kind == SECTIONKIND_CODE_OR_RODATA
+            && 0 == memcmp(".init", sh_name, 5)) {
+          addInitFini(&oc->info->init, &oc->sections[i], INITFINI_INIT, 0);
+      } else if (kind == SECTIONKIND_INIT_ARRAY
+            || 0 == memcmp(".init_array", sh_name, 11)) {
+          uint32_t prio;
+          if (sscanf(sh_name, ".init_array.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
+          }
+          prio += 0x10000; // .init_arrays run after .ctors
+          addInitFini(&oc->info->init, &oc->sections[i], INITFINI_INIT_ARRAY, prio);
+          kind = SECTIONKIND_INIT_ARRAY;
+      } else if (kind == SECTIONKIND_FINI_ARRAY
+            || 0 == memcmp(".fini_array", sh_name, 11)) {
+          uint32_t prio;
+          if (sscanf(sh_name, ".fini_array.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
+          }
+          prio += 0x10000; // .fini_arrays run before .dtors
+          addInitFini(&oc->info->fini, &oc->sections[i], INITFINI_FINI_ARRAY, prio);
+          kind = SECTIONKIND_FINI_ARRAY;
+
+      /* N.B. a compilation unit may have more than one .ctor section; we
+       * must run them all. See #21618 for a case where this happened */
+      } else if (0 == memcmp(".ctors", sh_name, 6)) {
+          uint32_t prio;
+          if (sscanf(sh_name, ".ctors.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
+          }
+          // .ctors/.dtors are executed in reverse order: higher numbers are
+          // executed first
+          prio = 0xffff - prio;
+          addInitFini(&oc->info->init, &oc->sections[i], INITFINI_CTORS, prio);
+          kind = SECTIONKIND_INIT_ARRAY;
+      } else if (0 == memcmp(".dtors", sh_name, 6)) {
+          uint32_t prio;
+          if (sscanf(sh_name, ".dtors.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
+          }
+          // .ctors/.dtors are executed in reverse order: higher numbers are
+          // executed first
+          prio = 0xffff - prio;
+          addInitFini(&oc->info->fini, &oc->sections[i], INITFINI_DTORS, prio);
+          kind = SECTIONKIND_FINI_ARRAY;
+      }
+
 
       if (is_bss && size > 0) {
          /* This is a non-empty .bss section.  Allocate zeroed space for
@@ -848,13 +904,9 @@ ocGetNames_ELF ( ObjectCode* oc )
           oc->sections[i].info->stub_size = 0;
           oc->sections[i].info->stubs = NULL;
       }
-      oc->sections[i].info->name          = oc->info->sectionHeaderStrtab
-                                            + shdr[i].sh_name;
+      oc->sections[i].info->name          = sh_name;
       oc->sections[i].info->sectionHeader = &shdr[i];
 
-
-
-
       if (shdr[i].sh_type != SHT_SYMTAB) continue;
 
       /* copy stuff into this module's object symbol table */
@@ -1971,62 +2023,10 @@ ocResolve_ELF ( ObjectCode* oc )
 // See Note [Initializers and finalizers (ELF)].
 int ocRunInit_ELF( ObjectCode *oc )
 {
-   Elf_Word i;
-   char*     ehdrC = (char*)(oc->image);
-   Elf_Ehdr* ehdr  = (Elf_Ehdr*) ehdrC;
-   Elf_Shdr* shdr  = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
-   char* sh_strtab = ehdrC + shdr[elf_shstrndx(ehdr)].sh_offset;
-   int argc, envc;
-   char **argv, **envv;
-
-   getProgArgv(&argc, &argv);
-   getProgEnvv(&envc, &envv);
-
-   // XXX Apparently in some archs .init may be something
-   // special!  See DL_DT_INIT_ADDRESS macro in glibc
-   // as well as ELF_FUNCTION_PTR_IS_SPECIAL.  We've not handled
-   // it here, please file a bug report if it affects you.
-   for (i = 0; i < elf_shnum(ehdr); i++) {
-      init_t *init_start, *init_end, *init;
-      char *sh_name = sh_strtab + shdr[i].sh_name;
-      int is_bss = false;
-      SectionKind kind = getSectionKind_ELF(&shdr[i], &is_bss);
-
-      if (kind == SECTIONKIND_CODE_OR_RODATA
-       && 0 == memcmp(".init", sh_name, 5)) {
-          init_t init_f = (init_t)(oc->sections[i].start);
-          init_f(argc, argv, envv);
-      }
-
-      // Note [GCC 6 init/fini section workaround]
-      if (kind == SECTIONKIND_INIT_ARRAY
-          || 0 == memcmp(".init_array", sh_name, 11)) {
-         char *init_startC = oc->sections[i].start;
-         init_start = (init_t*)init_startC;
-         init_end = (init_t*)(init_startC + shdr[i].sh_size);
-         for (init = init_start; init < init_end; init++) {
-            CHECK(0x0 != *init);
-            (*init)(argc, argv, envv);
-         }
-      }
-
-      // XXX could be more strict and assert that it's
-      // SECTIONKIND_RWDATA; but allowing RODATA seems harmless enough.
-      if ((kind == SECTIONKIND_RWDATA || kind == SECTIONKIND_CODE_OR_RODATA)
-       && 0 == memcmp(".ctors", sh_strtab + shdr[i].sh_name, 6)) {
-         char *init_startC = oc->sections[i].start;
-         init_start = (init_t*)init_startC;
-         init_end = (init_t*)(init_startC + shdr[i].sh_size);
-         // ctors run in reverse
-         for (init = init_end - 1; init >= init_start; init--) {
-            CHECK(0x0 != *init);
-            (*init)(argc, argv, envv);
-         }
-      }
-   }
-
-   freeProgEnvv(envc, envv);
-   return 1;
+    if (oc && oc->info && oc->info->init) {
+        return runInit(&oc->info->init);
+    }
+    return true;
 }
 
 // Run the finalizers of an ObjectCode.
@@ -2034,46 +2034,10 @@ int ocRunInit_ELF( ObjectCode *oc )
 // See Note [Initializers and finalizers (ELF)].
 int ocRunFini_ELF( ObjectCode *oc )
 {
-   char*     ehdrC = (char*)(oc->image);
-   Elf_Ehdr* ehdr  = (Elf_Ehdr*) ehdrC;
-   Elf_Shdr* shdr  = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
-   char* sh_strtab = ehdrC + shdr[elf_shstrndx(ehdr)].sh_offset;
-
-   for (Elf_Word i = 0; i < elf_shnum(ehdr); i++) {
-      char *sh_name = sh_strtab + shdr[i].sh_name;
-      int is_bss = false;
-      SectionKind kind = getSectionKind_ELF(&shdr[i], &is_bss);
-
-      if (kind == SECTIONKIND_CODE_OR_RODATA && 0 == memcmp(".fini", sh_strtab + shdr[i].sh_name, 5)) {
-         fini_t fini_f = (fini_t)(oc->sections[i].start);
-         fini_f();
-      }
-
-      // Note [GCC 6 init/fini section workaround]
-      if (kind == SECTIONKIND_FINI_ARRAY
-          || 0 == memcmp(".fini_array", sh_name, 11)) {
-         fini_t *fini_start, *fini_end, *fini;
-         char *fini_startC = oc->sections[i].start;
-         fini_start = (fini_t*)fini_startC;
-         fini_end = (fini_t*)(fini_startC + shdr[i].sh_size);
-         for (fini = fini_start; fini < fini_end; fini++) {
-            CHECK(0x0 != *fini);
-            (*fini)();
-         }
-      }
-
-      if (kind == SECTIONKIND_CODE_OR_RODATA && 0 == memcmp(".dtors", sh_strtab + shdr[i].sh_name, 6)) {
-         char *fini_startC = oc->sections[i].start;
-         fini_t *fini_start = (fini_t*)fini_startC;
-         fini_t *fini_end = (fini_t*)(fini_startC + shdr[i].sh_size);
-         for (fini_t *fini = fini_start; fini < fini_end; fini++) {
-            CHECK(0x0 != *fini);
-            (*fini)();
-         }
-      }
-   }
-
-   return 1;
+    if (oc && oc->info && oc->info->fini) {
+        return runFini(&oc->info->fini);
+    }
+    return true;
 }
 
 /*


=====================================
rts/linker/ElfTypes.h
=====================================
@@ -6,6 +6,7 @@
 #include "ghcplatform.h"
 
 #include <elf.h>
+#include "linker/InitFini.h"
 
 /*
  * Define a set of types which can be used for both ELF32 and ELF64
@@ -137,6 +138,8 @@ struct ObjectCodeFormatInfo {
     ElfRelocationTable   *relTable;
     ElfRelocationATable  *relaTable;
 
+    struct InitFiniList* init; // Freed by ocRunInit_PEi386
+    struct InitFiniList* fini; // Freed by ocRunFini_PEi386
 
     /* pointer to the global offset table */
     void *                got_start;
@@ -164,7 +167,7 @@ struct SectionFormatInfo {
     size_t nstubs;
     Stub * stubs;
 
-    char * name;
+    const char * name;
 
     Elf_Shdr *sectionHeader;
 };


=====================================
rts/linker/InitFini.c
=====================================
@@ -0,0 +1,196 @@
+#include "Rts.h"
+#include "RtsUtils.h"
+#include "LinkerInternals.h"
+#include "GetEnv.h"
+#include "InitFini.h"
+
+/*
+ * Note [Initializers and finalizers (PEi386/ELF)]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Most ABIs allow an object to define initializers and finalizers to be run
+ * at load/unload time, respectively. These are represented in two ways:
+ *
+ *  - a `.init`/`.fini` section which contains a function of type init_t which
+ *    is to be executed during initialization/finalization.
+ *
+ *  - `.ctors`/`.dtors` sections; these contain an array of pointers to
+ *    `init_t`/`fini_t` functions, all of which should be executed at
+ *    initialization/finalization time. The `.ctors` entries are run in reverse
+ *    order. The list may end in a 0 or -1 sentinel value.
+ *
+ *  - `.init_array`/`.fini_array` sections; these contain an array
+ *    of pointers to `init_t`/`fini_t` functions.
+ *
+ * Objects may contain multiple `.ctors`/`.dtors` and
+ * `.init_array`/`.fini_array` sections, each optionally suffixed with an
+ * 16-bit integer priority (e.g. `.init_array.1234`). Confusingly, `.ctors`
+ * priorities and `.init_array` priorities have different orderings: `.ctors`
+ * sections are run from high to low priority whereas `.init_array` sections
+ * are run from low-to-high.
+ *
+ * Sections without a priority (e.g.  `.ctors`) are assumed to run last (that
+ * is, are given a priority of 0xffff).
+ *
+ * In general, we run finalizers in the reverse order of the associated
+ * initializers. That is to say, e.g., .init_array entries are run from first
+ * to last entry and therefore .fini_array entries are run from last-to-first.
+ *
+ * To determine the ordering among the various section types, we follow glibc's
+ * model:
+ *
+ *  - first run .ctors (last entry to first entry)
+ *  - then run .init_arrays (first-to-last)
+ *
+ * and on unload we run in opposite order:
+ *
+ *  - first run fini_arrays (first-to-last)
+ *  - then run .dtors (last-to-first)
+ *
+ * For more about how the code generator emits initializers and finalizers see
+ * Note [Initializers and finalizers in Cmm] in GHC.Cmm.InitFini.
+ */
+
+// Priority follows the init_array definition: initializers are run
+// lowest-to-highest, finalizers run highest-to-lowest.
+void addInitFini(struct InitFiniList **head, Section *section, enum InitFiniKind kind, uint32_t priority)
+{
+    struct InitFiniList *slist = stgMallocBytes(sizeof(struct InitFiniList), "addInitFini");
+    slist->section = section;
+    slist->kind = kind;
+    slist->priority = priority;
+    slist->next = *head;
+    *head = slist;
+}
+
+enum SortOrder { INCREASING, DECREASING };
+
+// Sort a InitFiniList by priority.
+static void sortInitFiniList(struct InitFiniList **slist, enum SortOrder order)
+{
+    // Bubble sort
+    bool done = false;
+    while (!done) {
+        struct InitFiniList **last = slist;
+        done = true;
+        while (*last != NULL && (*last)->next != NULL) {
+            struct InitFiniList *s0 = *last;
+            struct InitFiniList *s1 = s0->next;
+            bool flip;
+            switch (order) {
+                case INCREASING: flip = s0->priority > s1->priority; break;
+                case DECREASING: flip = s0->priority < s1->priority; break;
+            }
+            if (flip) {
+                s0->next = s1->next;
+                s1->next = s0;
+                *last = s1;
+                done = false;
+            } else {
+                last = &s0->next;
+            }
+        }
+    }
+}
+
+void freeInitFiniList(struct InitFiniList *slist)
+{
+    while (slist != NULL) {
+        struct InitFiniList *next = slist->next;
+        stgFree(slist);
+        slist = next;
+    }
+}
+
+static bool runInitFini(struct InitFiniList **head)
+{
+    int argc, envc;
+    char **argv, **envv;
+
+    getProgArgv(&argc, &argv);
+    getProgEnvv(&envc, &envv);
+
+    for (struct InitFiniList *slist = *head;
+           slist != NULL;
+           slist = slist->next)
+    {
+        Section *section = slist->section;
+        switch (slist->kind) {
+        case INITFINI_INIT: {
+            init_t *init = (init_t*)section->start;
+            (*init)(argc, argv, envv);
+            break;
+        }
+        case INITFINI_CTORS: {
+            uint8_t *init_startC = section->start;
+            init_t *init_start   = (init_t*)init_startC;
+            init_t *init_end     = (init_t*)(init_startC + section->size);
+
+            // ctors are run *backwards*!
+            for (init_t *init = init_end - 1; init >= init_start; init--) {
+                if ((intptr_t) *init == 0x0 || (intptr_t)init == -1) {
+                    continue;
+                }
+                (*init)(argc, argv, envv);
+            }
+            break;
+        }
+        case INITFINI_DTORS: {
+            char *fini_startC = section->start;
+            fini_t *fini_start = (fini_t*)fini_startC;
+            fini_t *fini_end = (fini_t*)(fini_startC + section->size);
+            for (fini_t *fini = fini_start; fini < fini_end; fini++) {
+                if ((intptr_t) *fini == 0x0 || (intptr_t) *fini == -1) {
+                    continue;
+                }
+                (*fini)();
+            }
+            break;
+        }
+        case INITFINI_INIT_ARRAY: {
+            char *init_startC = section->start;
+            init_t *init_start = (init_t*)init_startC;
+            init_t *init_end = (init_t*)(init_startC + section->size);
+            for (init_t *init = init_start; init < init_end; init++) {
+                CHECK(0x0 != *init);
+                (*init)(argc, argv, envv);
+            }
+            break;
+        }
+        case INITFINI_FINI_ARRAY: {
+            char *fini_startC = section->start;
+            fini_t *fini_start = (fini_t*)fini_startC;
+            fini_t *fini_end = (fini_t*)(fini_startC + section->size);
+            // .fini_array finalizers are run backwards
+            for (fini_t *fini = fini_end - 1; fini >= fini_start; fini--) {
+                CHECK(0x0 != *fini);
+                (*fini)();
+            }
+            break;
+        }
+        default: barf("unknown InitFiniKind");
+        }
+    }
+    freeInitFiniList(*head);
+    *head = NULL;
+
+    freeProgEnvv(envc, envv);
+    return true;
+}
+
+// Run the constructors/initializers of an ObjectCode.
+// Returns 1 on success.
+// See Note [Initializers and finalizers (PEi386/ELF)].
+bool runInit(struct InitFiniList **head)
+{
+    sortInitFiniList(head, INCREASING);
+    return runInitFini(head);
+}
+
+// Run the finalizers of an ObjectCode.
+// Returns 1 on success.
+// See Note [Initializers and finalizers (PEi386/ELF)].
+bool runFini(struct InitFiniList **head)
+{
+    sortInitFiniList(head, DECREASING);
+    return runInitFini(head);
+}


=====================================
rts/linker/InitFini.h
=====================================
@@ -0,0 +1,22 @@
+#pragma once
+
+enum InitFiniKind {
+    INITFINI_INIT,       // .init section
+    INITFINI_CTORS,      // .ctors section
+    INITFINI_DTORS,      // .dtors section
+    INITFINI_INIT_ARRAY, // .init_array section
+    INITFINI_FINI_ARRAY, // .fini_array section
+};
+
+// A linked-list of initializer or finalizer sections.
+struct InitFiniList {
+    Section *section;
+    uint32_t priority;
+    enum InitFiniKind kind;
+    struct InitFiniList *next;
+};
+
+void addInitFini(struct InitFiniList **slist, Section *section, enum InitFiniKind kind, uint32_t priority);
+void freeInitFiniList(struct InitFiniList *slist);
+bool runInit(struct InitFiniList **slist);
+bool runFini(struct InitFiniList **slist);


=====================================
rts/linker/PEi386.c
=====================================
@@ -308,7 +308,6 @@
 
 #include "RtsUtils.h"
 #include "RtsSymbolInfo.h"
-#include "GetEnv.h"
 #include "CheckUnload.h"
 #include "LinkerInternals.h"
 #include "linker/PEi386.h"
@@ -386,45 +385,6 @@ const int default_alignment = 8;
    the pointer as a redirect.  Essentially it's a DATA DLL reference.  */
 const void* __rts_iob_func = (void*)&__acrt_iob_func;
 
-enum SortOrder { INCREASING, DECREASING };
-
-// Sort a SectionList by priority.
-static void sortSectionList(struct SectionList **slist, enum SortOrder order)
-{
-    // Bubble sort
-    bool done = false;
-    while (!done) {
-        struct SectionList **last = slist;
-        done = true;
-        while (*last != NULL && (*last)->next != NULL) {
-            struct SectionList *s0 = *last;
-            struct SectionList *s1 = s0->next;
-            bool flip;
-            switch (order) {
-                case INCREASING: flip = s0->priority > s1->priority; break;
-                case DECREASING: flip = s0->priority < s1->priority; break;
-            }
-            if (flip) {
-                s0->next = s1->next;
-                s1->next = s0;
-                *last = s1;
-                done = false;
-            } else {
-                last = &s0->next;
-            }
-        }
-    }
-}
-
-static void freeSectionList(struct SectionList *slist)
-{
-    while (slist != NULL) {
-        struct SectionList *next = slist->next;
-        stgFree(slist);
-        slist = next;
-    }
-}
-
 void initLinker_PEi386()
 {
     if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
@@ -553,8 +513,8 @@ static void releaseOcInfo(ObjectCode* oc) {
     if (!oc) return;
 
     if (oc->info) {
-        freeSectionList(oc->info->init);
-        freeSectionList(oc->info->fini);
+        freeInitFiniList(oc->info->init);
+        freeInitFiniList(oc->info->fini);
         stgFree (oc->info->ch_info);
         stgFree (oc->info->symbols);
         stgFree (oc->info->str_tab);
@@ -1513,26 +1473,28 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       if (0==strncmp(".ctors", section->info->name, 6)) {
           /* N.B. a compilation unit may have more than one .ctor section; we
            * must run them all. See #21618 for a case where this happened */
-          struct SectionList *slist = stgMallocBytes(sizeof(struct SectionList), "ocGetNames_PEi386");
-          slist->section = &oc->sections[i];
-          slist->next = oc->info->init;
-          if (sscanf(section->info->name, ".ctors.%d", &slist->priority) != 1) {
-              // Sections without an explicit priority must be run last
-              slist->priority = 0;
+          uint32_t prio;
+          if (sscanf(section->info->name, ".ctors.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
           }
-          oc->info->init = slist;
+          // .ctors/.dtors are executed in reverse order: higher numbers are
+          // executed first
+          prio = 0xffff - prio;
+          addInitFini(&oc->info->init, &oc->sections[i], INITFINI_CTORS, prio);
           kind = SECTIONKIND_INIT_ARRAY;
       }
 
       if (0==strncmp(".dtors", section->info->name, 6)) {
-          struct SectionList *slist = stgMallocBytes(sizeof(struct SectionList), "ocGetNames_PEi386");
-          slist->section = &oc->sections[i];
-          slist->next = oc->info->fini;
-          if (sscanf(section->info->name, ".dtors.%d", &slist->priority) != 1) {
-              // Sections without an explicit priority must be run last
-              slist->priority = INT_MAX;
+          uint32_t prio;
+          if (sscanf(section->info->name, ".dtors.%d", &prio) != 1) {
+              // Sections without an explicit priority are run last
+              prio = 0;
           }
-          oc->info->fini = slist;
+          // .ctors/.dtors are executed in reverse order: higher numbers are
+          // executed first
+          prio = 0xffff - prio;
+          addInitFini(&oc->info->fini, &oc->sections[i], INITFINI_DTORS, prio);
           kind = SECTIONKIND_FINI_ARRAY;
       }
 
@@ -1632,10 +1594,6 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       addProddableBlock(oc, oc->sections[i].start, sz);
    }
 
-   /* Sort the constructors and finalizers by priority */
-   sortSectionList(&oc->info->init, DECREASING);
-   sortSectionList(&oc->info->fini, INCREASING);
-
    /* Copy exported symbols into the ObjectCode. */
 
    oc->n_symbols = info->numberOfSymbols;
@@ -2170,95 +2128,23 @@ ocResolve_PEi386 ( ObjectCode* oc )
   content of .pdata on to RtlAddFunctionTable and the OS will do
   the rest.  When we're unloading the object we have to unregister
   them using RtlDeleteFunctionTable.
-
 */
 
-/*
- * Note [Initializers and finalizers (PEi386)]
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * COFF/PE allows an object to define initializers and finalizers to be run
- * at load/unload time, respectively. These are listed in the `.ctors` and
- * `.dtors` sections. Moreover, these section names may be suffixed with an
- * integer priority (e.g. `.ctors.1234`). Sections are run in order of
- * high-to-low priority. Sections without a priority (e.g.  `.ctors`) are run
- * last.
- *
- * A `.ctors`/`.dtors` section contains an array of pointers to
- * `init_t`/`fini_t` functions, respectively. Note that `.ctors` must be run in
- * reverse order.
- *
- * For more about how the code generator emits initializers and finalizers see
- * Note [Initializers and finalizers in Cmm] in GHC.Cmm.InitFini.
- */
-
-
-// Run the constructors/initializers of an ObjectCode.
-// Returns 1 on success.
-// See Note [Initializers and finalizers (PEi386)].
 bool
 ocRunInit_PEi386 ( ObjectCode *oc )
 {
-  if (!oc || !oc->info || !oc->info->init) {
-    return true;
-  }
-
-  int argc, envc;
-  char **argv, **envv;
-
-  getProgArgv(&argc, &argv);
-  getProgEnvv(&envc, &envv);
-
-  for (struct SectionList *slist = oc->info->init;
-       slist != NULL;
-       slist = slist->next) {
-    Section *section = slist->section;
-    CHECK(SECTIONKIND_INIT_ARRAY == section->kind);
-    uint8_t *init_startC = section->start;
-    init_t *init_start   = (init_t*)init_startC;
-    init_t *init_end     = (init_t*)(init_startC + section->size);
-
-    // ctors are run *backwards*!
-    for (init_t *init = init_end - 1; init >= init_start; init--) {
-        (*init)(argc, argv, envv);
+    if (oc && oc->info && oc->info->init) {
+        return runInit(&oc->info->init);
     }
-  }
-
-  freeSectionList(oc->info->init);
-  oc->info->init = NULL;
-
-  freeProgEnvv(envc, envv);
-  return true;
+    return true;
 }
 
-// Run the finalizers of an ObjectCode.
-// Returns 1 on success.
-// See Note [Initializers and finalizers (PEi386)].
 bool ocRunFini_PEi386( ObjectCode *oc )
 {
-  if (!oc || !oc->info || !oc->info->fini) {
-    return true;
-  }
-
-  for (struct SectionList *slist = oc->info->fini;
-       slist != NULL;
-       slist = slist->next) {
-    Section section = *slist->section;
-    CHECK(SECTIONKIND_FINI_ARRAY == section.kind);
-
-    uint8_t *fini_startC = section.start;
-    fini_t *fini_start   = (fini_t*)fini_startC;
-    fini_t *fini_end     = (fini_t*)(fini_startC + section.size);
-
-    // dtors are run in forward order.
-    for (fini_t *fini = fini_end - 1; fini >= fini_start; fini--) {
-      (*fini)();
+    if (oc && oc->info && oc->info->fini) {
+        return runFini(&oc->info->fini);
     }
-  }
-
-  freeSectionList(oc->info->fini);
-  oc->info->fini = NULL;
-
-  return true;
+    return true;
 }
 
 SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl, ObjectCode *dependent, SymType *type)


=====================================
rts/linker/PEi386Types.h
=====================================
@@ -4,6 +4,7 @@
 
 #include "ghcplatform.h"
 #include "PEi386.h"
+#include "linker/InitFini.h"
 #include <stdint.h>
 #include <stdio.h>
 
@@ -17,17 +18,9 @@ struct SectionFormatInfo {
     uint64_t virtualAddr;
  };
 
-// A linked-list of Sections; used to represent the set of initializer/finalizer
-// list sections.
-struct SectionList {
-    Section *section;
-    int priority;
-    struct SectionList *next;
-};
-
 struct ObjectCodeFormatInfo {
-    struct SectionList* init;  // Freed by ocRunInit_PEi386
-    struct SectionList* fini;  // Freed by ocRunFini_PEi386
+    struct InitFiniList* init; // Freed by ocRunInit_PEi386
+    struct InitFiniList* fini; // Freed by ocRunFini_PEi386
     Section* pdata;
     Section* xdata;
     COFF_HEADER_INFO* ch_info; // Freed by ocResolve_PEi386


=====================================
rts/rts.cabal.in
=====================================
@@ -550,6 +550,7 @@ library
                hooks/StackOverflow.c
                linker/CacheFlush.c
                linker/Elf.c
+               linker/InitFini.c
                linker/LoadArchive.c
                linker/M32Alloc.c
                linker/MMap.c



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9ae873075c31d4ccd841f2e253ed6ee3d730164b

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9ae873075c31d4ccd841f2e253ed6ee3d730164b
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20220812/4d7e2473/attachment-0001.html>


More information about the ghc-commits mailing list