[project @ 2001-09-04 18:29:20 by ken]
[ghc-hetmet.git] / ghc / rts / Linker.c
index d9e2b91..9160aea 100644 (file)
@@ -1,12 +1,13 @@
 /* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.47 2001/06/28 14:26:58 sewardj Exp $
+ * $Id: Linker.c,v 1.65 2001/09/04 18:29:21 ken Exp $
  *
- * (c) The GHC Team, 2000
+ * (c) The GHC Team, 2000, 2001
  *
  * RTS Object Linker
  *
  * ---------------------------------------------------------------------------*/
 
+#include "PosixSource.h"
 #include "Rts.h"
 #include "RtsFlags.h"
 #include "HsFFI.h"
@@ -84,6 +85,7 @@ typedef struct _RtsSymbolVal {
 /* These are statically linked from the mingw libraries into the ghc
    executable, so we have to employ this hack. */
 #define RTS_MINGW_ONLY_SYMBOLS                  \
+      SymX(memset)                              \
       SymX(inet_ntoa)                           \
       SymX(inet_addr)                           \
       SymX(htonl)                               \
@@ -136,6 +138,7 @@ typedef struct _RtsSymbolVal {
       Sym(mktime)                               \
       Sym(_imp___timezone)                      \
       Sym(_imp___tzname)                        \
+      Sym(_imp___iob)                           \
       Sym(localtime)                            \
       Sym(gmtime)                               \
       SymX(getenv)                              \
@@ -150,6 +153,10 @@ typedef struct _RtsSymbolVal {
       SymX(GetExitCodeProcess)                  \
       SymX(WaitForSingleObject)                 \
       SymX(CreateProcessA)                      \
+      Sym(__divdi3)                             \
+      Sym(__udivdi3)                            \
+      Sym(__moddi3)                             \
+      Sym(__umoddi3)                            \
       SymX(_errno)
 #endif
 
@@ -232,6 +239,7 @@ typedef struct _RtsSymbolVal {
       SymX(newArrayzh_fast)                    \
       SymX(unsafeThawArrayzh_fast)             \
       SymX(newByteArrayzh_fast)                        \
+      SymX(newPinnedByteArrayzh_fast)          \
       SymX(newMutVarzh_fast)                   \
       SymX(quotRemIntegerzh_fast)              \
       SymX(quotIntegerzh_fast)                 \
@@ -267,6 +275,8 @@ typedef struct _RtsSymbolVal {
       SymX(__gmpz_get_ui)                      \
       SymX(prog_argv)                          \
       SymX(prog_argc)                          \
+      SymX(getProgArgv)                                \
+      SymX(setProgArgv)                                \
       SymX(resetNonBlockingFd)                 \
       SymX(performGC)                          \
       SymX(getStablePtr)                       \
@@ -277,7 +287,7 @@ typedef struct _RtsSymbolVal {
       Sym(StgReturn)                           \
       Sym(init_stack)                          \
       SymX(cmp_thread)                         \
-      Sym(__init_PrelGHC)                      \
+      Sym(__stginit_PrelGHC)                   \
       SymX(freeHaskellFunctionPtr)             \
       SymX(OnExitHook)                         \
       SymX(ErrorHdrHook)                       \
@@ -330,41 +340,6 @@ typedef struct _RtsSymbolVal {
 #define RTS_LONG_LONG_SYMS /* nothing */
 #else
 #define RTS_LONG_LONG_SYMS                     \
-      SymX(stg_gtWord64)                       \
-      SymX(stg_geWord64)                       \
-      SymX(stg_eqWord64)                       \
-      SymX(stg_neWord64)                       \
-      SymX(stg_ltWord64)                       \
-      SymX(stg_leWord64)                       \
-      SymX(stg_gtInt64)                                \
-      SymX(stg_geInt64)                                \
-      SymX(stg_eqInt64)                                \
-      SymX(stg_neInt64)                                \
-      SymX(stg_ltInt64)                                \
-      SymX(stg_leInt64)                                \
-      SymX(stg_remWord64)                      \
-      SymX(stg_quotWord64)                     \
-      SymX(stg_remInt64)                       \
-      SymX(stg_quotInt64)                      \
-      SymX(stg_negateInt64)                    \
-      SymX(stg_plusInt64)                      \
-      SymX(stg_minusInt64)                     \
-      SymX(stg_timesInt64)                     \
-      SymX(stg_and64)                          \
-      SymX(stg_or64)                           \
-      SymX(stg_xor64)                          \
-      SymX(stg_not64)                          \
-      SymX(stg_shiftL64)                       \
-      SymX(stg_shiftRL64)                      \
-      SymX(stg_iShiftL64)                      \
-      SymX(stg_iShiftRL64)                     \
-      SymX(stg_iShiftRA64)                     \
-      SymX(stg_intToInt64)                     \
-      SymX(stg_int64ToInt)                     \
-      SymX(stg_int64ToWord64)                  \
-      SymX(stg_wordToWord64)                   \
-      SymX(stg_word64ToWord)                   \
-      SymX(stg_word64ToInt64)                  \
       SymX(int64ToIntegerzh_fast)              \
       SymX(word64ToIntegerzh_fast)
 #endif /* SUPPORT_LONG_LONGS */
@@ -450,7 +425,7 @@ static OpenedDLL* opened_dlls = NULL;
 
 
 char*
-addDLL ( char* path, char* dll_name )
+addDLL ( __attribute((unused)) char* path, char* dll_name )
 {
 #  if defined(OBJFORMAT_ELF)
    void *hdl;
@@ -532,10 +507,22 @@ lookupSymbol( char *lbl )
         void* sym;
         for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
            /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */
+           if (lbl[0] == '_') {
+              /* HACK: if the name has an initial underscore, try stripping
+                 it off & look that up first. I've yet to verify whether there's
+                 a Rule that governs whether an initial '_' *should always* be
+                 stripped off when mapping from import lib name to the DLL name.
+              */
+              sym = GetProcAddress(o_dll->instance, (lbl+1));
+              if (sym != NULL) return sym;
+           }
            sym = GetProcAddress(o_dll->instance, lbl);
            if (sym != NULL) return sym;
         }
         return NULL;
+#       else
+        ASSERT(2+2 == 5);
+        return NULL;
 #       endif
     } else {
        return val;
@@ -603,6 +590,7 @@ loadObj( char *path )
    oc->symbols           = NULL;
    oc->sections          = NULL;
    oc->lochash           = allocStrHashTable();
+   oc->proddables        = NULL;
 
    /* chain it onto the list of objects */
    oc->next              = objects;
@@ -723,6 +711,54 @@ unloadObj( char *path )
     return 0;
 }
 
+/* -----------------------------------------------------------------------------
+ * Sanity checking.  For each ObjectCode, maintain a list of address ranges
+ * which may be prodded during relocation, and abort if we try and write
+ * outside any of these.
+ */
+static void addProddableBlock ( ObjectCode* oc, void* start, int size )
+{
+   ProddableBlock* pb 
+      = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock");
+   /* fprintf(stderr, "aPB %p %p %d\n", oc, start, size); */
+   ASSERT(size > 0);
+   pb->start      = start;
+   pb->size       = size;
+   pb->next       = oc->proddables;
+   oc->proddables = pb;
+}
+
+static void checkProddableBlock ( ObjectCode* oc, void* addr )
+{
+   ProddableBlock* pb;
+   for (pb = oc->proddables; pb != NULL; pb = pb->next) {
+      char* s = (char*)(pb->start);
+      char* e = s + pb->size - 1;
+      char* a = (char*)addr;
+      /* Assumes that the biggest fixup involves a 4-byte write.  This
+         probably needs to be changed to 8 (ie, +7) on 64-bit
+         plats. */
+      if (a >= s && (a+3) <= e) return;
+   }
+   barf("checkProddableBlock: invalid fixup in runtime linker");
+}
+
+/* -----------------------------------------------------------------------------
+ * Section management.
+ */
+static void addSection ( ObjectCode* oc, SectionKind kind,
+                         void* start, void* end )
+{
+   Section* s   = stgMallocBytes(sizeof(Section), "addSection");
+   s->start     = start;
+   s->end       = end;
+   s->kind      = kind;
+   s->next      = oc->sections;
+   oc->sections = s;
+}
+
+
+
 /* --------------------------------------------------------------------------
  * PEi386 specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
@@ -995,8 +1031,14 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
             (int)(hdr->Characteristics));
       return 0;
    }
+   /* If the string table size is way crazy, this might indicate that
+      there are more than 64k relocations, despite claims to the
+      contrary.  Hence this test. */
    /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */
-   if (* (UInt32*)strtab > 510000) {
+   if (* (UInt32*)strtab > 600000) {
+      /* Note that 600k has no special significance other than being
+         big enough to handle the almost-2MB-sized lumps that
+         constitute HSwin32*.o. */
       belch("PEi386 object has suspiciously large string table; > 64k relocs?");
       return 0;
    }
@@ -1050,13 +1092,15 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
                 "  data sz %d\n"
                 " data off %d\n"
                 "  num rel %d\n"
-                "  off rel %d\n",
+                "  off rel %d\n"
+                "  ptr raw 0x%x\n",
                 sectab_i->VirtualSize,
                 sectab_i->VirtualAddress,
                 sectab_i->SizeOfRawData,
                 sectab_i->PointerToRawData,
                 sectab_i->NumberOfRelocations,
-                sectab_i->PointerToRelocations
+                sectab_i->PointerToRelocations,
+                sectab_i->PointerToRawData
               );
       reltab = (COFF_reloc*) (
                   ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
@@ -1075,9 +1119,9 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
          printName ( sym->Name, strtab -10 );
          fprintf ( stderr, "'\n" );
       }
+
       fprintf ( stderr, "\n" );
    }
-
    fprintf ( stderr, "\n" );
    fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab );
    fprintf ( stderr, "---START of string table---\n");
@@ -1104,12 +1148,12 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
       fprintf ( stderr, 
                 "'\n"
                 "    value 0x%x\n"
-                "     sec# %d\n"
+                "   1+sec# %d\n"
                 "     type 0x%x\n"
                 "   sclass 0x%x\n"
                 "     nAux %d\n",
                 symtab_i->Value,
-                (Int32)(symtab_i->SectionNumber) - 1,
+                (Int32)(symtab_i->SectionNumber),
                 (UInt32)symtab_i->Type,
                 (UInt32)symtab_i->StorageClass,
                 (UInt32)symtab_i->NumberOfAuxSymbols 
@@ -1148,62 +1192,31 @@ ocGetNames_PEi386 ( ObjectCode* oc )
             + hdr->PointerToSymbolTable
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
-   /* Copy exported symbols into the ObjectCode. */
-
-   oc->n_symbols = hdr->NumberOfSymbols;
-   oc->symbols   = stgMallocBytes(oc->n_symbols * sizeof(char*),
-                                  "ocGetNames_PEi386(oc->symbols)");
-   /* Call me paranoid; I don't care. */
-   for (i = 0; i < oc->n_symbols; i++) 
-      oc->symbols[i] = NULL;
-
-   i = 0;
-   while (1) {
-      COFF_symbol* symtab_i;
-      if (i >= (Int32)(hdr->NumberOfSymbols)) break;
-      symtab_i = (COFF_symbol*)
-                 myindex ( sizeof_COFF_symbol, symtab, i );
-
-      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL &&
-          symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
+   /* Allocate space for any (local, anonymous) .bss sections. */
 
-         /* This symbol is global and defined, viz, exported */
-         COFF_section* sectabent;
-
-         /* cstring_from_COFF_symbol_name always succeeds. */
-         sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab );
-
-         /* for MYIMAGE_SYMCLASS_EXTERNAL 
-                && !MYIMAGE_SYM_UNDEFINED,
-            the address of the symbol is: 
-                address of relevant section + offset in section
-         */
-         sectabent = (COFF_section*)
-                     myindex ( sizeof_COFF_section, 
-                               sectab,
-                               symtab_i->SectionNumber-1 );
-         addr = ((UChar*)(oc->image))
-                + (sectabent->PointerToRawData
-                   + symtab_i->Value);
-         /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */
-         IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);)
-         ASSERT(i >= 0 && i < oc->n_symbols);
-         oc->symbols[i] = sname;
-         insertStrHashTable(symhash, sname, addr);
-      }
-      i += symtab_i->NumberOfAuxSymbols;
-      i++;
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      UChar* zspace;
+      COFF_section* sectab_i
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, sectab, i );
+      if (0 != strcmp(sectab_i->Name, ".bss")) continue;
+      if (sectab_i->VirtualSize == 0) continue;
+      /* This is a non-empty .bss section.  Allocate zeroed space for
+         it, and set its PointerToRawData field such that oc->image +
+         PointerToRawData == addr_of_zeroed_space.  */
+      zspace = stgCallocBytes(1, sectab_i->VirtualSize, 
+                              "ocGetNames_PEi386(anonymous bss)");
+      sectab_i->PointerToRawData = ((UChar*)zspace) - ((UChar*)(oc->image));
+      addProddableBlock(oc, zspace, sectab_i->VirtualSize);
+      /* fprintf(stderr, "BSS anon section at 0x%x\n", zspace); */
    }
 
    /* Copy section information into the ObjectCode. */
 
