Index: /trunk/emx/src/emxomf/emxomfld.c
===================================================================
--- /trunk/emx/src/emxomf/emxomfld.c	(revision 3666)
+++ /trunk/emx/src/emxomf/emxomfld.c	(revision 3667)
@@ -37,4 +37,6 @@
 #include <alloca.h>
 #include <sys/omflib.h>
+#include <sys/elf.h>
+#include <ar.h>
 #include "defs.h"
 #include "weakld.h"
@@ -51,4 +53,12 @@
 } name_list;
 
+/* OMF record header. */
+#pragma pack(1)
+typedef struct omf_rec_hdr
+{
+    byte type;
+    word len;
+} omf_rec_hdr;
+#pragma pack()
 
 /* Whether or not linker tracing is enabled. */
@@ -504,4 +514,245 @@
 
 /**
+ * Reports archive parsing error.
+ * @returns 0.
+ * @param   pszError    The parsing error.
+ */
+static int bad_arch(const char *pszError)
+{
+    fprintf(stderr, "emxomfld: failed parsing archive: %s\n", pszError);
+    return 0;
+}
+
+/** 
+ * Validates a numeric ar_hdr field.
+ *
+ * These are supposed to be padded with spaces, however, emximp seems to be 
+ * using null terminators as well (ar_mode for instance). 
+ *
+ * @returns 1 if valid, 0 if invalid.
+ * @param   pachField       The field.
+ * @param   cchField        The field length.
+ * @param   uBase           10 for decimal, 8 for octal.
+ * @param   pszName         The field name.
+ */
+static int is_arch_num_field_valid(char const *pachField, size_t cchField, unsigned uBase, const char *pszName)
+{
+    while (cchField > 0)
+    {
+        unsigned ch = *pachField;
+        if (ch - '0' >= uBase)
+        {
+            if (ch == ' ' || !ch)
+                break;
+            return bad_arch(pszName);
+        }
+        cchField--;
+        pachField++;
+    }
+
+    while (cchField > 0)
+    {
+        char ch = *pachField;
+        if (ch != ' ' && ch)
+            return bad_arch(pszName);
+        cchField--;
+        pachField++;
+    }
+    
+    return 1;
+}
+
+/**
+ * Checks the name field to see if there is a BSD style variable sized name
+ * field following the header.
+ 
+ * @returns 0 if none, length if something.
+ * @param   pArHdr          The archive header.
+ */
+static unsigned arch_hdr_get_ext_name_len(struct ar_hdr *pArHdr)
+{
+    unsigned cchExtName = 0;
+    if (!memcmp(&pArHdr->ar_name[0], AR_EFMT1, sizeof(AR_EFMT1) - 1))
+    {
+        int         cch = sizeof(pArHdr->ar_name) - sizeof(AR_EFMT1) - 1;
+        const char *pch = &pArHdr->ar_name[sizeof(AR_EFMT1) - 1];
+        while (cch-- > 0)
+        {
+            unsigned uDig = (unsigned char)*pch++ - '0';
+            if (uDig > 10)
+                break;
+            cchExtName *= 10;
+            cchExtName += uDig;
+        }
+    }
+    return cchExtName;
+}
+
+/**
+ * Converts the size field of the header into something we can use.
+ * @returns ar_size as off_t.
+ * @param   pArHdr          The archive header.
+ */
+static off_t arch_hdr_get_size(struct ar_hdr *pArHdr)
+{
+    off_t       cb  = 0;
+    int         cch = sizeof(pArHdr->ar_size);
+    const char *pch = &pArHdr->ar_size[0];
+    while (cch-- > 0)
+    {
+        unsigned uDig = (unsigned char)*pch++ - '0';
+        if (uDig > 10)
+            break;
+        cb *= 10;
+        cb += uDig;
+    }
+    return cb;
+}
+
+/**
+ * Matches @a pszName with the name in the archive header.
+ *
+ * @returns 1 if matches, 0 if not.
+ * @param   pArHdr          The archive header.
+ * @param   pszName         The name to match it with.
+ */
+static int arch_hdr_match_name(struct ar_hdr *pArHdr, const char *pszName)
+{
+    size_t      cch = sizeof(pArHdr->ar_name);
+    const char *pch = &pArHdr->ar_name[0];
+    while (cch > 0)
+    {
+        if (*pszName != *pch)
+        {
+            if (*pszName)
+                return 0;
+            break;
+        }
+        cch--;
+        pszName++;
+        pch++;
+    }
+    
+    while (cch-- > 0)
+    {
+        char ch = *pch++;
+        if (ch != ' ' && ch)
+            return 0;
+    }
+    
+    return 1;
+}
+
+/**
+ * Checks if the stream @a pFile is an archive only containing ELF and OMF 
+ * files.
+ *
+ * @returns 1 if so, 0 if not.
+ * @param   pFile   The file stream to check.  The caller rewinds the stream.
+ */
+static int check_arch_library_with_omf_and_or_elf(FILE *pFile)
+{
+    union 
+    {
+        char            achMagic[SARMAG];
+        struct ar_hdr   ArHdr;
+        Elf32_Ehdr      Elfhdr;
+        omf_rec_hdr     OmfHdr;
+        /*struct exec     AoutHdr;*/
+    } uBuf;
+    off_t offArchive;
+
+    /*
+     * Read+reverify the magic.
+     */
+    if (fread(&uBuf.achMagic[0], SARMAG, 1, pFile) != 1)
+        return 0;
+    if (memcmp(&uBuf.achMagic[0], ARMAG, SARMAG) != 0)
+        return 0;
+
+    /*
+     * Process the archive, file by file.
+     */
+    offArchive = SARMAG;
+    while (!feof(pFile))
+    {
+        off_t   cbFile;
+        off_t   offNext;
+        size_t  cbRead;
+        int     cchExtraName;
+
+        /* read + verify the archive header */
+        cbRead = fread(&uBuf.ArHdr, 1, sizeof(uBuf.ArHdr), pFile);
+        if (cbRead != sizeof(uBuf.ArHdr))
+            return cbRead == 0 && feof(pFile) ? 1 : bad_arch("fread");
+        offArchive += sizeof(uBuf.ArHdr);
+
+        if (memcmp(uBuf.ArHdr.ar_fmag, ARFMAG, sizeof(uBuf.ArHdr.ar_fmag)))
+            return bad_arch("ar_fmag");
+        if (   !is_arch_num_field_valid(uBuf.ArHdr.ar_date, sizeof(uBuf.ArHdr.ar_date), 10, "ar_date")
+            || !is_arch_num_field_valid(uBuf.ArHdr.ar_uid,  sizeof(uBuf.ArHdr.ar_uid),  10, "ar_uid")
+            || !is_arch_num_field_valid(uBuf.ArHdr.ar_gid,  sizeof(uBuf.ArHdr.ar_gid),  10, "ar_gid")
+            || !is_arch_num_field_valid(uBuf.ArHdr.ar_mode, sizeof(uBuf.ArHdr.ar_mode),  8, "ar_mode")
+            || !is_arch_num_field_valid(uBuf.ArHdr.ar_size, sizeof(uBuf.ArHdr.ar_size), 10, "ar_size") )
+            return 0; /* bitched already */
+        
+        cbFile  = arch_hdr_get_size(&uBuf.ArHdr);
+        offNext = offArchive + cbFile;
+        offNext += offNext & 1;         /* make even */
+
+        /* skip the extended name field if present (BSD). */
+        cchExtraName = arch_hdr_get_ext_name_len(&uBuf.ArHdr);
+        /*fprintf(stderr, "%#06x '%.16s' offNext=%#x cb=%#x ext=%d\n", (unsigned)offArchive, &uBuf.ArHdr.ar_name[0], (unsigned)offNext, (unsigned)cbFile, cchExtraName);*/
+        if (cchExtraName)
+        {
+            cbFile     -= cchExtraName;
+            offArchive += cchExtraName;
+            if (fseek(pFile, offArchive, SEEK_SET))
+                return bad_arch("fseek-ext-name");
+        }
+
+        /* ignore the archive symbol table. */
+        if (   !arch_hdr_match_name(&uBuf.ArHdr, "__.SYMDEF")
+            && !arch_hdr_match_name(&uBuf.ArHdr, "/")
+            && !arch_hdr_match_name(&uBuf.ArHdr, "ARFILENAMES/")
+            && !arch_hdr_match_name(&uBuf.ArHdr, "//"))
+        {            
+            cbRead = sizeof(uBuf);
+            if (cbRead > cbFile)
+            {
+                cbRead = cbFile;
+                memset(&uBuf, 0, sizeof(uBuf));
+            }
+            if (fread(&uBuf, 1, cbRead, pFile) != cbRead)
+                return bad_arch("fread-member-hdr");
+
+            if (   (   uBuf.OmfHdr.len >= sizeof(uBuf.OmfHdr)
+                    && cbRead > sizeof(sizeof(uBuf.OmfHdr)) )
+                    && (   uBuf.OmfHdr.type == THEADR 
+                        /*|| uBuf.OmfHdr.type == LIBADR - doubt wlink can handle this */)
+                || IS_ELF(uBuf.Elfhdr) )
+            { 
+                /* nothing */ 
+                /*fprintf(stderr, IS_ELF(uBuf.Elfhdr) ? "ELF\n" : "OMF\n");*/
+            }
+            else
+            {
+                /*fprintf(stderr, "not omf or elf\n");*/
+                return 0;
+            }
+        }
+        /*else
+            fprintf(stderr, "skip archive symbol table\n");*/
+        
+        /* advance to the next file */
+        if (fseek(pFile, offNext, SEEK_SET))
+            return bad_arch("fseek-next");
+        offArchive = offNext;
+    }
+
+    return 1;            
+}
+
+/**
  * Checks if the stream phFile is an OMF library.
  *
@@ -546,22 +797,50 @@
  * @param   phFile  Filestream to check.
  */
