reloc.c

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

C
498
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <string.h>
#include "linkstd.h"
#include "alloc.h"
#include "reloc.h"
#include "fileio.h"
#include "spillio.h"
#include "loadfile.h"
#include "overlays.h"

typedef union {
    unsigned long   spill;
    void *          addr;
} spilladdr;

/* note: if either of these two structures get any bigger, the magic constants
 * in the RLIDX_* macros will have to change to ensure that no allocation > 64k
 * occurs. */

typedef struct reloc_info {
    struct reloc_info * next;
    unsigned            sizeleft;
    spilladdr           loc;
} reloc_info;

typedef struct os2_reloc_header {
    reloc_info *        externals; /* external and segment style fixups */
    reloc_info *        internals; /* internal, non-segment fixups */
} os2_reloc_header;

#define RELOC_PAGE_SIZE 512
#define RELOC_SPILLED   0x8000
#define SIZELEFT_MASK   0x7FFF

unsigned        FmtRelocSize;
reloc_info  *   FloatFixups;

extern void ResetReloc( void )
/****************************/
{
    FloatFixups = NULL;
}

static reloc_info * AllocRelocInfo( void )
/****************************************/
/* allocate a relocation information block */
{
    reloc_info *    info;

    _PermAlloc( info, sizeof( reloc_info ) );       /* allocate more */
    info->sizeleft = RELOC_PAGE_SIZE;
    _LnkAlloc( info->loc.addr, RELOC_PAGE_SIZE );
    if( info->loc.addr == NULL ) {
        info->loc.spill = SpillAlloc( RELOC_PAGE_SIZE );
        info->sizeleft |= RELOC_SPILLED;
    }
    return( info );
}

static void * OS2PagedRelocInit( offset size, int unitsize )
/***************************************************************/
/* For some OS/2 formats we have to split up the structure off the grp_relocs
 * field up into small bits to ensure that we don't get structure allocations
 * > 64K. This is stored basically as a 2-d array */
{
    void **     mem;
    void **     start;
    offset      pageidx;
    offset      idxhigh;
    unsigned    idxlow;
    unsigned    allocsize;

    pageidx = OSF_PAGE_COUNT( size );
    idxhigh = OSF_RLIDX_HIGH( pageidx );
    _PermAlloc( mem, ( idxhigh + 1 ) * sizeof( void * ) );
    start = mem;
    allocsize = OSF_RLIDX_MAX * unitsize;
    while( idxhigh > 0 ) {
        _ChkAlloc( *mem, allocsize );
        memset( *mem, 0, allocsize );
        mem++;
        idxhigh--;
    }
    idxlow = OSF_RLIDX_LOW( pageidx );
    if( idxlow != 0 ) {
        allocsize = idxlow * unitsize;
        _ChkAlloc( *mem, allocsize );
        memset( *mem, 0, allocsize );
    }
    return( start );
}

static void * OS2FlatRelocInit( offset size )
/*******************************************/
/* initialize relocations for OS2 flat memory manager. */
{
    return( OS2PagedRelocInit( size, sizeof( os2_reloc_header ) ) );
}

static void * PERelocInit( offset size )
/**************************************/
/* initialize relocations for PE executable format */
{
    return( OS2PagedRelocInit( size, sizeof( reloc_info * ) ) );
}

static void DoWriteReloc( reloc_info **list, void *reloc, unsigned size )
/***********************************************************************/
{
    reloc_info *    info;
    unsigned        offset;

    info = *list;
    if( info == NULL ) {
        info = AllocRelocInfo();
        info->next = NULL;
        *list = info;
    }
    if( ( info->sizeleft & SIZELEFT_MASK ) < size ) {     /* if no space */
        info = AllocRelocInfo();
        info->next = *list;
        *list = info;
    }
    offset = RELOC_PAGE_SIZE - ( info->sizeleft & SIZELEFT_MASK );
    if( info->sizeleft & RELOC_SPILLED ) {
        SpillWrite( info->loc.spill, offset, reloc, size );
    } else {
        memcpy( (char *)( info->loc.addr ) + offset, reloc, size );
    }
    info->sizeleft -= size;
}

extern void WriteReloc( group_entry *group, offset off, void *reloc,
                        unsigned size )
/******************************************************************/
/* write the given relocation to virtual memory */
{
    os2_reloc_header ** pagelist;
    reloc_info ***      reloclist;
    reloc_info **       header;
    unsigned_32         idx;

    if( FmtData.type & MK_PE ) {
        reloclist = group->g.grp_relocs;
        if( reloclist == NULL ) {
           reloclist = PERelocInit( group->totalsize );
           group->g.grp_relocs = reloclist;
        }
        idx = ( off - group->grp_addr.off ) >> OSF_PAGE_SHIFT;
        header = &reloclist[OSF_RLIDX_HIGH( idx )][OSF_RLIDX_LOW( idx )];
        DoWriteReloc( header, reloc, size );
    } else if( FmtData.type & MK_OS2_FLAT ) {
        pagelist = group->g.grp_relocs;
        if( pagelist == NULL ) {
            pagelist = OS2FlatRelocInit( group->totalsize );
            group->g.grp_relocs = pagelist;
        }
        idx = ( off - group->grp_addr.off ) >> OSF_PAGE_SHIFT;
        header = &pagelist[OSF_RLIDX_HIGH( idx )][OSF_RLIDX_LOW( idx )].externals;
        switch( ((os2_flat_reloc_item *)reloc)->fmt.nr_flags & OSF_TARGET_MASK )  {
        case INTERNAL_REFERENCE:
            switch( ((os2_flat_reloc_item *)reloc)->fmt.nr_stype ) {
            case OFFSET_ONLY:
            case OFFSET48_ONLY:
            case OFFSET48_RELATIVE:
                //NYI: don't have to write this out if we can figure out
                // how to tell the loader that we're doing it.
                header =
                   &pagelist[OSF_RLIDX_HIGH( idx )][OSF_RLIDX_LOW( idx )].internals;
                break;
            }
            break;
        }
        DoWriteReloc( header, reloc, size );
    } else if( FmtData.type & ( MK_OS2_16BIT | MK_ELF ) ) {
        DoWriteReloc( &group->g.grp_relocs, reloc, size );
    } else {
        DoWriteReloc( &group->section->reloclist, reloc, size );
    }
    group->section->relocs++;
}

#ifdef _QNXLOAD
extern void FloatReloc( reloc_item * item )
/****************************************/
{
    DoWriteReloc( &FloatFixups, item, sizeof( qnx_reloc_item ) );
}

extern void QNXLinearReloc( group_entry * group, reloc_item * item )
/******************************************************************/
{
    DoWriteReloc( &group->g.grp_relocs, item, sizeof( qnx_linear_item ) );
}
#endif

static bool FreeRelocList( reloc_info * list )
/********************************************/
/* free any reloc blocks pointed to by list */
{
    while( list != NULL ) {
        if( !( list->sizeleft & RELOC_SPILLED ) ) {
            _LnkFree( list->loc.addr );
        }
        list = list->next;
    }
    return( FALSE );  /* needed for OS2 generic traversal routines */
}

static void FreeRelocSect( section *sect )
/****************************************/
{
    FreeRelocList( sect->reloclist );
}

static bool TraverseRelocBlock( reloc_info ** reloclist, unsigned num,
                                bool (*fn)( reloc_info * ) )
/********************************************************************/

⌨️ 快捷键说明

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