exe2bin.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 485 行 · 第 1/2 页

C
485
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  DOS EXE to binary conversion utility.
*
****************************************************************************/


// this small utility just strips off the header of a dos-type exe-file and
// performs any necessary relocations. if there are embedded relocations an
// additional command-line argument "-l=seg" is mandatory, indicating the
// address the image is supposed to be loaded at.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "watcom.h"             // unsigned_16, ..., endian-macros, ...
#include "exedos.h"             // dos_exe_header, ...
#include "banner.h"             // Watcom banner


#define BUF_SIZE  0x1000        // buffer size for file-ops (has to be >1)

#define ERR_NONE    0x00        // error-types used by parse_cmdline,
#define ERR_USAGE   0x01        // copy_bindata
#define ERR_RESTRIC 0x02
#define ERR_ALLOC   0x03
#define ERR_READ    0x04
#define ERR_WRITE   0x05


typedef struct reloc_table {
    unsigned_16     num;        // number of relocations in reloc-table
    unsigned_16     lseg;       // load-address of exe-program (segment)
    unsigned_32     reloc[];    // array  of relocations in reloc-table
} reloc_table;


typedef struct reloc_offset {   // a single reloc-entry as found in an exe
    unsigned_16     offset;
    unsigned_16     segment;
} reloc_offset;


typedef struct arguments {
    FILE            *ifile;
    FILE            *ofile;
    struct {
        unsigned        be_ext   : 1;       // option 'x'
        unsigned        be_quiet : 1;       // option 'q'
        unsigned        disp_h   : 1;       // option 'h'
        unsigned        disp_r   : 1;       // option 'r'
        unsigned        have_l   : 1;       // option 'l'
        unsigned_16     lseg;               // arg to 'l'
    }               opt;
    char            iname[_MAX_PATH];
    char            oname[_MAX_PATH];
} arguments;


// skip over istream's header and copy the binary-data (i.e. everything but
// the header) to ostream. while doing so, apply any relocations

int copy_bindata( FILE *istream, FILE *ostream, unsigned_32 bin_size,
                  unsigned_32 num_skip, reloc_table *reltab )
{

    unsigned_16     addr;               // orig. addr of bin_data to patch
    unsigned_8      *buffer;            // buffer of len BUF_SIZE for file-i/o
    unsigned_8      *bptr;              // ptr into buffer to (part of) reloc
    unsigned_16     carry;              // carry from lo-part; 0x0100 or 0x0000
    unsigned_16     cur_reloc;          // idx of current reloc to deal with
    unsigned_16     num_read;           // bytes to read; in (0, BUF_SIZE]
    unsigned_32     tot_read;           // total bytes read so far

    if( fseek( istream, num_skip, SEEK_SET ) ) {
        return( ERR_READ );
    }

    if( !( buffer = malloc( BUF_SIZE ) ) ) {
        return( ERR_ALLOC );
    }

    tot_read  = 0;
    cur_reloc = 0;
    carry     = 0;

    while( bin_size ) {
        num_read  = (bin_size > BUF_SIZE) ? BUF_SIZE : bin_size;

        if( !fread( buffer, num_read, 1, istream ) ) {
            free( buffer );
            return( ERR_READ );
        }

        // the application of relocations is a bit tricky, cause we read the
        // binary data in chunks of BUF_SIZE bytes; i.e. it is possible that
        // the reloc-addend (the load segment) has to be applied in two parts,
        // first the "lo"-part at the last byte of one buffer (actually a
        // window into istream), then the "hi"-part at the beginning of the
        // next window. In this case the x86 little-endian architecture comes
        // in very handy: We do the addition of the lower 8 bits, keep the
        // possible carry, write the buffer, fill the buffer with the next
        // data and add the upper 8 bits, taking care of the carry.

        if( cur_reloc < reltab->num ) {             // still relocs to apply?

            // is there a "hi"-part of a reloc to apply?
            if( reltab->reloc[cur_reloc] == tot_read - 1 ) {
                bptr  = buffer;
                addr  = *bptr << 8;
                addr += (reltab->lseg & 0xFF00) +  carry;
                *bptr = (unsigned_8)((addr & 0xFF00) >> 8);

                cur_reloc++;
            }

            // apply all relocs fitting in the buffer as a whole
            while( cur_reloc < reltab->num
                   && reltab->reloc[cur_reloc] < tot_read + BUF_SIZE - 1 ) {
                bptr  = buffer + reltab->reloc[cur_reloc] - tot_read;
                addr  = GET_LE_16( *((unsigned_16 *)bptr) );
                addr += reltab->lseg;
                *((unsigned_16 *)bptr) = GET_LE_16( addr );

                cur_reloc++;
            }

            // is there a "lo"-part of a reloc to apply?
            if( cur_reloc < reltab->num
                && reltab->reloc[cur_reloc] == tot_read + BUF_SIZE - 1 ) {
                bptr  = buffer + BUF_SIZE - 1;
                addr  = *bptr;
                addr += (reltab->lseg & 0x00FF);
                *bptr = (unsigned_8)(addr & 0x00FF);

                carry = (addr & 0xFF00) ? 0x0100 : 0x0000;
            }
        }

        if( !fwrite( buffer, num_read, 1, ostream ) ) {
            free( buffer );
            return( ERR_WRITE );
        }

        tot_read += num_read;
        bin_size -= num_read;
    }

    free( buffer );

    return( ERR_NONE );
}


