diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-08-10 14:49:59 -0400 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-10-13 05:58:56 -0400 |
commit | 78ab7afe244a7617d600a6180d81d9dec657114d (patch) | |
tree | 6254371d34249440dfa690265e8467ff0de4f123 | |
parent | ce2939085e5b59513748ff73bc66161c09d69468 (diff) | |
download | haskell-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.c | 168 | ||||
-rw-r--r-- | rts/linker/ElfTypes.h | 5 | ||||
-rw-r--r-- | rts/linker/InitFini.c | 196 | ||||
-rw-r--r-- | rts/linker/InitFini.h | 22 | ||||
-rw-r--r-- | rts/linker/PEi386.c | 162 | ||||
-rw-r--r-- | rts/linker/PEi386Types.h | 13 | ||||
-rw-r--r-- | rts/rts.cabal.in | 1 |
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 |