diff options
Diffstat (limited to 'rts/linker/Elf.c')
-rw-r--r-- | rts/linker/Elf.c | 168 |
1 files changed, 66 insertions, 102 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; } /* |