diff options
author | Edward Z. Yang <ezyang@mit.edu> | 2013-09-16 17:17:35 -0700 |
---|---|---|
committer | Edward Z. Yang <ezyang@mit.edu> | 2013-09-16 17:17:42 -0700 |
commit | bfe3c4c69a36ac5e56a680bdd83e8d9ccba1d1e1 (patch) | |
tree | 4b69ec62e900a309db256303eecfa1eb6898ef44 /rts | |
parent | 9672b08272ce6ed0e6540b0cfc99c2754d6100c8 (diff) | |
download | haskell-bfe3c4c69a36ac5e56a680bdd83e8d9ccba1d1e1.tar.gz |
Implement ctors support for Linux.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
Diffstat (limited to 'rts')
-rw-r--r-- | rts/Linker.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index e2c408157c..4f85498f0c 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -5543,21 +5543,36 @@ static int ocRunInit_ELF( ObjectCode *oc ) // 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 + // 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 < ehdr->e_shnum; i++) { + init_t *init_start, *init_end, *init; int is_bss = FALSE; SectionKind kind = getSectionKind_ELF(&shdr[i], &is_bss); if (kind == SECTIONKIND_CODE_OR_RODATA && 0 == memcmp(".init", sh_strtab + shdr[i].sh_name, 5)) { - init_t init = (init_t)(ehdrC + shdr[i].sh_offset); - init(argc, argv, envv); + init_t init_f = (init_t)(ehdrC + shdr[i].sh_offset); + init_f(argc, argv, envv); } if (kind == SECTIONKIND_INIT_ARRAY) { char *init_startC = ehdrC + shdr[i].sh_offset; - init_t *init = (init_t*)init_startC; - init_t *init_end = (init_t*)(init_startC + shdr[i].sh_size); - for (; init < init_end; init++) { + init_start = (init_t*)init_startC; + init_end = (init_t*)(init_startC + shdr[i].sh_size); + for (init = init_start; init < init_end; 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 = ehdrC + shdr[i].sh_offset; + 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--) { (*init)(argc, argv, envv); } } |