-   oc->n_sections = hdr->NumberOfSections;
-   oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), 
-                                  "ocGetNamesPEi386" );
-
-   for (i = 0; i < oc->n_sections; i++) {
+   for (i = 0; i < hdr->NumberOfSections; i++) {
       UChar* start;
       UChar* end;
+      UInt32 sz;
 
       SectionKind kind 
          = SECTIONKIND_OTHER;
@@ -1212,7 +1225,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
            myindex ( sizeof_COFF_section, sectab, i );
       IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name ));
 
-#if 0
+#     if 0
       /* I'm sure this is the Right Way to do it.  However, the 
          alternative of testing the sectab_i->Name field seems to
          work ok with Cygwin.
@@ -1220,27 +1233,114 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE || 
           sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA)
          kind = SECTIONKIND_CODE_OR_RODATA;
-#endif
+#     endif
 
-      if (0==strcmp(".text",sectab_i->Name))
+      if (0==strcmp(".text",sectab_i->Name) ||
+          0==strcmp(".rodata",sectab_i->Name))
          kind = SECTIONKIND_CODE_OR_RODATA;
       if (0==strcmp(".data",sectab_i->Name) ||
           0==strcmp(".bss",sectab_i->Name))
          kind = SECTIONKIND_RWDATA;
 
-      start = ((UChar*)(oc->image)) 
-              + sectab_i->PointerToRawData;
-      end   = start 
-              + sectab_i->SizeOfRawData - 1;
+      ASSERT(sectab_i->SizeOfRawData == 0 || sectab_i->VirtualSize == 0);
+      sz = sectab_i->SizeOfRawData;
+      if (sz < sectab_i->VirtualSize) sz = sectab_i->VirtualSize;
+
+      start = ((UChar*)(oc->image)) + sectab_i->PointerToRawData;
+      end   = start + sz - 1;
 
       if (kind == SECTIONKIND_OTHER) {
          belch("Unknown PEi386 section name `%s'", sectab_i->Name);
          return 0;
       }
 
-      oc->sections[i].start = start;
-      oc->sections[i].end   = end;
-      oc->sections[i].kind  = kind;
+      if (end >= start) {
+         addSection(oc, kind, start, end);
+         addProddableBlock(oc, start, end - start + 1);
+      }
+   }
+
+   /* Copy exported symbols into the ObjectCode. */
+
+   oc->n_symbols = hdr->NumberOfSymbols;
+   oc->symbols   = stgMallocBytes(oc->n_symbols * sizeof(char*),
+                                  "ocGetNames_PEi386(oc->symbols)");
+   /* Call me paranoid; I don't care. */
+   for (i = 0; i < oc->n_symbols; i++) 
+      oc->symbols[i] = NULL;
+
+   i = 0;
+   while (1) {
+      COFF_symbol* symtab_i;
+      if (i >= (Int32)(hdr->NumberOfSymbols)) break;
+      symtab_i = (COFF_symbol*)
+                 myindex ( sizeof_COFF_symbol, symtab, i );
+
+      addr  = NULL;
+
+      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL
+          && symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
+         /* This symbol is global and defined, viz, exported */
+         /* for MYIMAGE_SYMCLASS_EXTERNAL 
+                && !MYIMAGE_SYM_UNDEFINED,
+            the address of the symbol is: 
+                address of relevant section + offset in section
+         */
+         COFF_section* sectabent 
+            = (COFF_section*) myindex ( sizeof_COFF_section, 
+                                        sectab,
+                                        symtab_i->SectionNumber-1 );
+         addr = ((UChar*)(oc->image))
+                + (sectabent->PointerToRawData
+                   + symtab_i->Value);
+      } 
+      else
+      if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED
+         && symtab_i->Value > 0) {
+         /* This symbol isn't in any section at all, ie, global bss.
+            Allocate zeroed space for it. */
+         addr = stgCallocBytes(1, symtab_i->Value, 
+                               "ocGetNames_PEi386(non-anonymous bss)");
+         addSection(oc, SECTIONKIND_RWDATA, addr, 
+                        ((UChar*)addr) + symtab_i->Value - 1);
+         addProddableBlock(oc, addr, symtab_i->Value);
+         /* fprintf(stderr, "BSS      section at 0x%x\n", addr); */
+      }
+
+      if (addr != NULL) {
+         sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab );
+         /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */
+         IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);)
+         ASSERT(i >= 0 && i < oc->n_symbols);
+         /* cstring_from_COFF_symbol_name always succeeds. */
+         oc->symbols[i] = sname;
+         insertStrHashTable(symhash, sname, addr);
+      } else {
+#        if 0
+         fprintf ( stderr, 
+                   "IGNORING symbol %d\n"
+                   "     name `",
+                   i 
+                 );
+         printName ( symtab_i->Name, strtab );
+         fprintf ( stderr, 
+                   "'\n"
+                   "    value 0x%x\n"
+                   "   1+sec# %d\n"
+                   "     type 0x%x\n"
+                   "   sclass 0x%x\n"
+                   "     nAux %d\n",
+                   symtab_i->Value,
+                   (Int32)(symtab_i->SectionNumber),
+                   (UInt32)symtab_i->Type,
+                   (UInt32)symtab_i->StorageClass,
+                   (UInt32)symtab_i->NumberOfAuxSymbols 
+                 );
+#        endif
+      }
+
+      i += symtab_i->NumberOfAuxSymbols;
+      i++;
    }
 
    return 1;   
