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 + -
显示快捷键?