-static int check_omf(FILE *phFile)
+static int check_omf_or_elf(FILE *phFile)
 {
 #pragma pack(1)
-    struct
-    {
-        byte rec_type;
-        word rec_len;
-    } omfhdr;
+    union
+    {
+        struct
+        {
+            byte rec_type;
+            word rec_len;
+        }    omfhdr;
+        byte elfmagic[4];
+        char arch[7];
+    } u;
 #pragma pack()
-    if (    fread(&omfhdr, 1, sizeof(omfhdr), phFile) == sizeof (omfhdr)
-        &&  omfhdr.rec_type == THEADR
-        &&  omfhdr.rec_len >= sizeof(omfhdr)
-        &&  !fseek(phFile, 0, SEEK_SET)
-       )
+    size_t cbRead = fread(&u.omfhdr, 1, sizeof(u), phFile);
+    if (fseek(phFile, 0, SEEK_SET))
+        return 0;
+
+    /* OMF object or library? */
+    if (   cbRead >= sizeof(u.omfhdr)   
+        && u.omfhdr.rec_type == THEADR
+        && u.omfhdr.rec_len >= sizeof(u.omfhdr) )
         return 1;
-
-    return !fseek(phFile, 0, SEEK_SET)
-        && check_omf_library(phFile);
+    if (   cbRead >= sizeof(u.omfhdr)
+        && u.omfhdr.rec_type == LIBHDR)
+        return check_omf_library(phFile);
+    
+    /* ELF object? */
+    if (   u.elfmagic[0] == ELFMAG0
+        && u.elfmagic[1] == ELFMAG1
+        && u.elfmagic[2] == ELFMAG2
+        && u.elfmagic[3] == ELFMAG3)
+        return 1;
+
+    /* AR archive with OMF and/or ELF content? */
+    if (   cbRead >= sizeof("!<arch>") - 1
+        && !memcmp(u.arch, "!<arch>", sizeof(u.arch)))
+    {
+        int rc = check_arch_library_with_omf_and_or_elf(phFile);
+        if (fseek(phFile, 0, SEEK_SET))
+            rc = 0;
+        return rc;
+    }
+
+    /* Not anything we know */
+    return 0;
 }
 