@@ -1320,8 +1420,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
             COFF_section* section_sym 
                = findPEi386SectionCalled ( oc, sym->Name );
             if (!section_sym) {
-               fprintf ( stderr, "bad section = `%s'\n", sym->Name );
-               barf("Can't find abovementioned PEi386 section");
+               belch("%s: can't find section `%s'", oc->fileName, sym->Name);
                return 0;
             }
             S = ((UInt32)(oc->image))
@@ -1329,17 +1428,20 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    + sym->Value);
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
+            (void*)S = lookupLocalSymbol( oc, symbol );
+            if ((void*)S != NULL) goto foundit;
+            (void*)S = lookupSymbol( symbol );
+            if ((void*)S != NULL) goto foundit;
             zapTrailingAtSign ( symbol );
             (void*)S = lookupLocalSymbol( oc, symbol );
-            if ((void*)S == NULL)
-               (void*)S = lookupSymbol( symbol );
-            if (S == 0) {
-               belch("ocResolve_PEi386: %s: unknown symbol `%s'", 
-                      oc->fileName, symbol);
-               return 0;
-            }
+            if ((void*)S != NULL) goto foundit;
+            (void*)S = lookupSymbol( symbol );
+            if ((void*)S != NULL) goto foundit;
+            belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+            return 0;
+           foundit:
          }
