[project @ 2001-08-31 14:32:03 by sewardj]
[ghc-hetmet.git] / ghc / rts / Linker.c
index 10423a1..1f958cb 100644 (file)
@@ -1,12 +1,13 @@
 /* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.49 2001/06/29 16:17:28 sewardj Exp $
+ * $Id: Linker.c,v 1.62 2001/08/31 14:32:03 sewardj 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"
@@ -151,6 +152,10 @@ typedef struct _RtsSymbolVal {
       SymX(GetExitCodeProcess)                  \
       SymX(WaitForSingleObject)                 \
       SymX(CreateProcessA)                      \
+      Sym(__divdi3)                             \
+      Sym(__udivdi3)                            \
+      Sym(__moddi3)                             \
+      Sym(__umoddi3)                            \
       SymX(_errno)
 #endif
 
@@ -233,6 +238,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)                 \
@@ -268,6 +274,8 @@ typedef struct _RtsSymbolVal {
       SymX(__gmpz_get_ui)                      \
       SymX(prog_argv)                          \
       SymX(prog_argc)                          \
+      SymX(getProgArgv)                                \
+      SymX(setProgArgv)                                \
       SymX(resetNonBlockingFd)                 \
       SymX(performGC)                          \
       SymX(getStablePtr)                       \
@@ -331,41 +339,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 */
@@ -451,7 +424,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;
@@ -533,10 +506,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;
@@ -604,6 +589,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;
@@ -724,6 +710,39 @@ 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");
+}
+
+
 /* --------------------------------------------------------------------------
  * PEi386 specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
@@ -1051,13 +1070,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
@@ -1076,9 +1097,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");
@@ -1105,12 +1126,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 
@@ -1149,6 +1170,25 @@ ocGetNames_PEi386 ( ObjectCode* oc )
             + hdr->PointerToSymbolTable
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
+   /* Allocate space for any (local, anonymous) .bss sections. */
+
+   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 section at 0x%x\n", zspace); */
+   }
+
    /* Copy exported symbols into the ObjectCode. */
 
    oc->n_symbols = hdr->NumberOfSymbols;
@@ -1165,33 +1205,66 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       symtab_i = (COFF_symbol*)
                  myindex ( sizeof_COFF_symbol, symtab, i );
 
-      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL &&
-          symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
+      addr  = NULL;
 
+      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL
+          && symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
          /* 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 );
+         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)");
+         addProddableBlock(oc, addr, symtab_i->Value);
+      }
+
+      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++;
    }
@@ -1213,7 +1286,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.
@@ -1221,7 +1294,7 @@ 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) ||
           0==strcmp(".rodata",sectab_i->Name))
@@ -1240,9 +1313,12 @@ ocGetNames_PEi386 ( ObjectCode* oc )
          return 0;
       }
 
-      oc->sections[i].start = start;
-      oc->sections[i].end   = end;
-      oc->sections[i].kind  = kind;
+      if (end >= start) {
+         oc->sections[i].start = start;
+         oc->sections[i].end   = end;
+         oc->sections[i].kind  = kind;
+         addProddableBlock(oc, start, end - start + 1);
+      }
    }
 
    return 1;   
@@ -1322,8 +1398,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))
@@ -1336,12 +1411,11 @@ ocResolve_PEi386 ( ObjectCode* oc )
             if ((void*)S == NULL)
                (void*)S = lookupSymbol( symbol );
             if (S == 0) {
-               belch("ocResolve_PEi386: %s: unknown symbol `%s'", 
-                      oc->fileName, symbol);
+               belch("%s: unknown symbol `%s'", oc->fileName, symbol);
                return 0;
             }
          }
-
+         checkProddableBlock(oc, pP);
          switch (reltab_j->Type) {
             case MYIMAGE_REL_I386_DIR32: 
                *pP = A + S; 
@@ -1362,17 +1436,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;
 }
 
@@ -1390,7 +1462,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>
 
@@ -1429,13 +1506,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;
    }
 
@@ -1447,12 +1524,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" ));
@@ -1462,7 +1539,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;
    }
 
@@ -1475,7 +1552,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", 
@@ -1516,7 +1593,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;
    }
 
@@ -1533,7 +1610,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++) {
@@ -1568,7 +1645,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;
    }
 
@@ -1591,7 +1668,7 @@ ocGetNames_ELF ( ObjectCode* oc )
    ASSERT(symhash != NULL);
 
    if (!strtab) {
-      belch("ocGetNames_ELF: no strtab");
+      belch("%s: no strtab", oc->fileName);
       return 0;
    }
 
@@ -1605,18 +1682,38 @@ ocGetNames_ELF ( ObjectCode* oc )
       /* 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);
+         /* We don't prod BSS sections, hence the following isn't
+            necessary:
+               addProddableBlock(oc, zspace, shdr[i].sh_size);
+         */
+         /*
+         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;
-      
+      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 */
@@ -1641,11 +1738,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;
@@ -1682,9 +1788,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;
@@ -1727,22 +1834,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;
       }
 
@@ -1753,9 +1860,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;
@@ -1804,8 +1912,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);
@@ -1815,6 +1923,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, P );
       switch (ELF32_R_TYPE(info)) {
 #        if defined(sparc_TARGET_ARCH)
          case R_SPARC_WDISP30: 
@@ -1838,15 +1947,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;
       }
 
@@ -1872,7 +1991,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; 
    }