// display the passed exe-header to stdout

void disp_header( dos_exe_header *header )
{
    printf( "Signature                      %04X\n",   header->signature    );
    printf( "Size mod 512       (bytes)     %04X\n",   header->mod_size     );
    printf( "Number of pages                %04X\n",   header->file_size    );
    printf( "Number of relocations          %04X\n",   header->num_relocs   );
    printf( "Size of header     (paras)     %04X\n",   header->hdr_size     );
    printf( "Minimum allocation (paras)     %04X\n",   header->min_16       );
    printf( "Maximum allocation (paras)     %04X\n",   header->max_16       );
    printf( "Initial ss:sp             %04X:%04X\n",   header->SS_offset,
                                                       header->SP );
    printf( "Checksum                       %04X\n",   header->chk_sum      );
    printf( "Initial cs:ip             %04X:%04X\n",   header->CS_offset,
                                                       header->IP );
    printf( "Relocation-table at            %04X\n",   header->reloc_offset );
    printf( "Overlay number                 %04X\n\n", header->overlay_num  );
}


// display the passed relocation-table to stdout

void disp_reltab( reloc_table *reltab )
{
    int i;

    printf( "There are " );
    reltab->num ? printf( "%u", reltab->num ) : printf( "no" );
    printf( " relocations in the exe-file." );

    for( i = 0; i < reltab->num; i++ ) {
        if( i % 6 == 0 ) {
            printf( "\n" );
        }
        printf( "0x%08X  ", reltab->reloc[i] );
    }
    printf( "\n" );
}


// allocate an exe-header for stream and convert the header-entries to match
// the local endianess. the caller owns the returned memory.

dos_exe_header *get_header( FILE *stream )
{
    unsigned_16     *hdr_val;
    dos_exe_header  *header;
    int             i;

    header = malloc( sizeof( dos_exe_header ) );
    if( header ) {
        if( !fread( header, sizeof( dos_exe_header ), 1, stream ) ) {
            free( header );
            header = NULL;
        } else {
            // this is really crude, cause we assume the exe-header consists
            // solely of packed, unsigned_16's; otoh it does, and this will
            // not change in the future ...
            hdr_val = (unsigned_16 *)header;
            for( i = 0; i < ( sizeof( dos_exe_header ) >> 1 ); i++ ) {
                CONV_LE_16( *hdr_val );
                hdr_val++;
            }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?