-
+         checkProddableBlock(oc, pP);
          switch (reltab_j->Type) {
             case MYIMAGE_REL_I386_DIR32: 
                *pP = A + S; 
@@ -1360,17 +1462,15 @@ ocResolve_PEi386 ( ObjectCode* oc )
                *pP = S - ((UInt32)pP) - 4;
                break;
             default: 
-               fprintf(stderr, 
-                       "unhandled PEi386 relocation type %d\n",
-                       reltab_j->Type);
-               barf("unhandled PEi386 relocation type");
+               belch("%s: unhandled PEi386 relocation type %d", 
+                    oc->fileName, reltab_j->Type);
                return 0;
          }
 
       }
    }
    
-   /* fprintf(stderr, "completed     %s\n", oc->fileName); */
+   IF_DEBUG(linker, belch("completed %s", oc->fileName));
    return 1;
 }
 
@@ -1388,7 +1488,12 @@ ocResolve_PEi386 ( ObjectCode* oc )
 
 #if defined(sparc_TARGET_ARCH)
 #  define ELF_TARGET_SPARC  /* Used inside <elf.h> */
+#elif defined(i386_TARGET_ARCH)
+#  define ELF_TARGET_386    /* Used inside <elf.h> */
 #endif
+/* There is a similar case for IA64 in the Solaris2 headers if this
+ * ever becomes relevant.
+ */
 
 #include <elf.h>
 