@@ -637,5 +916,5 @@
 
     /* We need to apply _realrealpath to the tmpdir, so resolve that once and for all. */
-    if (!s_szTmp[0]) 
+    if (!s_szTmp[0])
     {
         const char *    pszTmp = getenv("TMP");
@@ -863,5 +1142,5 @@
      */
     if (    autoconvert_flag
-        &&  !check_omf(phFile))
+        &&  !check_omf_or_elf(phFile))
         phFile = aout_to_omf(phFile, pszFullname, FALSE);
 
@@ -1006,5 +1285,5 @@
                         if (check_lx_dll(phFile))
                             phFile = lx_to_omf(phFile, pszFullname);
-                        else if (!check_omf(phFile))
+                        else if (!check_omf_or_elf(phFile))
                             phFile = aout_to_omf(phFile, pszFullname, TRUE);
                     }
@@ -1367,5 +1646,8 @@
       case _MD_STUB:
         if (!stmt->stub.none)
-          fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
+          {
+            fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
+            *(int*)(arg) = 0; /*need_stub*/
+          }
         else
           fprintf (stderr, "emxomfld: warning: \"STUB NONE\" is not supported by wlink. ignoring\n");
@@ -2085,4 +2367,5 @@
     {
       unsigned uPMType = 0;
+      int need_stub = 1;
 
       open_response_file ();
@@ -2275,11 +2558,4 @@
         fprintf (response_file, "OPTION OFFSET=%s\n", base);
 
-      /* the stub */
-
-      _execname(&execname[0], sizeof(execname));
-      strcpy (_getname (&execname[0]), "os2stub.bin");
-      if (!stat (execname, &s))
-        fprintf (response_file, "OPTION STUB='%s'\n", execname);
-
       /* Add the /INFORMATION option if the -i or -t option was given.  This is
          for debugging. */
@@ -2305,4 +2581,5 @@
 
       /* Translate the essentials of the module definition file into wlink lingo. */
+      
       if (def_fname)
         {
@@ -2314,7 +2591,18 @@
             }
           _md_next_token (pMd);
-          _md_parse (pMd, def_2_watcom, NULL);
+          _md_parse (pMd, def_2_watcom, &need_stub);
           _md_close (pMd);
         }
+      
+      /* the stub */
+
+      if (need_stub)
+        {
+          _execname(&execname[0], sizeof(execname));
+          strcpy (_getname (&execname[0]), "os2stub.bin");
+          if (!stat (execname, &s))
+            fprintf (response_file, "OPTION STUB='%s'\n", execname);
+        }
+
     }
 
Index: /trunk/emx/src/emxomf/weakld.c
===================================================================
--- /trunk/emx/src/emxomf/weakld.c	(revision 3666)
+++ /trunk/emx/src/emxomf/weakld.c	(revision 3667)
@@ -35,5 +35,5 @@
  * There is a couple of symbol types, but we can skip most of them for this
  * pre-linking operation. We use one symbol type which is public or global
- * symbols if you like. Perhaps it would be wise to devide them into separat
+ * symbols if you like. Perhaps it would be wise to divide them into separat
  * type groups, but the choice was made to differenciate this using flags.
  * So, symbol enumeration is done using flag masks.
@@ -101,4 +101,6 @@
 #include <sys/omflib.h>
 #include <sys/moddef.h>
+#include <sys/elf.h>
+#include <ar.h>
 #include "defs.h"
 #include "grow.h"
@@ -155,11 +157,24 @@
     const char *pszLibName;
     /** Filehandle if open */
-    FILE *      phFile;
-    /** Pointer to extended dictiorary. */
-    void *      pDict;
-    /** Library header. */
-    OMFLIBHDR   LibHdr;
+    FILE       *phFile;
+    /** Set if it's a OMF library, clear if it's a unix archive. */
+    unsigned    fOmfLib;
+    /** Pointer to the extended dictionary (OMF) / symbol table (AR). */
+    void       *pDict;
+    union
+    {
+        struct
+        {
+            /** Library header. */
+            OMFLIBHDR   LibHdr;
+        } Omf;
+        struct
+        {
+            /** Later. */
+            unsigned    uDummy;
+        } Ar;
+    } u;
     /** Linked list next pointer. */
-    struct wldlib * pNext;
+    struct wldlib *pNext;
 } WLDLIB, *PWLDLIB;
 
@@ -414,4 +429,5 @@
 static void         wldIntErr(PWLD pWld, PWLDMOD pMod, const char *pszFile, unsigned iLine, const char *pszFunction);
 static unsigned     pass1ReadOMFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch);
