summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-08-10 14:49:59 -0400
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-10-13 05:58:56 -0400
commit78ab7afe244a7617d600a6180d81d9dec657114d (patch)
tree6254371d34249440dfa690265e8467ff0de4f123
parentce2939085e5b59513748ff73bc66161c09d69468 (diff)
downloadhaskell-78ab7afe244a7617d600a6180d81d9dec657114d.tar.gz
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.
-rw-r--r--rts/linker/Elf.c168
-rw-r--r--rts/linker/ElfTypes.h5
-rw-r--r--rts/linker/InitFini.c196
-rw-r--r--rts/linker/InitFini.h22
-rw-r--r--rts/linker/PEi386.c162
-rw-r--r--rts/linker/PEi386Types.h13
-rw-r--r--rts/rts.cabal.in1
7 files changed, 316 insertions, 251 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index fb9efae369..197edc95e3 100644
--- a/rts/linker/Elf.c
+++ b/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;
}
/*
diff --git a/rts/linker/ElfTypes.h b/rts/linker/ElfTypes.h
index e5333d71a7..24e29a1d8d 100644
--- a/rts/linker/ElfTypes.h
+++ b/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;
};
diff --git a/rts/linker/InitFini.c b/rts/linker/InitFini.c
new file mode 100644
index 0000000000..48a548e3cf
--- /dev/null
+++ b/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);
+}
diff --git a/rts/linker/InitFini.h b/rts/linker/InitFini.h
new file mode 100644
index 0000000000..f00233d88d
--- /dev/null
+++ b/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);
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
index 86c8cfdb03..8e2ce984ca 100644
--- a/rts/linker/PEi386.c
+++ b/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)
diff --git a/rts/linker/PEi386Types.h b/rts/linker/PEi386Types.h
index edf3d419a6..573467b7cf 100644
--- a/rts/linker/PEi386Types.h
+++ b/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
diff --git a/rts/rts.cabal.in b/rts/rts.cabal.in
index 68648f0ba6..2a113e8867 100644
--- a/rts/rts.cabal.in
+++ b/rts/rts.cabal.in
@@ -554,6 +554,7 @@ library
hooks/StackOverflow.c
linker/CacheFlush.c
linker/Elf.c
+ linker/InitFini.c
linker/LoadArchive.c
linker/M32Alloc.c
linker/MMap.c