@@ -1427,13 +1532,13 @@ ocVerifyImage_ELF ( ObjectCode* oc )
        ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
        ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
        ehdr->e_ident[EI_MAG3] != ELFMAG3) {
-      belch("ocVerifyImage_ELF: not an ELF header");
+      belch("%s: not an ELF header", oc->fileName);
       return 0;
    }
    IF_DEBUG(linker,belch( "Is an ELF header" ));
 
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
-      belch("ocVerifyImage_ELF: not 32 bit ELF" );
+      belch("%s: not 32 bit ELF", oc->fileName);
       return 0;
    }
 
@@ -1445,12 +1550,12 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
        IF_DEBUG(linker,belch( "Is big-endian" ));
    } else {
-       belch("ocVerifyImage_ELF: unknown endiannness");
+       belch("%s: unknown endiannness", oc->fileName);
        return 0;
    }
 
    if (ehdr->e_type != ET_REL) {
-      belch("ocVerifyImage_ELF: not a relocatable object (.o) file");
+      belch("%s: not a relocatable object (.o) file", oc->fileName);
       return 0;
    }
    IF_DEBUG(linker, belch( "Is a relocatable object (.o) file" ));
@@ -1460,7 +1565,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
       case EM_386:   IF_DEBUG(linker,belch( "x86" )); break;
       case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break;
       default:       IF_DEBUG(linker,belch( "unknown" )); 
