summaryrefslogtreecommitdiff
path: root/rts/linker/Elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/linker/Elf.c')
-rw-r--r--rts/linker/Elf.c168
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;
}
/*