Fix #8698 by properly handling long section names and reenabling .ctors handling
authorEdward Z. Yang <ezyang@cs.stanford.edu>
Tue, 4 Feb 2014 23:59:55 +0000 (15:59 -0800)
committerEdward Z. Yang <ezyang@cs.stanford.edu>
Wed, 5 Feb 2014 00:12:03 +0000 (16:12 -0800)
Our old function for searching for sections could only deal
with section names that were eight bytes or shorter; this
patch adds support for long section names.

Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
rts/Linker.c

index b9c8fd0..8f57873 100644 (file)
@@ -211,9 +211,7 @@ static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
 static int ocVerifyImage_PEi386 ( ObjectCode* oc );
 static int ocGetNames_PEi386    ( ObjectCode* oc );
 static int ocResolve_PEi386     ( ObjectCode* oc );
-#if !defined(x86_64_HOST_ARCH)
 static int ocRunInit_PEi386     ( ObjectCode* oc );
-#endif
 static void *lookupSymbolInDLLs ( unsigned char *lbl );
 static void zapTrailingAtSign   ( unsigned char *sym );
 static char *allocateImageAndTrampolines (
@@ -2875,10 +2873,7 @@ resolveObjs( void )
 #if defined(OBJFORMAT_ELF)
             r = ocRunInit_ELF ( oc );
 #elif defined(OBJFORMAT_PEi386)
-#if !defined(x86_64_HOST_ARCH)
-            /* It does not work on x86_64 yet. #8698. */
             r = ocRunInit_PEi386 ( oc );
-#endif
 #elif defined(OBJFORMAT_MACHO)
             r = ocRunInit_MachO ( oc );
 #else
@@ -3608,9 +3603,10 @@ cstring_from_section_name (UChar* name, UChar* strtab)
 
 /* Just compares the short names (first 8 chars) */
 static COFF_section *
-findPEi386SectionCalled ( ObjectCode* oc,  UChar* name )
+findPEi386SectionCalled ( ObjectCode* oc,  UChar* name, UChar* strtab )
 {
    int i;
+   rtsBool long_name = rtsFalse;
    COFF_header* hdr
       = (COFF_header*)(oc->image);
    COFF_section* sectab
@@ -3618,6 +3614,14 @@ findPEi386SectionCalled ( ObjectCode* oc,  UChar* name )
            ((UChar*)(oc->image))
            + sizeof_COFF_header + hdr->SizeOfOptionalHeader
         );
+   // String is longer than 8 bytes, swap in the proper
+   // (NULL-terminated) version, and make a note that this
+   // is a long name.
+   if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
+      UInt32 strtab_offset = * (UInt32*)(name+4);
+      name = ((UChar*)strtab) + strtab_offset;
+      long_name = rtsTrue;
+   }
    for (i = 0; i < hdr->NumberOfSections; i++) {
       UChar* n1;
       UChar* n2;
@@ -3626,10 +3630,28 @@ findPEi386SectionCalled ( ObjectCode* oc,  UChar* name )
            myindex ( sizeof_COFF_section, sectab, i );
       n1 = (UChar*) &(section_i->Name);
       n2 = name;
-      if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] &&
-          n1[3]==n2[3] && n1[4]==n2[4] && n1[5]==n2[5] &&
-          n1[6]==n2[6] && n1[7]==n2[7])
-         return section_i;
+      // Long section names are prefixed with a slash, see
+      // also cstring_from_section_name
+      if (n1[0] == '/' && long_name) {
+         // Long name check
+         // We don't really want to make an assumption that the string
+         // table indexes are the same, so we'll do a proper check.
+         int n1_strtab_offset = strtol((char*)n1+1,NULL,10);
+         n1 = (UChar*) (((char*)strtab) + n1_strtab_offset);
+         if (0==strcmp((const char*)n1, (const char*)n2)) {
+            return section_i;
+         }
+      } else if (n1[0] != '/' && !long_name) {
+         // Short name check
+         if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] &&
+             n1[3]==n2[3] && n1[4]==n2[4] && n1[5]==n2[5] &&
+             n1[6]==n2[6] && n1[7]==n2[7]) {
+            return section_i;
+         }
+      } else {
+         // guaranteed to mismatch, because we never attempt to link
+         // in an executable where the section name may be truncated
+      }
    }
 
    return NULL;
@@ -4235,14 +4257,6 @@ ocResolve_PEi386 ( ObjectCode* oc )
           continue;
       }
 
-#if defined(x86_64_HOST_ARCH)
-      /* It does not work on x86_64 yet. #8698. */
-      if (0 == strcmp(".ctors", (char*)secname)) {
-          stgFree(secname);
-          continue;
-      }
-#endif
-
       stgFree(secname);
 
       if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) {
@@ -4304,9 +4318,11 @@ ocResolve_PEi386 ( ObjectCode* oc )
 
          if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) {
             COFF_section* section_sym
-               = findPEi386SectionCalled ( oc, sym->Name );
+               = findPEi386SectionCalled ( oc, sym->Name, strtab );
             if (!section_sym) {
-               errorBelch("%" PATH_FMT ": can't find section `%s' in %s", oc->fileName, sym->Name, secname);
+               errorBelch("%" PATH_FMT ": can't find section named: ", oc->fileName);
+               printName(sym->Name, strtab);
+               errorBelch(" in %s", secname);
                return 0;
             }
             S = ((size_t)(oc->image))
@@ -4414,8 +4430,6 @@ ocResolve_PEi386 ( ObjectCode* oc )
    return 1;
 }
 
-/* It does not work on x86_64 yet. #8698. */
-#if !defined(x86_64_HOST_ARCH)
 static int
 ocRunInit_PEi386 ( ObjectCode *oc )
 {
@@ -4458,7 +4472,6 @@ ocRunInit_PEi386 ( ObjectCode *oc )
     freeProgEnvv(envc, envv);
     return 1;
 }
-#endif
 
 #endif /* defined(OBJFORMAT_PEi386) */