-                     belch("ocVerifyImage_ELF: unknown architecture");
+                     belch("%s: unknown architecture", oc->fileName);
                      return 0;
    }
 
@@ -1473,7 +1578,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
 
    if (ehdr->e_shstrndx == SHN_UNDEF) {
-      belch("ocVerifyImage_ELF: no section header string table");
+      belch("%s: no section header string table", oc->fileName);
       return 0;
    } else {
       IF_DEBUG(linker,belch( "Section header string table is section %d", 
@@ -1514,7 +1619,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
       }
    }  
    if (nstrtab != 1) {
-      belch("ocVerifyImage_ELF: no string tables, or too many");
+      belch("%s: no string tables, or too many", oc->fileName);
       return 0;
    }
 
@@ -1531,7 +1636,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
                shdr[i].sh_size % sizeof(Elf32_Sym)
              ));
       if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
-         belch("ocVerifyImage_ELF: non-integral number of symbol table entries");
+         belch("%s: non-integral number of symbol table entries", oc->fileName);
          return 0;
       }
       for (j = 0; j < nent; j++) {
@@ -1566,7 +1671,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    }
 
    if (nsymtabs == 0) {
-      belch("ocVerifyImage_ELF: didn't find any symbol tables");
+      belch("%s: didn't find any symbol tables", oc->fileName);
       return 0;
    }
 
@@ -1589,32 +1694,43 @@ ocGetNames_ELF ( ObjectCode* oc )
    ASSERT(symhash != NULL);
 
    if (!strtab) {
-      belch("ocGetNames_ELF: no strtab");
+      belch("%s: no strtab", oc->fileName);
       return 0;
    }
 
    k = 0;
