summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@well-typed.com>2022-07-13 18:15:44 +0000
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-07-16 23:50:37 -0400
commit6c476e1a804d4fbfacff0fc69cdb7c4700fd0eaa (patch)
tree3a695604079c6295601691576494e921cab096db
parent5b0ed8a8baaa32e03fee7af2c08656b462b62770 (diff)
downloadhaskell-6c476e1a804d4fbfacff0fc69cdb7c4700fd0eaa.tar.gz
rts/linker/Elf: Work around GCC 6 init/fini behavior
It appears that GCC 6t (at least on i386) fails to give init_array/fini_array sections the correct SHT_INIT_ARRAY/SHT_FINI_ARRAY section types, instead marking them as SHT_PROGBITS. This caused T20494 to fail on Debian.
-rw-r--r--rts/linker/Elf.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index dd4b8fcd0d..fb9efae369 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -1955,6 +1955,15 @@ ocResolve_ELF ( ObjectCode* oc )
*
* See also: the "Initialization and Termination Functions" section of the
* System V ABI.
+ *
+ * Note [GCC 6 init/fini section workaround]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * The System V ABI specifies that .init_array and .fini_array sections should
+ * be marked with the SHT_INIT_ARRAY/SHT_FINI_ARRAY section types. However, it
+ * seems that GCC 6 (at least on i386) produces sections *named*
+ * .init_array/.fini_array but marks them as SHT_PROGBITS. Consequently we need
+ * to augment the usual section type check (which in an ideal world would be
+ * sufficient) with a check looking at the section name to catch this case.
*/
// Run the constructors/initializers of an ObjectCode.
@@ -1979,15 +1988,19 @@ int ocRunInit_ELF( ObjectCode *oc )
// 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_strtab + shdr[i].sh_name, 5)) {
+ && 0 == memcmp(".init", sh_name, 5)) {
init_t init_f = (init_t)(oc->sections[i].start);
init_f(argc, argv, envv);
}
- if (kind == SECTIONKIND_INIT_ARRAY) {
+ // 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);
@@ -2027,6 +2040,7 @@ int ocRunFini_ELF( ObjectCode *oc )
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);
@@ -2035,7 +2049,9 @@ int ocRunFini_ELF( ObjectCode *oc )
fini_f();
}
- if (kind == SECTIONKIND_FINI_ARRAY) {
+ // 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;