Ignore:
Timestamp:
Sep 18, 2010, 3:06:59 AM (15 years ago)
Author:
bird
Message:

emxomfld/weakld: working on AR and ELF support.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/emx/src/emxomf/emxomfld.c

    r3462 r3667  
    3737#include <alloca.h>
    3838#include <sys/omflib.h>
     39#include <sys/elf.h>
     40#include <ar.h>
    3941#include "defs.h"
    4042#include "weakld.h"
     
    5153} name_list;
    5254
     55/* OMF record header. */
     56#pragma pack(1)
     57typedef struct omf_rec_hdr
     58{
     59    byte type;
     60    word len;
     61} omf_rec_hdr;
     62#pragma pack()
    5363
    5464/* Whether or not linker tracing is enabled. */
     
    504514
    505515/**
     516 * Reports archive parsing error.
     517 * @returns 0.
     518 * @param   pszError    The parsing error.
     519 */
     520static int bad_arch(const char *pszError)
     521{
     522    fprintf(stderr, "emxomfld: failed parsing archive: %s\n", pszError);
     523    return 0;
     524}
     525
     526/**
     527 * Validates a numeric ar_hdr field.
     528 *
     529 * These are supposed to be padded with spaces, however, emximp seems to be
     530 * using null terminators as well (ar_mode for instance).
     531 *
     532 * @returns 1 if valid, 0 if invalid.
     533 * @param   pachField       The field.
     534 * @param   cchField        The field length.
     535 * @param   uBase           10 for decimal, 8 for octal.
     536 * @param   pszName         The field name.
     537 */
     538static int is_arch_num_field_valid(char const *pachField, size_t cchField, unsigned uBase, const char *pszName)
     539{
     540    while (cchField > 0)
     541    {
     542        unsigned ch = *pachField;
     543        if (ch - '0' >= uBase)
     544        {
     545            if (ch == ' ' || !ch)
     546                break;
     547            return bad_arch(pszName);
     548        }
     549        cchField--;
     550        pachField++;
     551    }
     552
     553    while (cchField > 0)
     554    {
     555        char ch = *pachField;
     556        if (ch != ' ' && ch)
     557            return bad_arch(pszName);
     558        cchField--;
     559        pachField++;
     560    }
     561   
     562    return 1;
     563}
     564
     565/**
     566 * Checks the name field to see if there is a BSD style variable sized name
     567 * field following the header.
     568 
     569 * @returns 0 if none, length if something.
     570 * @param   pArHdr          The archive header.
     571 */
     572static unsigned arch_hdr_get_ext_name_len(struct ar_hdr *pArHdr)
     573{
     574    unsigned cchExtName = 0;
     575    if (!memcmp(&pArHdr->ar_name[0], AR_EFMT1, sizeof(AR_EFMT1) - 1))
     576    {
     577        int         cch = sizeof(pArHdr->ar_name) - sizeof(AR_EFMT1) - 1;
     578        const char *pch = &pArHdr->ar_name[sizeof(AR_EFMT1) - 1];
     579        while (cch-- > 0)
     580        {
     581            unsigned uDig = (unsigned char)*pch++ - '0';
     582            if (uDig > 10)
     583                break;
     584            cchExtName *= 10;
     585            cchExtName += uDig;
     586        }
     587    }
     588    return cchExtName;
     589}
     590
     591/**
     592 * Converts the size field of the header into something we can use.
     593 * @returns ar_size as off_t.
     594 * @param   pArHdr          The archive header.
     595 */
     596static off_t arch_hdr_get_size(struct ar_hdr *pArHdr)
     597{
     598    off_t       cb  = 0;
     599    int         cch = sizeof(pArHdr->ar_size);
     600    const char *pch = &pArHdr->ar_size[0];
     601    while (cch-- > 0)
     602    {
     603        unsigned uDig = (unsigned char)*pch++ - '0';
     604        if (uDig > 10)
     605            break;
     606        cb *= 10;
     607        cb += uDig;
     608    }
     609    return cb;
     610}
     611
     612/**
     613 * Matches @a pszName with the name in the archive header.
     614 *
     615 * @returns 1 if matches, 0 if not.
     616 * @param   pArHdr          The archive header.
     617 * @param   pszName         The name to match it with.
     618 */
     619static int arch_hdr_match_name(struct ar_hdr *pArHdr, const char *pszName)
     620{
     621    size_t      cch = sizeof(pArHdr->ar_name);
     622    const char *pch = &pArHdr->ar_name[0];
     623    while (cch > 0)
     624    {
     625        if (*pszName != *pch)
     626        {
     627            if (*pszName)
     628                return 0;
     629            break;
     630        }
     631        cch--;
     632        pszName++;
     633        pch++;
     634    }
     635   
     636    while (cch-- > 0)
     637    {
     638        char ch = *pch++;
     639        if (ch != ' ' && ch)
     640            return 0;
     641    }
     642   
     643    return 1;
     644}
     645
     646/**
     647 * Checks if the stream @a pFile is an archive only containing ELF and OMF
     648 * files.
     649 *
     650 * @returns 1 if so, 0 if not.
     651 * @param   pFile   The file stream to check.  The caller rewinds the stream.
     652 */
     653static int check_arch_library_with_omf_and_or_elf(FILE *pFile)
     654{
     655    union
     656    {
     657        char            achMagic[SARMAG];
     658        struct ar_hdr   ArHdr;
     659        Elf32_Ehdr      Elfhdr;
     660        omf_rec_hdr     OmfHdr;
     661        /*struct exec     AoutHdr;*/
     662    } uBuf;
     663    off_t offArchive;
     664
     665    /*
     666     * Read+reverify the magic.
     667     */
     668    if (fread(&uBuf.achMagic[0], SARMAG, 1, pFile) != 1)
     669        return 0;
     670    if (memcmp(&uBuf.achMagic[0], ARMAG, SARMAG) != 0)
     671        return 0;
     672
     673    /*
     674     * Process the archive, file by file.
     675     */
     676    offArchive = SARMAG;
     677    while (!feof(pFile))
     678    {
     679        off_t   cbFile;
     680        off_t   offNext;
     681        size_t  cbRead;
     682        int     cchExtraName;
     683
     684        /* read + verify the archive header */
     685        cbRead = fread(&uBuf.ArHdr, 1, sizeof(uBuf.ArHdr), pFile);
     686        if (cbRead != sizeof(uBuf.ArHdr))
     687            return cbRead == 0 && feof(pFile) ? 1 : bad_arch("fread");
     688        offArchive += sizeof(uBuf.ArHdr);
     689
     690        if (memcmp(uBuf.ArHdr.ar_fmag, ARFMAG, sizeof(uBuf.ArHdr.ar_fmag)))
     691            return bad_arch("ar_fmag");
     692        if (   !is_arch_num_field_valid(uBuf.ArHdr.ar_date, sizeof(uBuf.ArHdr.ar_date), 10, "ar_date")
     693            || !is_arch_num_field_valid(uBuf.ArHdr.ar_uid,  sizeof(uBuf.ArHdr.ar_uid),  10, "ar_uid")
     694            || !is_arch_num_field_valid(uBuf.ArHdr.ar_gid,  sizeof(uBuf.ArHdr.ar_gid),  10, "ar_gid")
     695            || !is_arch_num_field_valid(uBuf.ArHdr.ar_mode, sizeof(uBuf.ArHdr.ar_mode),  8, "ar_mode")
     696            || !is_arch_num_field_valid(uBuf.ArHdr.ar_size, sizeof(uBuf.ArHdr.ar_size), 10, "ar_size") )
     697            return 0; /* bitched already */
     698       
     699        cbFile  = arch_hdr_get_size(&uBuf.ArHdr);
     700        offNext = offArchive + cbFile;
     701        offNext += offNext & 1;         /* make even */
     702
     703        /* skip the extended name field if present (BSD). */
     704        cchExtraName = arch_hdr_get_ext_name_len(&uBuf.ArHdr);
     705        /*fprintf(stderr, "%#06x '%.16s' offNext=%#x cb=%#x ext=%d\n", (unsigned)offArchive, &uBuf.ArHdr.ar_name[0], (unsigned)offNext, (unsigned)cbFile, cchExtraName);*/
     706        if (cchExtraName)
     707        {
     708            cbFile     -= cchExtraName;
     709            offArchive += cchExtraName;
     710            if (fseek(pFile, offArchive, SEEK_SET))
     711                return bad_arch("fseek-ext-name");
     712        }
     713
     714        /* ignore the archive symbol table. */
     715        if (   !arch_hdr_match_name(&uBuf.ArHdr, "__.SYMDEF")
     716            && !arch_hdr_match_name(&uBuf.ArHdr, "/")
     717            && !arch_hdr_match_name(&uBuf.ArHdr, "ARFILENAMES/")
     718            && !arch_hdr_match_name(&uBuf.ArHdr, "//"))
     719        {           
     720            cbRead = sizeof(uBuf);
     721            if (cbRead > cbFile)
     722            {
     723                cbRead = cbFile;
     724                memset(&uBuf, 0, sizeof(uBuf));
     725            }
     726            if (fread(&uBuf, 1, cbRead, pFile) != cbRead)
     727                return bad_arch("fread-member-hdr");
     728
     729            if (   (   uBuf.OmfHdr.len >= sizeof(uBuf.OmfHdr)
     730                    && cbRead > sizeof(sizeof(uBuf.OmfHdr)) )
     731                    && (   uBuf.OmfHdr.type == THEADR
     732                        /*|| uBuf.OmfHdr.type == LIBADR - doubt wlink can handle this */)
     733                || IS_ELF(uBuf.Elfhdr) )
     734            {
     735                /* nothing */
     736                /*fprintf(stderr, IS_ELF(uBuf.Elfhdr) ? "ELF\n" : "OMF\n");*/
     737            }
     738            else
     739            {
     740                /*fprintf(stderr, "not omf or elf\n");*/
     741                return 0;
     742            }
     743        }
     744        /*else
     745            fprintf(stderr, "skip archive symbol table\n");*/
     746       
     747        /* advance to the next file */
     748        if (fseek(pFile, offNext, SEEK_SET))
     749            return bad_arch("fseek-next");
     750        offArchive = offNext;
     751    }
     752
     753    return 1;           
     754}
     755
     756/**
    506757 * Checks if the stream phFile is an OMF library.
    507758 *
     
    546797 * @param   phFile  Filestream to check.
    547798 */
    548 static int check_omf(FILE *phFile)
     799static int check_omf_or_elf(FILE *phFile)
    549800{
    550801#pragma pack(1)
    551     struct
    552     {
    553         byte rec_type;
    554         word rec_len;
    555     } omfhdr;
     802    union
     803    {
     804        struct
     805        {
     806            byte rec_type;
     807            word rec_len;
     808        }    omfhdr;
     809        byte elfmagic[4];
     810        char arch[7];
     811    } u;
    556812#pragma pack()
    557     if (    fread(&omfhdr, 1, sizeof(omfhdr), phFile) == sizeof (omfhdr)
    558         &&  omfhdr.rec_type == THEADR
    559         &&  omfhdr.rec_len >= sizeof(omfhdr)
    560         &&  !fseek(phFile, 0, SEEK_SET)
    561        )
     813    size_t cbRead = fread(&u.omfhdr, 1, sizeof(u), phFile);
     814    if (fseek(phFile, 0, SEEK_SET))
     815        return 0;
     816
     817    /* OMF object or library? */
     818    if (   cbRead >= sizeof(u.omfhdr)   
     819        && u.omfhdr.rec_type == THEADR
     820        && u.omfhdr.rec_len >= sizeof(u.omfhdr) )
    562821        return 1;
    563 
    564     return !fseek(phFile, 0, SEEK_SET)
    565         && check_omf_library(phFile);
     822    if (   cbRead >= sizeof(u.omfhdr)
     823        && u.omfhdr.rec_type == LIBHDR)
     824        return check_omf_library(phFile);
     825   
     826    /* ELF object? */
     827    if (   u.elfmagic[0] == ELFMAG0
     828        && u.elfmagic[1] == ELFMAG1
     829        && u.elfmagic[2] == ELFMAG2
     830        && u.elfmagic[3] == ELFMAG3)
     831        return 1;
     832
     833    /* AR archive with OMF and/or ELF content? */
     834    if (   cbRead >= sizeof("!<arch>") - 1
     835        && !memcmp(u.arch, "!<arch>", sizeof(u.arch)))
     836    {
     837        int rc = check_arch_library_with_omf_and_or_elf(phFile);
     838        if (fseek(phFile, 0, SEEK_SET))
     839            rc = 0;
     840        return rc;
     841    }
     842
     843    /* Not anything we know */
     844    return 0;
    566845}
    567846
     
    637916
    638917    /* We need to apply _realrealpath to the tmpdir, so resolve that once and for all. */
    639     if (!s_szTmp[0]) 
     918    if (!s_szTmp[0])
    640919    {
    641920        const char *    pszTmp = getenv("TMP");
     
    8631142     */
    8641143    if (    autoconvert_flag
    865         &&  !check_omf(phFile))
     1144        &&  !check_omf_or_elf(phFile))
    8661145        phFile = aout_to_omf(phFile, pszFullname, FALSE);
    8671146
     
    10061285                        if (check_lx_dll(phFile))
    10071286                            phFile = lx_to_omf(phFile, pszFullname);
    1008                         else if (!check_omf(phFile))
     1287                        else if (!check_omf_or_elf(phFile))
    10091288                            phFile = aout_to_omf(phFile, pszFullname, TRUE);
    10101289                    }
     
    13671646      case _MD_STUB:
    13681647        if (!stmt->stub.none)
    1369           fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
     1648          {
     1649            fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
     1650            *(int*)(arg) = 0; /*need_stub*/
     1651          }
    13701652        else
    13711653          fprintf (stderr, "emxomfld: warning: \"STUB NONE\" is not supported by wlink. ignoring\n");
     
    20852367    {
    20862368      unsigned uPMType = 0;
     2369      int need_stub = 1;
    20872370
    20882371      open_response_file ();
     
    22752558        fprintf (response_file, "OPTION OFFSET=%s\n", base);
    22762559
    2277       /* the stub */
    2278 
    2279       _execname(&execname[0], sizeof(execname));
    2280       strcpy (_getname (&execname[0]), "os2stub.bin");
    2281       if (!stat (execname, &s))
    2282         fprintf (response_file, "OPTION STUB='%s'\n", execname);
    2283 
    22842560      /* Add the /INFORMATION option if the -i or -t option was given.  This is
    22852561         for debugging. */
     
    23052581
    23062582      /* Translate the essentials of the module definition file into wlink lingo. */
     2583     
    23072584      if (def_fname)
    23082585        {
     
    23142591            }
    23152592          _md_next_token (pMd);
    2316           _md_parse (pMd, def_2_watcom, NULL);
     2593          _md_parse (pMd, def_2_watcom, &need_stub);
    23172594          _md_close (pMd);
    23182595        }
     2596     
     2597      /* the stub */
     2598
     2599      if (need_stub)
     2600        {
     2601          _execname(&execname[0], sizeof(execname));
     2602          strcpy (_getname (&execname[0]), "os2stub.bin");
     2603          if (!stat (execname, &s))
     2604            fprintf (response_file, "OPTION STUB='%s'\n", execname);
     2605        }
     2606
    23192607    }
    23202608
Note: See TracChangeset for help on using the changeset viewer.