-   oc->n_sections = ehdr->e_shnum;
-   oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), 
-                                  "ocGetNames_ELF(oc->sections)" );
-
-   for (i = 0; i < oc->n_sections; i++) {
+   for (i = 0; i < ehdr->e_shnum; i++) {
 
       /* make a section entry for relevant sections */
       SectionKind kind = SECTIONKIND_OTHER;
       if (!strcmp(".data",sh_strtab+shdr[i].sh_name) ||
-          !strcmp(".data1",sh_strtab+shdr[i].sh_name))
+          !strcmp(".data1",sh_strtab+shdr[i].sh_name) ||
+          !strcmp(".bss",sh_strtab+shdr[i].sh_name))
          kind = SECTIONKIND_RWDATA;
       if (!strcmp(".text",sh_strtab+shdr[i].sh_name) ||
           !strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
           !strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
          kind = SECTIONKIND_CODE_OR_RODATA;
 
+      if (!strcmp(".bss",sh_strtab+shdr[i].sh_name) && shdr[i].sh_size > 0) {
+         /* This is a non-empty .bss section.  Allocate zeroed space for
+            it, and set its .sh_offset field such that 
+            ehdrC + .sh_offset == addr_of_zeroed_space.  */
+         char* zspace = stgCallocBytes(1, shdr[i].sh_size, 
+                                       "ocGetNames_ELF(anonymous bss)");
+         shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC);
+         /*
+         fprintf(stderr, "BSS section at 0x%x, size %d\n", 
+                         zspace, shdr[i].sh_size);
+         */
+      }
+
       /* fill in the section info */
-      oc->sections[i].start = ehdrC + shdr[i].sh_offset;
-      oc->sections[i].end   = ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1;
-      oc->sections[i].kind  = kind;
-      
+      addSection(oc, kind, ehdrC + shdr[i].sh_offset, 
+                     ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
+      if (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0)
+         addProddableBlock(oc, ehdrC + shdr[i].sh_offset, shdr[i].sh_size);
+
       if (shdr[i].sh_type != SHT_SYMTAB) continue;
 
       /* copy stuff into this module's object symbol table */
@@ -1639,11 +1755,20 @@ ocGetNames_ELF ( ObjectCode* oc )
                 ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT ||
                 ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE 
               )
-            ) { 
-            char* nm = strtab + stab[j].st_name;
-            char* ad = ehdrC 
-                       + shdr[ stab[j].st_shndx ].sh_offset
-                       + stab[j].st_value;
+            ) {
+            char* nm;
+            char* ad; 
+           int secno = stab[j].st_shndx;
+           /* Section 0 is the undefined section, hence > and not >=. */
+            ASSERT(secno > 0 && secno < ehdr->e_shnum);
+            nm = strtab + stab[j].st_name;
+            /*
+            if (shdr[secno].sh_type == SHT_NOBITS) {
+               fprintf(stderr, "bss symbol, size %d off %d name %s\n", 
+               stab[j].st_size, stab[j].st_value, nm);
+            }
+            */
+            ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value;
             ASSERT(nm != NULL);
             ASSERT(ad != NULL);
            oc->symbols[j] = nm;
@@ -1680,9 +1805,10 @@ ocGetNames_ELF ( ObjectCode* oc )
 
 /* Do ELF relocations which lack an explicit addend.  All x86-linux
    relocations appear to be of this form. */
-static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
-                                      Elf32_Shdr* shdr, int shnum, 
-                                      Elf32_Sym*  stab, char* strtab )
+static int
+do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
+                           Elf32_Shdr* shdr, int shnum, 
+                           Elf32_Sym*  stab, char* strtab )
 {
    int j;
    char *symbol;
@@ -1725,22 +1851,22 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
                (void*)S = lookupSymbol( symbol );
          }
          if (!S) {
-            barf("do_Elf32_Rel_relocations:  %s: unknown symbol `%s'", 
-                 oc->fileName, symbol);
+            belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+           return 0;
          }
          IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
       }
       IF_DEBUG(linker,belch( "Reloc: P = %p   S = %p   A = %p",
                             (void*)P, (void*)S, (void*)A )); 
