loadraw.c

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

C
396
字号
/****************************************************************************
*
*                            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:  Functions for creating binary and hex load files.
*
****************************************************************************/


#include <string.h>
#include <stdio.h>
#include "linkstd.h"
#include "ring.h"
#include "pcobj.h"
#include "newmem.h"
#include "msg.h"
#include "alloc.h"
#include "wlnkmsg.h"
#include "virtmem.h"
#include "fileio.h"
#include "objcalc.h"
#include "dbgall.h"
#include "loadraw.h"
#include "loadfile.h"


static bool WriteBinSegGroup( group_entry *group )
/*********************************************/
/* write the data for group to the loadfile */
/* returns TRUE if the file should be repositioned */
{
    unsigned_32         loc;
    signed_32           diff;
    section             *sect;
    bool                repos;
    outfilelist         *finfo;

    repos = FALSE;
    if( group->size != 0 || group->leaders->class->flags & CLASS_COPY ) {
        sect = group->section;
        CurrSect = sect;
        finfo = sect->outfile;
        loc = SUB_ADDR( group->grp_addr, sect->sect_addr ) + sect->u.file_loc;
        if ( (long)loc >= 0) {  // Offset may make this go negative for NOEMIT classes or segments
            diff = loc - finfo->file_loc;
            if( diff > 0 ) {
                PadLoad( diff );
            } else if( diff != 0 ) {
                SeekLoad( loc );
                repos = TRUE;
            }
            DEBUG((DBG_LOADDOS, "group %a section %d to %l in %s",
                &group->grp_addr, sect->ovl_num, loc, finfo->fname ));
            WriteGroupLoad( group );
            loc += group->size;
            if( loc > finfo->file_loc ) {
                finfo->file_loc = loc;
            }
        }
    }
    return repos;
}


extern void BinOutput( void )
/***************************/
{
    outfilelist         *fnode;
    group_entry         *group;
    bool                repos;
    unsigned_32         size;
    signed_32           diff;

    if( FmtData.type & (MK_PE | MK_QNX_FLAT | MK_OS2_FLAT | MK_ELF) ) {
        CurrSect = Root;        // needed for WriteInfo.
        Root->sect_addr = Groups->grp_addr;
        fnode = Root->outfile;
        fnode->file_loc = 0;
        Root->u.file_loc = Root->sect_addr.off - FmtData.output_offset;
        /* write groups */
        for( group = Groups; group != NULL; group = group->next_group ) {
            if (group->leaders->class->flags & CLASS_COPY ) {
               size = CalcGroupSize( group->leaders->class->DupClass->segs->group );
            }
            else {
                size = CalcGroupSize( group );
            }
            if( size ) {
                diff = (FmtData.base + group->grp_addr.off + group->linear 
                       - FmtData.output_offset) - PosLoad();
                if( diff < 0 ) {
                    LnkMsg( ERR + MSG_FIXED_LOC_BEFORE_CUR_LOC, "a", &(group->grp_addr));
                }
                else if( diff > 0 ) {
                   PadLoad( diff );
                }
                WriteGroupLoad( group );
            }
        }
    }
    else {
        OrderGroups( CompareDosSegments );
        CurrSect = Root;        // needed for WriteInfo.
        Root->sect_addr = Groups->grp_addr;
        fnode = Root->outfile;
        fnode->file_loc = 0;
        Root->u.file_loc = (Root->sect_addr.seg << FmtData.SegShift) + Root->sect_addr.off - FmtData.output_offset;
        /* write groups */
        for( group = Groups; group != NULL; group = group->next_group ) {
            repos = WriteBinSegGroup( group );
            if( repos ) {
                SeekLoad( fnode->file_loc );
            }
        }
    }
    WriteDBI();
}

// The following routine generates Intel Hex records using data buffered in LineBuf.
// A full record is 16 bytes of data.  Partial records are allowed when needed
// because of gaps in the loadfile data.  Initially segmented addressing is assumed
// with a starting segment value of 0 (Original 64K Intel Hex records).  If data
// is encountered above 64K, the routine outputs a segment record, seamlessly
// switching to segmented mode.  Segmented mode can use either the standard 4 bit
// shift (default) or the shift defined in FmtData.SegShift, or if set, the
// value in FmtData.HexSegShift, which is uniquely used by this function.  The
// purpose for this is that 24 bit addressing can be fully handled using segmented
// addressing (rather than extended linear addressing) if SegShift is 8.
// If data is encountered above what Segmented addressing can handle (1 M for default)
// the routine outputs an extended linear address record, seamlessly switching
// to a full 32 bit address range.  This approach provides full backward compatibility
// for systems which cannot read the newer formats when creating files that don't
// need the extra range.

#define HEXLEN 16   // number of bytes of data in a full record
static unsigned_32      nextAddr;
static unsigned_16      seg;
static bool             linear;
static char             lineBuf[HEXLEN];
static unsigned_32      bufOfs;

static void WriteHexLine( void )
/******************************/
{

    char            str_buf[2 * HEXLEN + 15];
    unsigned_16      checksum;
    unsigned_16      i;
    unsigned_16      seg_shift = FmtData.output_hshift ? FmtData.HexSegShift : FmtData.SegShift;
    unsigned_16      offset;

    if( nextAddr + bufOfs >= (0x10000L << seg_shift) && !linear ) {
        linear = 1;
        seg = 0;
    }

    if( !linear ) {
        if( nextAddr - (seg << seg_shift) + bufOfs > 0x10000L ) { // See if we need to output a segment record
            seg = (unsigned int)(nextAddr >> seg_shift);
            sprintf( str_buf, ":02000002%04x%02x\r\n", seg, (-(4 + (seg >> 8) + seg & 0xFF)) & 0xFF );
            WriteLoad( str_buf, 17 );
        }
        offset = (unsigned int)(nextAddr - (seg << seg_shift));
    }
    else {
        if( nextAddr - (seg << 16) + bufOfs > 0x10000L ) {  // See if we need to output
            seg = (unsigned int)(nextAddr >> 16);           //   an extended linear record
            sprintf( str_buf, ":02000004%04x%02x\r\n", seg, (-(6 + (seg >> 8) + seg & 0xFF)) & 0xFF );
            WriteLoad( str_buf, 17);
        }
        offset = (unsigned int)(nextAddr - (seg << 16));
    }

    sprintf( str_buf, ":%02x%04x00", bufOfs, offset );      // Intel Hex header
    checksum = bufOfs + (offset >> 8) + (offset & 0xFF);    // Start checksum using above elements

⌨️ 快捷键说明

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