summaryrefslogblamecommitdiff
path: root/misc/pascal/plink/plreloc.c
blob: 32911570ccfd4f97b2621d75a5b06632b897a323 (plain) (tree)





























































































































































































































































                                                                         
/**********************************************************************
 * plreloc.c
 * Relocation management for the P-Code Linker
 *
 *   Copyright (C) 2008 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 **********************************************************************/

/**********************************************************************
 * Included Files
 **********************************************************************/

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

#include "keywords.h"
#include "pdefs.h"
#include "podefs.h"
#include "pedefs.h"

#include "pofflib.h"
#include "paslib.h"
#include "pinsn.h"
#include "perr.h"
#include "plsym.h"
#include "plreloc.h"

/**********************************************************************
 * Definitions
 **********************************************************************/

#define INITIAL_RELOC_LIST_SIZE (1024*sizeof(poffRelocation_t*))
#define RELOC_LIST_INCREMENT    (256*sizeof(poffRelocation_t*))

/**********************************************************************
 * Private Types
 **********************************************************************/

/**********************************************************************
 * Private Variables
 **********************************************************************/

static poffRelocation_t *relocList      = NULL;
static uint32            relocListAlloc = 0;
static uint32            nRelocs        = 0;

/**********************************************************************
 * Private Function Prototypes

 **********************************************************************/

static void offsetRelocation(poffRelocation_t *reloc,
			     uint32 pcOffset, uint32 symOffset);
static void addRelocToList(poffRelocation_t *reloc);

/**********************************************************************
 * Public Functions
 **********************************************************************/

void mergeRelocations(poffHandle_t inHandle,
		      uint32 pcOffset, uint32 symOffset)
{
  poffRelocation_t reloc;
  sint32 index;

  do
    {
      /* Read each relocation record from the input File */

      index = poffGetRawRelocation(inHandle, &reloc);
      if (index >= 0)
	{
	  /* If the rellocation carries a "payload" that is a program
	   * section offset, then apply the pcOffset value to
	   * that "payload"
	   */

	  offsetRelocation(&reloc, pcOffset, symOffset);

	  /* Add the relocation to the in-memory relocation list */

	  addRelocToList(&reloc);
	}
    }
  while (index >= 0);
}

/***********************************************************************/

void applyRelocations(poffHandle_t outHandle)
{
  ubyte *progData;
  uint32 progSize;
  int    i;

  /* Take ownership of the program data image for a little while */

  progSize = poffExtractProgramData(outHandle, &progData);

  /* Process each text data section reloation */

  for (i = 0; i < nRelocs; i++)
    {
      poffRelocation_t *reloc = &relocList[i];
      uint32            symIndex = RLI_SYM(reloc->rl_info);
      uint32            relType  = RLI_TYPE(reloc->rl_info);
      poffLibSymbol_t  *sym;
      uint32            progIndex;

      switch (relType)
	{
	case RLT_PCAL:
	  /* Get the symbol referenced by the relocation.  At this
	   * point, we assume that the system has already verified
	   * that there are no undefined symbols.
	   */

	  sym = getSymbolByIndex(symIndex);

	  /* Get the index to the oPCAL instruction */

	  progIndex = reloc->rl_offset;

	  /* Sanity checking */

	  if (((sym->flags & STF_UNDEFINED) != 0) ||
	      (progIndex > progSize-4))
	    fatal(ePOFFCONFUSION);

	  /* Perform the relocation */

	  insn_FixupProcedureCall(&progData[progIndex], sym->value);
	  break;

	default:
	  break;
	}
    }


  /* Return ownership of the program data to the container */

  poffInsertProgramData(outHandle, progData, progSize);
}

/***********************************************************************/

void releaseRelocations(void)
{
  if (relocList) free(relocList);
  relocList = NULL;
}

/**********************************************************************
 * Private Functions
 **********************************************************************/

static void offsetRelocation(poffRelocation_t *reloc,
			     uint32 pcOffset, uint32 symOffset)
{
  uint32 symIndex = RLI_SYM(reloc->rl_info);
  uint32 relType  = RLI_TYPE(reloc->rl_info);

  switch (relType)
    {
    case RLT_PCAL:
      symIndex         += symOffset;
      reloc->rl_info    = RLI_MAKE(symIndex, relType);
      reloc->rl_offset += pcOffset;
      break;

    default:
      break;
    }
}

/***********************************************************************/
/* Add to the linear relocation list. */

static void addRelocToList(poffRelocation_t *reloc)
{
  /* Check if we have allocated a relocation buffer yet */

  if (!relocList)
    {
      /* No, allocate it now */

      relocList = (poffRelocation_t*)malloc(INITIAL_RELOC_LIST_SIZE);
      if (!relocList)
	{
	  fatal(eNOMEMORY);
	}
      relocListAlloc = INITIAL_RELOC_LIST_SIZE;
    }

  /* Check if there is room for a new symbol */

  if ((nRelocs + 1) * sizeof(poffRelocation_t) > relocListAlloc)
    {
      uint32 newAlloc = relocListAlloc + RELOC_LIST_INCREMENT;
      poffRelocation_t *tmp;

      /* Reallocate the file name buffer */

      tmp = (poffRelocation_t*)realloc(relocList, newAlloc);
      if (!tmp)
	{
	  fatal(eNOMEMORY);
	}

      /* And set the new size */

      relocListAlloc = newAlloc;
      relocList      = tmp;
    }

  /* Save the new symbol information in the relocation data */

  relocList[nRelocs] = *reloc;
  nRelocs++;
}

/***********************************************************************/