+      checkProddableBlock ( oc, pP );
       switch (ELF32_R_TYPE(info)) {
 #        ifdef i386_TARGET_ARCH
          case R_386_32:   *pP = S + A;     break;
          case R_386_PC32: *pP = S + A - P; break;
 #        endif
          default: 
-            fprintf(stderr, "unhandled ELF relocation(Rel) type %d\n",
-                            ELF32_R_TYPE(info));
-            barf("do_Elf32_Rel_relocations: unhandled ELF relocation type");
+            belch("%s: unhandled ELF relocation(Rel) type %d\n",
+                 oc->fileName, ELF32_R_TYPE(info));
             return 0;
       }
 
@@ -1751,9 +1877,10 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
 
 /* Do ELF relocations for which explicit addends are supplied.
    sparc-solaris relocations appear to be of this form. */
-static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
-                                       Elf32_Shdr* shdr, int shnum, 
-                                       Elf32_Sym*  stab, char* strtab )
+static int
+do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
+                            Elf32_Shdr* shdr, int shnum, 
+                            Elf32_Sym*  stab, char* strtab )
 {
    int j;
    char *symbol;
@@ -1769,13 +1896,12 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
    for (j = 0; j < nent; j++) {
       Elf32_Addr  offset = rtab[j].r_offset;
       Elf32_Word  info   = rtab[j].r_info;
-      Elf32_Sword addend = rtab[j].r_addend;
-
       Elf32_Addr  P  = ((Elf32_Addr)targ) + offset;
-      Elf32_Addr  A  = addend;
       Elf32_Addr  S;
 #     if defined(sparc_TARGET_ARCH)
       /* This #ifdef only serves to avoid unused-var warnings. */
+      Elf32_Sword addend = rtab[j].r_addend;
+      Elf32_Addr  A  = addend;
       Elf32_Word* pP = (Elf32_Word*)P;
       Elf32_Word  w1, w2;
 #     endif
@@ -1802,8 +1928,8 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
                (void*)S = lookupSymbol( symbol );
          }
          if (!S) {
-          barf("do_Elf32_Rela_relocations: %s: unknown symbol `%s'", 
-                   oc->fileName, symbol);
+          belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+          return 0;
           /* 
           S = 0x11223344;
           fprintf ( stderr, "S %p A %p S+A %p S+A-P %p\n",S,A,S+A,S+A-P);
@@ -1813,6 +1939,7 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
       }
       IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n",
                                         (void*)P, (void*)S, (void*)A )); 
+      checkProddableBlock ( oc, (void*)P );
       switch (ELF32_R_TYPE(info)) {
 #        if defined(sparc_TARGET_ARCH)
          case R_SPARC_WDISP30: 
@@ -1836,15 +1963,25 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
             w1 |= w2;
             *pP = w1;
             break;
+         /* According to the Sun documentation:
+            R_SPARC_UA32 
+            This relocation type resembles R_SPARC_32, except it refers to an
+            unaligned word. That is, the word to be relocated must be treated
+            as four separate bytes with arbitrary alignment, not as a word
+            aligned according to the architecture requirements.
+
+            (JRS: which means that freeloading on the R_SPARC_32 case
+            is probably wrong, but hey ...)  
+         */
+         case R_SPARC_UA32:
          case R_SPARC_32:
             w2 = (Elf32_Word)(S + A);
             *pP = w2;
             break;
 #        endif
          default: 
-            fprintf(stderr, "unhandled ELF relocation(RelA) type %d\n",
-                            ELF32_R_TYPE(info));
-            barf("do_Elf32_Rela_relocations: unhandled ELF relocation type");
+            belch("%s: unhandled ELF relocation(RelA) type %d\n",
+                 oc->fileName, ELF32_R_TYPE(info));
             return 0;
       }
 
@@ -1870,7 +2007,7 @@ ocResolve_ELF ( ObjectCode* oc )
    strtab = findElfSection ( ehdrC, SHT_STRTAB );
 
    if (stab == NULL || strtab == NULL) {
-      belch("ocResolve_ELF: can't find string or symbol table");
+      belch("%s: can't find string or symbol table", oc->fileName);
       return 0; 
    }