write.c 7.67 KB
/*==============================================================================
    Module: write.c
    $Revision: 1.1.1.2 $
    $Date: 2002/10/29 08:07:15 $
    $Author: blythe $
    $Source: /root/leakn64/depot/rf/sw/n64os20l/tools/gcord/com/write.c,v $
==============================================================================*/
#include <libelf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>

#include "global.h"
#include "option.h"
#include "update.h"

/*------------------------------------------------------------------------------
    update the program entry point
------------------------------------------------------------------------------*/
void    update_elf_header(void)
{
    if(IS_32BIT())
	update_elf_header32();
    else
	update_elf_header64();
}

/*------------------------------------------------------------------------------
    update .dynamic section.
------------------------------------------------------------------------------*/
void update_dynamic(void)
{
    if(IS_32BIT())
	update_dynamic32();
    else
	update_dynamic64();
}

/*------------------------------------------------------------------------------
    update .got section
------------------------------------------------------------------------------*/
void update_got(void)
{
    if(IS_32BIT())
	update_got32();
    else
	update_got64();
}

/*------------------------------------------------------------------------------
    
------------------------------------------------------------------------------*/
void update_reldyn(void)
{
    if(IS_32BIT())
	update_reldyn32();
    else
	update_reldyn64();
}

/*------------------------------------------------------------------------------
    update .dynsym section.
------------------------------------------------------------------------------*/
void update_dynsym(void)
{
    if(IS_32BIT())
	update_dynsym32();
    else
	update_dynsym64();
}

/*------------------------------------------------------------------------------
    update .symtab section.
------------------------------------------------------------------------------*/
void update_symtab(void)
{
    if(IS_32BIT())
	update_symtab32();
    else
	update_symtab64();
}

/*------------------------------------------------------------------------------
    Expand .text section.
------------------------------------------------------------------------------*/
void expand_text(void)
{
    if(IS_32BIT())
	expand_text32();
    else
	expand_text64();
}

/*------------------------------------------------------------------------------
    1. Process events section.
    2. Update contents in events section.
------------------------------------------------------------------------------*/
void update_events(void)
{
}

/*------------------------------------------------------------------------------
        The runtime procedure table is used by ADA,
        COBOL and PL/1 for exception handling. This
        table is tacked on the end of the .data section
        and is pointed to by the symbols:
            _procedure_table        - table location
            _procedure_table_size   - number of table entries

        if the value of _procedure_table is zero,  the
        table will be in a non-loadable part of the object file
        (currently hidden not in a section) and its file offset
        is stored in the program header.
------------------------------------------------------------------------------*/
void update_rpt(void)
{
}

/*------------------------------------------------------------------------------
    Update addresses in jump instruction.
    This should only be needed for non-shared, as shared program should use
    jalr t9.
------------------------------------------------------------------------------*/
void update_jump(MIPS_Inst inst, Addr old_address)
{
    Addr    target;
    Addr    new_target;
    Addr    new_address;

    target = inst.j_format.target <<2;
    target |= (old_address + SIZE_INST) & 0xf0000000;
	/* TO_DO: target may jump over 1G byte range */
    if (IN_TEXT(target))
    {
        new_target = NEW_ADDR(target);
	new_address = NEW_ADDR(old_address);
        GET_NEWTEXT_BY_ADDR(new_address).j_format.target = new_target >> 2;
    }
    else if (IN_BROAD_TEXT(target) && target > bin.text_hi)
    {
	new_target = target + bin.text_expand_offset;
	new_address = NEW_ADDR(old_address);
        GET_NEWTEXT_BY_ADDR(new_address).j_format.target = new_target >> 2;
    }
    else
    {
	warning("jump target %#llx not in .text or .init", (Uint64) target);
    }
    if (option.debug)
        dump("jump at %#llx changed from %#llx to %#llx",
            (Uint64) old_address, (Uint64) target, (Uint64) new_target);
    return;
}

/*------------------------------------------------------------------------------
    Update the branch offset in branch instructions.
------------------------------------------------------------------------------*/
void update_one_branch(MIPS_Inst inst, Addr old_address)
{
    Addr	new_address;
    short 	offset;		/* branch offset */
    Sint32 	new_offset;
    Addr	target;		/* target address */
    Addr	new_target;		/* target address */

    new_address = NEW_ADDR(old_address);
    offset = inst.i_format.simmediate <<2;
    target = old_address + offset + SIZE_INST;
    new_target = NEW_ADDR(target);
    new_offset = (Sint32) (new_target - new_address - SIZE_INST) >>2;

    if(new_offset > 0x7fff || new_offset < -0x8000)
	error("branch new offset %#x out of range", new_offset);

    GET_NEWTEXT_BY_ADDR(new_address).i_format.simmediate = (short) new_offset;
}

/*------------------------------------------------------------------------------
    update branch/jump offset
    This looks at the old text and modifies the corresponding new instructions.
------------------------------------------------------------------------------*/
void update_branch_offset(void)
{
    int i;
    MIPS_Inst	inst;
    unsigned int * instructionAddress = (unsigned int *)bin.text_lo;

    if ( option.debug )
                printf( "updating jumps\n" );

    for(i = 0; i < bin.n_instructions; i++, ++instructionAddress)
    {
	/* Since we have mixed code and data, check for code here */

        if ( !get_proc_by_addr( instructionAddress ) )
                continue;       /* assume it is not code */

	inst = bin.text[i];

        switch (inst.i_format.opcode)
	{
            case j_op:
            case jal_op:
		update_jump(inst, bin.text_lo + i*SIZE_INST);
                break;
	    case spec_op:
		switch (inst.r_format.func) 
		{
        	    case jalr_op:
        	    case jr_op:
		        break;
        	}
		break;
	    case bcond_op:
        	switch (inst.i_format.rt) 
		{
        	    case bltz_op:
        	    case bgez_op:
        	    case bltzl_op:
        	    case bgezl_op:

        	    case bltzal_op:
        	    case bgezal_op:
        	    case bltzall_op:
        	    case bgezall_op:
		        update_one_branch(inst, bin.text_lo + i*SIZE_INST);
        	}
		break;
	    case beq_op:
	    case bne_op:
	    case blez_op:
	    case bgtz_op:
	    case beql_op:
	    case bnel_op:
	    case blezl_op:
	    case bgtzl_op:
		update_one_branch(inst, bin.text_lo + i*SIZE_INST);
		break;

	    case cop0_op:
	    case cop1_op:
	    case cop2_op:
	        if (inst.i_format.rs == bc_op)
		{
		    update_one_branch(inst, bin.text_lo + i*SIZE_INST);
		}
	        break;

            default:
                break;
        }
    }
}

/*------------------------------------------------------------------------------
    write out the binary
------------------------------------------------------------------------------*/
void write_it(void)
{
    int 	size;

    size =  elf_update(bin.new_elf, ELF_C_WRITE);
    if (size == -1)
	print_elf_error();
    elf_end(bin.new_elf);
}