+static unsigned     pass1ReadELFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch);
 /** Parameter structure for wldDefCallback(). */
 typedef struct wldDefCallback_param
@@ -434,5 +450,33 @@
 static void         libCloseDict(PWLDLIB pLib);
 static int          libTryLoadSymbolThruDictionary(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
+static int          libLoadUndefSymbolsFromOmfLib(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
+/**
+ * Callback parameter structure used between libLoadUndefSymbolsFromArchLib 
+ * and libLoadUndefSymbolsFromArchLibCallback
+ */
+typedef struct libLoadUndefSymbolsFromArchLib_param
+{
+    /** The linker instance. */
+    PWLD        pWld;
+    /** The library. */
+    PWLDLIB     pLib;
+    /** See libLoadUndefSymbols. */
+    PWLDSYM     pSym;
+    /** See libLoadUndefSymbols. */
+    unsigned   *pcLoaded;
+} WLDLIBLOADUSFALPARAM, *PWLDLIBLOADUSFALPARAM;
+static int          libLoadUndefSymbolsFromArchLibCallback(FILE *pFile, const char *pszName, off_t cbFile, void *pvUser);
+static int          libLoadUndefSymbolsFromArchLib(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
 static int          libLoadUndefSymbols(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
+/**
+ * Enumeration callback routine.
+ * @returns Any non-zero value stops the enumeration and is passed to the caller.
+ * @param   pFile       Stream positioned at the start of the file. Don't close.
+ * @param   pszName     The file name.
+ * @param   cbFile      The file size.
+ * @param   pvUser      The user parameter.
+ */
+typedef int (* PFNLIBENUMFILE)(FILE *pFile, const char *pszName, off_t cbFile, void *pvUser);
+static int          libEnumFilesArch(PWLDLIB pLib, int fAll, PFNLIBENUMFILE pfnCallback, void *pvUser);
 static int          libErr(PWLDLIB pLib, const char *pszFormat, ...);
 #if 0
@@ -678,35 +722,48 @@
 #if 0
     FILE *phFile;
+
     /* been here, done that? */
-    if (pLib->pDict)
+    if (pLib->upDict)
         return 0;
 
-    /* check if it acutally is a library and have an ext dict */
-    if (    pLib->LibHdr.chType != LIBHDR
-        ||  pLib->LibHdr.offDict != 0
-        ||  pLib->LibHdr.cDictBlocks != 0)
-        return 1;
-
+    if (pLib->fOmfLib)
+    {
+        /* check if it acutally is a library and have an ext dict */
+        if (    pLib->u.Omf.LibHdr.chType != LIBHDR
+            ||  pLib->u.Omf.LibHdr.offDict != 0
+            ||  pLib->u.Omf.LibHdr.cDictBlocks != 0)
+            return 1;
+    }
+    else
+    {
+    }
+    
     /* ensure it's open. */
     phFile = libOpen(pLib);
     if (!phFile)
         return -1;
-
-    /* position us */
-    if (fseek(phFile, pLib->LibHdr.offDict, SEEK_SET))
-        return libErr(pLib, "Failed to seek to extended dictionary (offset %d).", (int)pLib->LibHdr.offDict);
-
-    /* read it */
-    pLib->pDict = xmalloc(pLib->LibHdr.cDictBlocks * 512);
-    if (fread(pLib->pDict, 512, pLib->LibHdr.cDictBlocks, phFile) == pLib->LibHdr.cDictBlocks)
-        return 0;
-    libErr(pLib, "Failed to read extended dictionary.");
+    
+    if (pLib->fOmfLib)
+    {
+        /* position us */
+        if (fseek(phFile, pLib->LibHdr.offDict, SEEK_SET))
+            return libErr(pLib, "Failed to seek to extended dictionary (offset %d).", (int)pLib->LibHdr.offDict);
+    
+        /* read it */
+        pLib->pDict = xmalloc(pLib->LibHdr.cDictBlocks * 512);
+        if (fread(pLib->pDict, 512, pLib->LibHdr.cDictBlocks, phFile) == pLib->LibHdr.cDictBlocks)
+            return 0;
+        
+        libErr(pLib, "Failed to read extended dictionary.");
+    }
+    
     free(pLib->pDict);
     pLib->pDict = NULL;
     return -1;
+
 #else
     /* till we support processing the dictionary, we pretend there is none. */
     pLib->pDict = NULL;
-    return -1;
+    return 1;
 #endif
 }
@@ -741,23 +798,18 @@
 static int          libTryLoadSymbolThruDictionary(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
 {
-    return libLoadUndefSymbols(pWld, pLib, pSym, pcLoaded); /* @todo implement this function! */
-}
-
-
-/**
- * Read thru an module looking for definitions for undef symbols.
- * If a definition is found we'll load the module containing it.
- *
- * @returns 0 on non failure.
- * @returns 42 if none found.
- * @returns -1 on link abort error.
- * @param   pWld    Linker instance.
- * @param   pLib    Library to search.
- * @param   pSym    Undefined symbol to search for.
- *                  If NULL we'll try and see if any defined global symbol we
- *                  encounter is undefined.
+    return libLoadUndefSymbols(pWld, pLib, pSym, pcLoaded); /** @todo implement this function! */
+}
+
+
+/**
+ * Implementation of libLoadUndefSymbols for unix archives.
+ *
+ * @returns see libLoadUndefSymbols
+ * @param   pWld        Linker instance.
+ * @param   pLib        Library to search.
+ * @param   pSym        See libLoadUndefSymbols.
  * @param   pcLoaded    Number of modules which was loaded from this library.
  */
-static int          libLoadUndefSymbols(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
+static int          libLoadUndefSymbolsFromOmfLib(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
 {
     FILE *          phFile = pLib->phFile;
@@ -774,8 +826,8 @@
 
     /* Position the library at the first module record. */
-    if (fseek(phFile, pLib->LibHdr.chType == LIBHDR ? pLib->LibHdr.cb + 3 : 0, SEEK_SET))
+    if (fseek(phFile, pLib->u.Omf.LibHdr.chType == LIBHDR ? pLib->u.Omf.LibHdr.cb + 3 : 0, SEEK_SET))
         return libErr(pLib, "Error when seeking to first module.");
 
-    if (pLib->LibHdr.chType != LIBHDR)
+    if (pLib->u.Omf.LibHdr.chType != LIBHDR)
     {
         uchEnd1 = MODEND;
@@ -1004,5 +1056,5 @@
             if (OmfRec.chType == MODEND || OmfRec.chType == (MODEND | REC32))
             {
-                unsigned    cbPage = pLib->LibHdr.cb + 3;
+                unsigned    cbPage = pLib->u.Omf.LibHdr.cb + 3;
                 off_t       off = ftell(phFile) + offSkip;
                 off -= cbPage * (off / cbPage); /* don't trust this to be 2**n. */
@@ -1031,5 +1083,259 @@
 
 /**
+ * Callback used by libLoadUndefSymbolsFromArchLib
+ *
+ * @returns 0 or -1  see libLoadUndefSymbols.
+ * @param   phFile      The library stream, positioned at the start of the file.  
+ * @param   pszName     The (short) file name.
+ * @param   cbFile      The file size.
+ * @param   pvUser      Parameters.
+ */
+static int          libLoadUndefSymbolsFromArchLibCallback(FILE *pFile, const char *pszName, off_t cbFile, void *pvUser)
+{  
+    PWLDLIBLOADUSFALPARAM pParam = (PWLDLIBLOADUSFALPARAM)pvUser;
+    /** @todo */
+    return 0;
+}
+
+
+/**
+ * Implementation of libLoadUndefSymbols for unix archives.
+ *
+ * @returns see libLoadUndefSymbols
+ * @param   pWld        Linker instance.
+ * @param   pLib        Library to search.
+ * @param   pSym        See libLoadUndefSymbols.
+ * @param   pcLoaded    Number of modules which was loaded from this library.
+ */
+static int          libLoadUndefSymbolsFromArchLib(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
+{
+    WLDLIBLOADUSFALPARAM Param;
+
+    Param.pWld      = pWld;
+    Param.pLib      = pLib;
+    Param.pSym      = pSym;
+    Param.pcLoaded  = pcLoaded;
+    return libEnumFilesArch(pLib, 0 /*fAll*/, libLoadUndefSymbolsFromArchLibCallback, &Param);
+}
+
+
+/**
+ * Read thru a library looking for definitions for undef symbols.
+ * If a definition is found we'll load the module containing it.
+ *
+ * @returns 0 on non failure.
+ * @returns 42 if none found.
+ * @returns -1 on link abort error.
+ * @param   pWld    Linker instance.
+ * @param   pLib    Library to search.
+ * @param   pSym    Undefined symbol to search for.
+ *                  If NULL we'll try and see if any defined global symbol we
+ *                  encounter is undefined.
+ * @param   pcLoaded    Number of modules which was loaded from this library.
+ */
+static int          libLoadUndefSymbols(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
+{
+    if (!pLib->fOmfLib)
+        return libLoadUndefSymbolsFromArchLib(pWld, pLib, pSym, pcLoaded); 
+    return libLoadUndefSymbolsFromOmfLib(pWld, pLib, pSym, pcLoaded);
+}
+
+
+/** 
+ * Validates a numeric ar_hdr field.
+ *
+ * These are supposed to be padded with spaces, however, emximp seems to be 
+ * using null terminators as well (ar_mode for instance). 
+ *
+ * @returns 0 if valid, -1 if invalid (error shown).
+ * @param   pachField       The field.
+ * @param   cchField        The field length.
+ * @param   uBase           10 for decimal, 8 for octal.
+ * @param   pszName         The field name.
+ */
+static int libArchValidateNumField(PWLDLIB pLib, char const *pachField, size_t cchField, unsigned uBase, const char *pszName)
+{
+    while (cchField > 0)
+    {
+        unsigned ch = *pachField;
+        if (ch - '0' >= uBase)
+        {
+            if (ch == ' ' || !ch)
+                break;
+            return libErr(pLib, "bad archive header field: %s", pszName);
+        }
+        cchField--;
+        pachField++;
+    }
+
+    while (cchField > 0)
+    {
+        char ch = *pachField;
+        if (ch != ' ' && ch)
+            return libErr(pLib, "bad archive header field: %s", pszName);
+        cchField--;
+        pachField++;
+    }
+    
+    return 0;
+}
+
+/**
+ * Checks the name field to see if there is a BSD style variable sized name
+ * field following the header.
+ *
+ * @returns 0 if none, length if something.
+ * @param   pArHdr          The archive header.
+ */
+static unsigned libArchHdrGetExtNameLen(struct ar_hdr *pArHdr)
+{
+    unsigned cchExtName = 0;
+    if (!memcmp(&pArHdr->ar_name[0], AR_EFMT1, sizeof(AR_EFMT1) - 1))
+    {
+        int         cch = sizeof(pArHdr->ar_name) - sizeof(AR_EFMT1) - 1;
+        const char *pch = &pArHdr->ar_name[sizeof(AR_EFMT1) - 1];
+        while (cch-- > 0)
+        {
+            unsigned uDig = (unsigned char)*pch++ - '0';
+            if (uDig > 10)
+                break;
+            cchExtName *= 10;
+            cchExtName += uDig;
+        }
+    }
+    return cchExtName;
+}
+
+
+/**
+ * Converts the size field of the header into something we can use.
+ * @returns ar_size as off_t.
+ * @param   pArHdr          The archive header.
+ */
+static off_t libArchHdrGetSize(struct ar_hdr *pArHdr)
+{
+    off_t       cb  = 0;
+    int         cch = sizeof(pArHdr->ar_size);
+    const char *pch = &pArHdr->ar_size[0];
+    while (cch-- > 0)
+    {
+        unsigned uDig = (unsigned char)*pch++ - '0';
+        if (uDig > 10)
+            break;
+        cb *= 10;
+        cb += uDig;
+    }
+    return cb;
+}
+
+
+/**
+ * Enumerates the files in the unix archive.
+ * 
+ * @returns 0 if pfnCallback returned 0 for all the files.
+ * @returns first non-zero value pfnCallback returns (stops enumeration).
+ * @returns -1 if the library is invalid.
+ * @param   pLib        The Library to enumerate
+ * @param   fAll        Whether to include the special files or not.
+ * @param   pfnCallback The callback to invoke for each file.
+ * @param   pvUser      The user argument to pass to the callback.
+ */
+static int          libEnumFilesArch(PWLDLIB pLib, int fAll, PFNLIBENUMFILE pfnCallback, void *pvUser)
+{
+    int     rc      = 0;
+    FILE   *pFile   = pLib->phFile;
+    off_t   offNext;
+    char    szMagic[SARMAG + 1];
+
+    if (pLib->fOmfLib)
+        return libErr(pLib, "OMF library, expected ARCH!");
+
+    /*
+     * Read+reverify the magic.
+     */
+    if (   fseek(pFile, 0, SEEK_SET) != 0
+        || fread(&szMagic[0], SARMAG, 1, pFile) != 1)
+        return libErr(pLib, "failed to read library magic");
+    szMagic[SARMAG] = '\0';
+    if (strcmp(szMagic, ARMAG) != 0)
+        return libErr(pLib, "invalid library magic");
+
+    /*
+     * Process the archive, file by file.
+     */
+    offNext = SARMAG;
+    while (!feof(pFile))
+    {
+        struct ar_hdr   ArHdr;
+        off_t           cbFile;
+        size_t          cbRead;
+        int             cchExtraName;
+        int             fSpecial;
+        int             i;
+
+        /* read + verify the archive header */
+        cbRead = fread(&ArHdr, 1, sizeof(ArHdr), pFile);
+        if (cbRead != sizeof(ArHdr))
+            return cbRead == 0 && feof(pFile) ? 0 : libErr(pLib, "fread error");
+        offNext += sizeof(ArHdr);
+
+        if (memcmp(ArHdr.ar_fmag, ARFMAG, sizeof(ArHdr.ar_fmag)))
+            return libErr(pLib, "Bad ar_fmag value");
+        if (   libArchValidateNumField(pLib, ArHdr.ar_date, sizeof(ArHdr.ar_date), 10, "ar_date")
+            || libArchValidateNumField(pLib, ArHdr.ar_uid,  sizeof(ArHdr.ar_uid),  10, "ar_uid")
+            || libArchValidateNumField(pLib, ArHdr.ar_gid,  sizeof(ArHdr.ar_gid),  10, "ar_gid")
+            || libArchValidateNumField(pLib, ArHdr.ar_mode, sizeof(ArHdr.ar_mode),  8, "ar_mode")
+            || libArchValidateNumField(pLib, ArHdr.ar_size, sizeof(ArHdr.ar_size), 10, "ar_size") )
+            return 0; /* bitched already */
+        
+        cbFile   = libArchHdrGetSize(&ArHdr);
+        offNext += cbFile;
+        offNext += offNext & 1;         /* make even */
+
+        /* skip the extended name field if present (BSD). */
+        cchExtraName = libArchHdrGetExtNameLen(&ArHdr);
+        if (cchExtraName)
+        {
+            cbFile -= cchExtraName;
+            if (fseek(pFile, cchExtraName, SEEK_CUR))
+                return libErr(pLib, "fseek past the extended name failed");
+        }
+
+        /* strip trailing spaces from the header name. */
+        i = sizeof(ArHdr.ar_name);
+        ArHdr.ar_name[i] = '\0';
+        while (i-- > 0 && ArHdr.ar_name[i] == ' ')
+            ArHdr.ar_name[i] = '\0';
+
+        fSpecial = !strcmp(ArHdr.ar_name, "__.SYMDEF")
+                || !strcmp(ArHdr.ar_name, "/") 
+                || !strcmp(ArHdr.ar_name, "//") 
+                || !strcmp(ArHdr.ar_name, "ARFILENAMES");
+
+        /* trailing slashes used to be fashionable. */
+        if (!fSpecial && i > 0 && ArHdr.ar_name[i] == '/') 
+            ArHdr.ar_name[i] = '\0';
+
+        /* ignore the archive symbol table. */
+        if (   fAll
+            || !fSpecial)
+        {           
+            rc = pfnCallback(pFile, ArHdr.ar_name, cbFile, pvUser);
+            if (rc)
+                return rc;
+        }
+        
+        /* advance to the next file */
+        if (fseek(pFile, offNext, SEEK_SET))
+            return libErr(pLib, "seek next failed.");
+    }
+    
+    return 0;            
+}
+
+
+/**
  * Put out an error for this library.
+ * @returns -1.
  * @param   pLib        Library which the warning occured in.
  * @param   pszFormat   Message format.
@@ -2569,5 +2875,18 @@
 
 
-
+/**
+ * Reads an ELF module from a file.
+ *
+ * @returns 0 on success.
+ * @returns non zero on failure.
+ * @param   pWld        Pointer to linker instance.
+ * @param   pMod        Pointer to module
+ * @param   fLibSearch  Set if we're doing library search at this time.
+ */
+static unsigned     pass1ReadELFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch)
+{
+    /** @todo implement me. */
+    return 0;
+}
 
 
@@ -2687,4 +3006,46 @@
 
 /**
+ * Checks if the ELF header is valid.
+ *
+ * @returns 1 if it is, 0 if it isn't.
+ * @param   pEhdr   The ELF header.
+ * @param   pszName The file name to use when reporting errors.
+ */
+static int wldIsValidElfHdr(Elf32_Ehdr const *pEhdr, const char *pszName)
+{
+    if (!IS_ELF(*pEhdr))
+        fprintf(stderr, "weakld: '%s': not ELF file..\n", pszName);
+    else if (   pEhdr->e_ident[EI_CLASS] != ELFCLASS32
+             && pEhdr->e_ident[EI_CLASS] != ELFCLASSNONE)
+        fprintf(stderr, "weakld: '%s': wrong ELF class.\n", pszName);
+    else if (   pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
+             && pEhdr->e_ident[EI_DATA] != ELFDATANONE)
+        fprintf(stderr, "weakld: '%s': wrong ELF endian.\n", pszName);
+    else if (pEhdr->e_ident[EI_VERSION] != EV_CURRENT)
+        fprintf(stderr, "weakld: '%s': wrong ELF version.\n", pszName);
+    /* Ignore EI_OSABI, EI_ABIVERSION and EI_PAD. */
+    else if (pEhdr->e_type != ET_REL)
+        fprintf(stderr, "weakld: '%s': not relocatable ELF file.\n", pszName);
+    else if (   pEhdr->e_machine != EM_386
+             && pEhdr->e_machine != EM_486)
+        fprintf(stderr, "weakld: '%s': not 386 or 486 ELF file.\n", pszName);
+    else if (pEhdr->e_version != EV_CURRENT)
+        fprintf(stderr, "weakld: '%s': wrong ELF version (#2).\n", pszName);
+    else if (pEhdr->e_ehsize != sizeof(*pEhdr))
+        fprintf(stderr, "weakld: '%s': wrong ELF header size.\n", pszName);
+    else if (pEhdr->e_phoff && pEhdr->e_phoff < sizeof(*pEhdr))
+        fprintf(stderr, "weakld: '%s': bad ELF program header offset.\n", pszName);
+    else if (pEhdr->e_shoff && pEhdr->e_shoff < sizeof(*pEhdr))
+        fprintf(stderr, "weakld: '%s': bad ELF section header offset.\n", pszName);
+    else if (pEhdr->e_phentsize != sizeof(Elf32_Phdr) && (pEhdr->e_phnum || pEhdr->e_phentsize))
+        fprintf(stderr, "weakld: '%s': wrong ELF program header size: %d\n", pszName, pEhdr->e_phentsize);
+    else if (pEhdr->e_shentsize != sizeof(Elf32_Shdr) && (pEhdr->e_shnum || pEhdr->e_shentsize))
+        fprintf(stderr, "weakld: '%s': wrong ELF section header size: %d\n", pszName, pEhdr->e_shentsize);
+    else
+        return 1;
+    return 0;
+}
+
+/**
  * Adds a object module to the linking process.
  * The object module will be analysed and the file handle closed.
@@ -2703,5 +3064,9 @@
 int     WLDAddObject(PWLD pWld, FILE *phFile, const char *pszName)
 {
-    OMFREC  OmfRec = {0,0};
+    union
+    {
+        OMFREC          OmfRec;
+        Elf32_Ehdr      Ehdr;
+    }       uBuf;
     int     rc = 0;
     if (!phFile)
@@ -2713,11 +3078,16 @@
     }
     WLDINFO(pWld, ("adding object %s.", pszName));
+    if (fread(&uBuf.OmfRec, sizeof(uBuf.OmfRec), 1, phFile) != 1)
+    {
+        fprintf(stderr, "weakld: error reading object file '%s'.\n", pszName);
+        fclose(phFile);
+        return -1;
+    }
 
     /*
-     * An object module is either a object or a library.
+     * An object module is either a object (OMF or ELF) or a library (OMF).
      * In anycase all the modules it contains is to be added to the link.
      */
-    fread(&OmfRec, sizeof(OmfRec), 1, phFile);
-    if (OmfRec.chType == THEADR)
+    if (uBuf.OmfRec.chType == THEADR)
     {
         /* Single Object */
@@ -2731,10 +3101,10 @@
         modClose(pMod);
     }
-    else if (OmfRec.chType == LIBHDR)
+    else if (uBuf.OmfRec.chType == LIBHDR)
     {
         /* Library of object modules */
-        while (OmfRec.chType != LIBEND && OmfRec.chType != (LIBEND | REC32))
-        {
-            if (OmfRec.chType == THEADR || OmfRec.chType == (THEADR | REC32))
+        while (uBuf.OmfRec.chType != LIBEND && uBuf.OmfRec.chType != (LIBEND | REC32))
+        {
+            if (uBuf.OmfRec.chType == THEADR || uBuf.OmfRec.chType == (THEADR | REC32))
             {
                 PWLDMOD     pMod = xmalloc(sizeof(*pMod));
@@ -2742,5 +3112,5 @@
                 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
                 pMod->phFile = phFile;
-                pMod->off = ftell(phFile) - sizeof(OmfRec);
+                pMod->off = ftell(phFile) - sizeof(uBuf.OmfRec);
                 *pWld->ppObjsAdd = pMod;
                 pWld->ppObjsAdd = &pMod->pNext;
@@ -2761,11 +3131,36 @@
             {
                 /* skip to the net record */
-                fseek(phFile, OmfRec.cb, SEEK_CUR);
+                fseek(phFile, uBuf.OmfRec.cb, SEEK_CUR);
             }
 
             /* read next record */
-            fread(&OmfRec, sizeof(OmfRec), 1, phFile);
+            fread(&uBuf.OmfRec, sizeof(uBuf.OmfRec), 1, phFile);
         }
         fclose(phFile);
+    }
+    else if (   uBuf.Ehdr.e_ident[EI_MAG0] == ELFMAG0
+             && uBuf.Ehdr.e_ident[EI_MAG1] == ELFMAG1
+             && uBuf.Ehdr.e_ident[EI_MAG2] == ELFMAG2
+             && fread((char *)&uBuf.Ehdr + sizeof(uBuf.OmfRec),
+                      sizeof(uBuf.Ehdr) - sizeof(uBuf.OmfRec), 1, phFile) == 1
+             && uBuf.Ehdr.e_ident[EI_MAG3] == ELFMAG3)
+    {
+        if (wldIsValidElfHdr(&uBuf.Ehdr, pszName))
+        {
+            /* Single Object */
+            PWLDMOD pMod = xmalloc(sizeof(*pMod));
+            memset(pMod, 0, sizeof(*pMod));
+            pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
+            pMod->phFile = phFile;
+            *pWld->ppObjsAdd = pMod;
+            pWld->ppObjsAdd = &pMod->pNext;
+            rc = pass1ReadELFMod(pWld, pMod, 0);
+            modClose(pMod);
+        }
+        else
+        {
+            fclose(phFile);
+            rc = -1;
+        }
     }
     else
@@ -2946,6 +3341,5 @@
 int     WLDAddLibrary(PWLD pWld, FILE *phFile, const char *pszName)
 {
-    PWLDLIB     pLib;
-    int         rc = 0;
+    PWLDLIB pLib;
 
     if (!phFile)
@@ -2965,16 +3359,48 @@
     pLib->pNext = NULL;
 
-    /* read the library header. */
+    /* read the library header, detect the format. */
     if (    !fseek(phFile, 0, SEEK_SET)
-        &&  fread(&pLib->LibHdr, sizeof(OMFREC), 1, phFile) == 1
-        &&  (   pLib->LibHdr.chType != LIBHDR
-             || fread(&pLib->LibHdr.offDict, sizeof(pLib->LibHdr) - sizeof(OMFREC), 1, phFile) == 1
-                )
-        )
-    {
-        /* link it in */
-        *pWld->ppLibsAdd = pLib;
-        pWld->ppLibsAdd = &pLib->pNext;
-        libClose(pLib);
+        &&  fread(&pLib->u.Omf.LibHdr, sizeof(OMFREC), 1, phFile) == 1)
+    {
+        int rc; 
+        if (pLib->u.Omf.LibHdr.chType == LIBHDR)
+        {
+            pLib->fOmfLib = 1;
+            if (fread(&pLib->u.Omf.LibHdr.offDict, sizeof(pLib->u.Omf.LibHdr) - sizeof(OMFREC), 1, phFile) == 1)
+                rc = 0;
+            else
+                rc = libErr(pLib, "Failed reading OMF library header.");
+        }
+        else if (pLib->u.Omf.LibHdr.chType == THEADR)
+            pLib->fOmfLib = 1;
+        else if (!memcmp(&pLib->u.Omf.LibHdr, ARMAG, sizeof(OMFREC)))
+        {
+            char achMagic[SARMAG];
+            if (fread(achMagic, SARMAG - sizeof(OMFREC), 1, phFile) == 1)
+            {
+                if (!memcmp(achMagic, ARMAG + sizeof(OMFREC), SARMAG - sizeof(OMFREC)))
+                {
+                    pLib->fOmfLib = 0;
+                    pLib->u.Ar.uDummy = 0;
+                    rc = 0;
+                }
+                else
+                    rc = libErr(pLib, "Invalid library format.");
+            }
+            else
+                rc = libErr(pLib, "Failed reading AR library magic.");
+        }
+        else
+            rc = libErr(pLib, "Invalid library format.");
+
+        if (rc == 0)
+        {
+            /* link it in */
+            *pWld->ppLibsAdd = pLib;
+            pWld->ppLibsAdd = &pLib->pNext;
+            libClose(pLib);
+
+            return 0;
+        }
     }
     else
@@ -2982,10 +3408,9 @@
         /* We failed. */
         libErr(pLib, "Invalid library format or read error.");
-        fclose(phFile);
-        free(pLib);
-        rc = -1;
-    }
-
-    return rc;
+    }
+    
+    fclose(phFile);
+    free(pLib);
+    return  -1;
 }
 
@@ -3612,5 +4037,5 @@
     pid_t           pid = getpid();
     static char     s_szTmp[_MAX_PATH + 1];
-    
+
     /* We need to apply _realrealpath to the tmpdir, so resolve that once and for all. */
     if (!s_szTmp[0])
