diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-01-05 13:35:12 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-01-05 13:35:12 +0000 |
commit | f6d83168b86cb3f48151a462f3513f58c3762063 (patch) | |
tree | 179aa6e6cd3dcbddf9610108c622e94a1a34d222 | |
parent | 46ce8c4bbb9bb2bda3b25fe97cc1008a607abce8 (diff) | |
download | nuttx-f6d83168b86cb3f48151a462f3513f58c3762063.tar.gz nuttx-f6d83168b86cb3f48151a462f3513f58c3762063.tar.bz2 nuttx-f6d83168b86cb3f48151a462f3513f58c3762063.zip |
P-Code linker
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@488 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | misc/pascal/plink/Makefile | 83 | ||||
-rw-r--r-- | misc/pascal/plink/plink.c | 549 | ||||
-rw-r--r-- | misc/pascal/plink/plreloc.c | 254 | ||||
-rw-r--r-- | misc/pascal/plink/plsym.c | 468 |
4 files changed, 1354 insertions, 0 deletions
diff --git a/misc/pascal/plink/Makefile b/misc/pascal/plink/Makefile new file mode 100644 index 000000000..9b76aa6a0 --- /dev/null +++ b/misc/pascal/plink/Makefile @@ -0,0 +1,83 @@ +############################################################################ +# plink/Makefile +# +# 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. +# +############################################################################ +# +# Directories +# +PLINKDIR = ${shell pwd} +PASCAL = $(PLINKDIR)/.. + +include $(PASCAL)/Make.config +include $(PASCAL)/Make.defs + +INCDIR = $(PASCAL)/include +LIBDIR = $(PASCAL)/lib +BINDIR-$(CONFIG_INSN16) = $(PASCAL)/bin16 +BINDIR-$(CONFIG_INSN32) = $(PASCAL)/bin32 + +# +# Objects and targets +# +PLINKSRCS = plink.c plsym.c plreloc.c +PLINKOBJS = $(PLINKSRCS:.c=.o) + +OBJS = $(PLINKOBJS) + +all: plink +.PHONY: all plink clean + +$(OBJS): %.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + +check_libs: + @if [ ! -f $(LIBDIR)/libpoff.a ] ; then \ + echo "$(LIBDIR)/libpoff.a does not exist" ; \ + exit 1 ; \ + fi + @if [ ! -f $(LIBDIR)/libpas.a ] ; then \ + echo "$(LIBDIR)/libpas.a does not exist" ; \ + exit 1 ; \ + fi + @if [ ! -f $(LIBDIR)/libinsn.a ] ; then \ + echo "$(LIBDIR)/libinsn.a does not exist" ; \ + exit 1 ; \ + fi + +$(BINDIR-y)/plink: check_libs $(PLINKOBJS) + $(CC) -o $@ $(LDFLAGS) $(PLINKOBJS) -lpas -linsn -lpoff + +plink: $(BINDIR-y)/plink + +clean: + $(RM) plink *.o core *~ diff --git a/misc/pascal/plink/plink.c b/misc/pascal/plink/plink.c new file mode 100644 index 000000000..22b5af45d --- /dev/null +++ b/misc/pascal/plink/plink.c @@ -0,0 +1,549 @@ +/**********************************************************************
+ * plink.c
+ * 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 "paslib.h"
+#include "perr.h"
+#include "plsym.h"
+#include "plreloc.h"
+#include "pinsn.h"
+#include "plink.h"
+
+/**********************************************************************
+ * Definitions
+ **********************************************************************/
+
+#define MAX_POFF_FILES 8
+
+/**********************************************************************
+ * Private Type Definitions
+ **********************************************************************/
+
+/**********************************************************************
+ * Private Constant Data
+ **********************************************************************/
+
+/**********************************************************************
+ * Private Data
+ **********************************************************************/
+
+static const char *outFileName;
+static const char *inFileName[MAX_POFF_FILES];
+static int nPoffFiles = 0;
+
+/**********************************************************************
+ * Private Function Prototypes
+ **********************************************************************/
+
+static void showUsage (const char *progname);
+static void parseArgs (int argc, char **argv);
+static void loadInputFiles (poffHandle_t outHandle);
+static void checkFileHeader (poffHandle_t inHandle, poffHandle_t outHandle,
+ uint32 pcOffset,boolean *progFound);
+static uint32 mergeRoData (poffHandle_t inHandle, poffHandle_t outHandle);
+static uint32 mergeProgramData (poffHandle_t inHandle, poffHandle_t outHandle,
+ uint32 pcOffset, uint32 roOffset);
+static uint32 mergeFileNames (poffHandle_t inHandle, poffHandle_t outHandle);
+static uint32 mergeLineNumbers (poffHandle_t inHandle, poffHandle_t outHandle,
+ uint32 pcOffset, uint32 fnOffset);
+static void writeOutputFile (poffHandle_t outHandle);
+
+/**********************************************************************
+ * Global Variables
+ **********************************************************************/
+
+/**********************************************************************
+ * Private Variables
+ **********************************************************************/
+
+/**********************************************************************
+ * Public Functions
+ **********************************************************************/
+
+int main(int argc, char *argv[], char *envp[])
+{
+ poffHandle_t outHandle;
+
+ /* Parse the command line arguments */
+
+ parseArgs(argc, argv);
+
+ /* Create a handle to hold the output file data */
+
+ outHandle = poffCreateHandle();
+ if (outHandle == NULL) fatal(eNOMEMORY);
+
+ /* Load the POFF files specified on the command line */
+
+ loadInputFiles(outHandle);
+
+ /* Verify that all symbols were processed correctly */
+
+ verifySymbols();
+
+ /* Apply the relocation data to the program data */
+
+ applyRelocations(outHandle);
+
+ /* Write the symbol table information to the output file */
+
+ writeSymbols(outHandle);
+
+ /* Write the output file */
+
+ writeOutputFile(outHandle);
+
+ /* Release bufferred symbol/relocation informtion */
+
+ releaseSymbols();
+ releaseRelocations();
+
+ /* Release the input file data */
+
+ poffDestroyHandle(outHandle);
+
+ return 0;
+
+} /* end main */
+
+/**********************************************************************
+ * Private Functions
+ **********************************************************************/
+
+static void showUsage(const char *progname)
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, " %s <in-file-name> {<in-file-name>} <out-file-name>\n",
+ progname);
+}
+
+/***********************************************************************/
+
+static void parseArgs(int argc, char **argv)
+{
+ int i;
+
+ /* Check for existence of filename argument */
+
+ if (argc < 3)
+ {
+ fprintf(stderr,
+ "ERROR: <in-file-name> and one <out-file-name> required\n");
+ showUsage(argv[0]);
+ } /* end if */
+
+ /* Get the name of the p-code file(s) from the last argument(s) */
+
+ for (i = 1; i < argc-1; i++)
+ {
+ inFileName[nPoffFiles] = argv[i];
+ nPoffFiles++;
+ }
+
+ /* The last thing on the command line is the output file name */
+
+ outFileName = argv[argc-1];
+}
+
+/***********************************************************************/
+/* This function loads each POFF file specified on the command line,
+ * merges the input POFF data, and generates intermediate structures
+ * to be used in the final link.
+ */
+
+static void loadInputFiles(poffHandle_t outHandle)
+{
+ poffHandle_t inHandle;
+ FILE *instream;
+ char fileName[FNAME_SIZE+1]; /* Object file name */
+ uint32 pcOffset = 0;
+ uint32 fnOffset = 0;
+ uint32 symOffset = 0;
+ uint32 roOffset = 0;
+ uint32 pcEnd = 0;
+ uint32 fnEnd = 0;
+ uint32 symEnd = 0;
+ uint16 errCode;
+ boolean progFound = FALSE;
+ int i;
+
+ /* Load the POFF files specified on the command line */
+
+ for (i = 0; i < nPoffFiles; i++)
+ {
+ /* Create a handle to hold the input file data */
+
+ inHandle = poffCreateHandle();
+ if (inHandle == NULL) fatal(eNOMEMORY);
+
+ /* Use .o or command line extension, if supplied, to get the
+ * input file name.
+ */
+
+ (void)extension(inFileName[i], "o", fileName, 0);
+
+ /* Open the input file */
+
+ instream = fopen(fileName, "rb");
+ if (instream == NULL)
+ {
+ fprintf(stderr, "ERROR: Could not open %s: %s\n",
+ fileName, strerror(errno));
+ exit(1);
+ }
+
+ /* Load the POFF file */
+
+ errCode = poffReadFile(inHandle, instream);
+ if (errCode != eNOERROR)
+ {
+ fprintf(stderr, "ERROR: Could not read %s (%d)\n",
+ fileName, errCode);
+ exit(1);
+ }
+
+ /* Check file header for critical settings */
+
+ checkFileHeader(inHandle, outHandle, pcOffset, &progFound);
+
+ /* Merge the read-only data sections */
+
+ roOffset = mergeRoData(inHandle, outHandle);
+
+ /* Merge program section data from the new input file into the
+ * output file container.
+ */
+
+ pcEnd = mergeProgramData(inHandle, outHandle, pcOffset, roOffset);
+
+ /* Merge the file name data from the new input file into the
+ * output file container.
+ */
+
+ fnEnd = mergeFileNames(inHandle, outHandle);
+
+ /* Merge the line number data from the new input file into the
+ * output file container.
+ */
+
+ (void)mergeLineNumbers(inHandle, outHandle, pcOffset, fnOffset);
+
+ /* On this pass, we just want to collect all symbol table in a
+ * local list where we can resolve all undefined symbols (later)
+ */
+
+ symEnd = mergeSymbols(inHandle, pcOffset, symOffset);
+
+ /* On this pass, we will also want to buffer all relocation data,
+ * adjusting only the program section offset and sym table
+ * offsets.
+ */
+
+ mergeRelocations(inHandle, pcOffset, symOffset);
+
+ /* Release the input file data */
+
+ insn_ResetOpCodeRead(inHandle);
+ poffDestroyHandle(inHandle);
+
+ /* Close the input file */
+
+ fclose(instream);
+
+ /* Set the offsest to be used for the next file equal
+ * to the end values found from processing this file
+ */
+
+ pcOffset = pcEnd;
+ fnOffset = fnEnd;
+ symOffset = symEnd;
+ }
+
+ /* Did we find exactly one program file? */
+
+ if (!progFound)
+ {
+ /* No! We have to have a program file to generate an executable */
+
+ fprintf(stderr, "ERROR: No program file found in input files\n");
+ exit(1);
+ }
+
+} /* end loadInputFiles */
+
+/***********************************************************************/
+
+static void checkFileHeader(poffHandle_t inHandle, poffHandle_t outHandle,
+ uint32 pcOffset, boolean *progFound)
+{
+ ubyte fileType;
+
+ /* What kind of file are we processing? */
+
+ fileType = poffGetFileType(inHandle);
+ if (fileType == FHT_PROGRAM)
+ {
+ /* We can handle only one pascal program file */
+
+ if (*progFound)
+ {
+ fprintf(stderr,
+ "ERROR: Only one compiled pascal program file "
+ "may appear in input file list\n");
+ exit(1);
+ }
+ else
+ {
+ /* Get the entry point from the pascal file, apply any
+ * necessary offsets, and store the entry point in the
+ * linked output file's file header.
+ */
+
+ poffSetEntryPoint(outHandle,
+ poffGetEntryPoint(inHandle) + pcOffset);
+
+ /* Copy the program name from the pascal file to the linked
+ * output file's file header and mark the output file as
+ * a pascal executable.
+ */
+
+ poffSetFileType(outHandle, FHT_EXEC, 0,
+ poffGetFileHdrName(inHandle));
+
+ /* Indicate that we have found the program file */
+
+ *progFound = TRUE;
+ }
+ }
+ else if (fileType != FHT_UNIT)
+ {
+ /* It is something other than a compiled pascal program or unit
+ * file.
+ */
+
+ fprintf(stderr,
+ "ERROR: Only compiled pascal program and unit files "
+ "may appear in input file list\n");
+ exit(1);
+ }
+}
+
+/***********************************************************************/
+
+static uint32 mergeRoData(poffHandle_t inHandle, poffHandle_t outHandle)
+{
+ ubyte *newRoData;
+ uint32 oldRoDataSize;
+ uint32 newRoDataSize;
+
+ /* Get the size of the read-only data section before we add the
+ * new data. This is the offset that must be applied to any
+ * references to the new data.
+ */
+
+ oldRoDataSize = poffGetRoDataSize(outHandle);
+
+ /* Remove the read-only data from new input file */
+
+ newRoDataSize = poffExtractRoData(inHandle, &newRoData);
+
+ /* And append the new read-only data to output file */
+
+ poffAppendRoData(outHandle, newRoData, newRoDataSize);
+
+ return oldRoDataSize;
+}
+
+/***********************************************************************/
+/* This function merges the program data section of a new file into the
+ * program data section of the output file, relocating simple program
+ * section references as they are encountered.
+ */
+
+static uint32 mergeProgramData(poffHandle_t inHandle,
+ poffHandle_t outHandle,
+ uint32 pcOffset, uint32 roOffset)
+{
+ OPTYPE op;
+ uint32 pc;
+ uint32 opSize;
+ int endOp;
+
+ /* Read each opcode from the input file, add pcOffset to each program
+ * section address, and add each opcode to the output file.
+ */
+
+ pc = pcOffset;
+ do
+ {
+ /* Read the next opcode (with its size) */
+
+ opSize = insn_GetOpCode(inHandle, &op);
+
+ /* Perform any necessary relocations */
+
+ endOp = insn_Relocate(&op, pcOffset, roOffset);
+
+ /* Save the potentially modified opcode in the temporary
+ * program data container.
+ */
+
+ insn_AddOpCode(outHandle, &op);
+ pc += opSize;
+ }
+ while (endOp == 0);
+
+ return pc;
+}
+
+/***********************************************************************/
+/* This function merges the file name section of a new file into the
+ * file name section of the output file, relocating simple program
+ * section references as they are encountered.
+ */
+
+static uint32 mergeFileNames(poffHandle_t inHandle,
+ poffHandle_t outHandle)
+{
+ sint32 inOffset;
+ uint32 outOffset;
+ const char *fname;
+
+ do
+ {
+ /* Read each file name from the input File */
+
+ inOffset = poffGetFileName(inHandle, &fname);
+ if (inOffset >= 0)
+ {
+ /* And write it to the output file */
+
+ outOffset = poffAddFileName(outHandle, fname);
+ }
+ }
+ while (inOffset >= 0);
+
+ /* Return the offset to the last file name written to the
+ * output file
+ */
+
+ return outOffset;
+}
+
+/***********************************************************************/
+/* This function merges the line number section of a new file into the
+ * line number section of the output file, relocating simple program
+ * section references as they are encountered.
+ */
+
+static uint32 mergeLineNumbers(poffHandle_t inHandle,
+ poffHandle_t outHandle,
+ uint32 pcOffset,
+ uint32 fnOffset)
+{
+ poffLineNumber_t lineno;
+ sint32 inOffset;
+ uint32 outOffset;
+
+ do
+ {
+ /* Read each line number from the input File */
+
+ inOffset = poffGetRawLineNumber(inHandle, &lineno);
+ if (inOffset >= 0)
+ {
+ /* And write it to the output file */
+
+ outOffset = poffAddLineNumber(outHandle, lineno.ln_lineno,
+ lineno.ln_fileno + fnOffset,
+ lineno.ln_poffset + pcOffset);
+ }
+ }
+ while (inOffset >= 0);
+
+ /* Return the offset to the last line number written to the
+ * output file
+ */
+
+ return outOffset;
+}
+
+/***********************************************************************/
+
+static void writeOutputFile(poffHandle_t outHandle)
+{
+ FILE *outstream;
+ char fileName[FNAME_SIZE+1]; /* Output file name */
+
+ /* Use .pex or command line extension, if supplied, to get the
+ * input file name.
+ */
+
+ (void)extension(outFileName, "pex", fileName, 0);
+
+ /* Open the output file */
+
+ outstream = fopen(fileName, "wb");
+ if (outstream == NULL)
+ {
+ fprintf(stderr, "ERROR: Could not open %s: %s\n",
+ fileName, strerror(errno));
+ exit(1);
+ }
+
+ /* Write the POFF file */
+
+ (void)poffWriteFile(outHandle, outstream);
+
+ /* Close the output file */
+
+ fclose(outstream);
+}
+
+/***********************************************************************/
diff --git a/misc/pascal/plink/plreloc.c b/misc/pascal/plink/plreloc.c new file mode 100644 index 000000000..32911570c --- /dev/null +++ b/misc/pascal/plink/plreloc.c @@ -0,0 +1,254 @@ +/********************************************************************** + * 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++; +} + +/***********************************************************************/ + diff --git a/misc/pascal/plink/plsym.c b/misc/pascal/plink/plsym.c new file mode 100644 index 000000000..1ef40461a --- /dev/null +++ b/misc/pascal/plink/plsym.c @@ -0,0 +1,468 @@ +/********************************************************************** + * plsym.c + * Symbol 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 "perr.h" +#include "plsym.h" + +/********************************************************************** + * Definitions + **********************************************************************/ + +#define INITIAL_SYMBOL_LIST_SIZE (1024*sizeof(symContainer_t*)) +#define SYMBOL_LIST_INCREMENT (256*sizeof(symContainer_t*)) + +/********************************************************************** + * Private Types + **********************************************************************/ + +/* This structure just contains a POFF library symbol */ + +struct symContainer_s +{ + struct symContainer_s *next; + struct symContainer_s *prev; + poffLibSymbol_t s; +}; +typedef struct symContainer_s symContainer_t; + +/********************************************************************** + * Private Variables + **********************************************************************/ + +static symContainer_t *symHead = NULL; +static symContainer_t *symTail = NULL; +static symContainer_t **symList = NULL; +static uint32 symListAlloc = 0; + +static int nUndefined = 0; +static int nMultiplyDefined = 0; + +/********************************************************************** + * Private Function Prototypes + + **********************************************************************/ + +static void offsetSymbolValue(poffLibSymbol_t *sym, + uint32 pcOffset); +static symContainer_t *insertSymbol(poffLibSymbol_t *sym); +static void addSymbolToList(symContainer_t *symbol, + uint32 index); + +/********************************************************************** + * Public Functions + **********************************************************************/ + +uint32 mergeSymbols(poffHandle_t inHandle, uint32 pcOffset, uint32 symOffset) +{ + poffLibSymbol_t symbol; + symContainer_t *container; + sint32 inIndex; + uint32 outIndex; + + do + { + /* Read each symbol from the input File */ + + inIndex = poffGetSymbol(inHandle, &symbol); + if (inIndex >= 0) + { + /* If the symbol carries a "payload" that is a program + * section offset, then apply the pcOffset value to + * that "payload" + */ + + offsetSymbolValue(&symbol, pcOffset); + + /* Create a container for the symbol information */ + + container = insertSymbol(&symbol); + + /* Add the symbol to the linearly indexed list */ + + outIndex = inIndex + symOffset; + addSymbolToList(container, outIndex); + } + } + while (inIndex >= 0); + + /* Return the offset to the last symbol inserted */ + + return outIndex; +} + +/***********************************************************************/ + +void verifySymbols(void) +{ + symContainer_t *sym; + + /* At the conclusion the link, there should be no undefined symbols. + * This function simply asserts that condition. It traverses the + * symbol container list and if any undefined symbol is found, it + * errors out. + */ + + for (sym = symHead; (sym); sym = sym->next) + { + if ((sym->s.flags & STF_UNDEFINED) != 0) + { + fprintf(stderr, "ERROR: Undefined symbol '%s'\n", + sym->s.name); + nUndefined++; + } + } + + if (nUndefined) fatal(eUNDEFINEDSYMBOL); + if (nMultiplyDefined) fatal(eMULTIDEFSYMBOL); +} + +/***********************************************************************/ + +void writeSymbols(poffHandle_t outHandle) +{ + symContainer_t *sym; + + /* Transfer all buffered symbol information to the output file */ + + for (sym = symHead; (sym); sym = sym->next) + { + (void)poffAddSymbol(outHandle, &sym->s); + } +} + +/***********************************************************************/ + +poffLibSymbol_t *getSymbolByIndex(uint32 symIndex) +{ + if (symIndex * sizeof(symContainer_t*) >= symListAlloc) + fatal(ePOFFCONFUSION); + return &symList[symIndex]->s; +} + +/***********************************************************************/ + +void releaseSymbols(void) +{ + static symContainer_t *curr; + static symContainer_t *next; + + for (curr = symHead; (curr); curr = next) + { + /* Get the next pointer from the container -- we are going + * to deallocate the container! + */ + + next = curr->next; + + /* Deallocate the name string copy */ + + if (curr->s.name) free((void*)curr->s.name); + + /* Free the container */ + + free(curr); + } + + /* Free the index-able symbol list */ + + if (symList) free((void*)symList); + + symHead = NULL; + symTail = NULL; + symList = NULL; +} + +/**********************************************************************/ + +static void offsetSymbolValue(poffLibSymbol_t *sym, uint32 pcOffset) +{ + /* Don't do anything with undefined symbols. By definition, these + * cannot cannot any meaning values. + */ + + if ((sym->flags & STF_UNDEFINED) == 0) + { + switch (sym->type) + { + case STT_PROC: + case STT_FUNC: + sym->value += pcOffset; + break; + + default: + break; + } + } +} + +/**********************************************************************/ + +static inline symContainer_t *makeSymContainer(poffLibSymbol_t *psym) +{ + symContainer_t *sym; + sym = (symContainer_t*)malloc(sizeof(symContainer_t)); + if (sym == NULL) + { + fatal(eNOMEMORY); + } + + /* The next container is not linked to anything yet */ + + sym->next = NULL; + sym->prev = NULL; + + /* Copy the whole symbol record */ + + sym->s = *psym; + + /* Duplicate the symbol name -- the reference in the symbol entry + * belongs to the input file and will be lost if/when the input file + * is released. + */ + + if (psym->name) + { + sym->s.name = strdup(psym->name); + } + return sym; +} + +static symContainer_t *insertSymbol(poffLibSymbol_t *sym) +{ + symContainer_t *prev; + symContainer_t *curr; + symContainer_t *newsym; + int compare; + + /* Find where to insert the symbol */ + + for (prev = NULL, curr = symHead; (curr); prev = curr, curr = curr->next) + { + /* Compare the names of the symbols */ + + compare = strcmp(curr->s.name, sym->name); + + /* Break out of the loop if curr->name > sym_name or + * if curr->name == sym_name AND the types of the + * symbols are the same. + */ + + if (compare > 0) + { + /* Break out... curr refers to a symbol AFTER the position + * where we want to put the new symbol. + */ + + break; + } + else if (compare == 0) + { + /* The symbols are the same. break out only if the types + * are the same or this is where we need to insert the new + * symbol (same name different type) + */ + + if (curr->s.type > sym->type) + { + compare = 1; + break; + } + else if (curr->s.type == sym->type) + { + break; + } + } + } + + /* We get here if: + * a. curr == NULL meaning that the symbol goes at the end of the + * list. (special case, prev == NULL as well. This happens when + * the list is empty). + * b. curr != NULL mean that the symbol goes between prev and curr + * (special cases: (i) compare == 0 meaning that the symbol is + * already in the list, or (ii) compare > 0 with prev == NULL + * meaning that the new entry goes at the beginning of the list). + */ + + if (curr == NULL) + { + /* The symbol goes at the end of the list */ + + newsym = makeSymContainer(sym); + newsym->next = NULL; + newsym->prev = prev; + symTail = newsym; + + if (prev) + prev->next = newsym; + else + symHead = newsym; + } + else if (compare == 0) + { + /* curr is non-NULL and refers to the same symbol (of the same + * type). If both are undefined, then just discard the new + * symbol. + */ + + if ((curr->s.flags & STF_UNDEFINED) != 0) + { + /* The symbol in the table is undefined */ + + if ((sym->flags & STF_UNDEFINED) != 0) + { + /* Both symbols are undefined. Just ignore the new one */ + } + else + { + /* The symbol in the table is undefined, but the new + * one is defined. Replace the one in the table (retaining + * the allocated symbol name). + */ + const char *save = curr->s.name; + curr->s = *sym; + curr->s.name = save; + } + } + else + { + /* The symbol in the table is defined */ + + if ((sym->flags & STF_UNDEFINED) != 0) + { + /* But the new symbol is undefined. Just ignore the + * new symbol + */ + } + else + { + /* OOPS! both symbols are defined */ + + fprintf(stderr, + "ERROR: Multiply defined symbol: '%s'\n", + sym->name); + nMultiplyDefined++; + } + + /* In any case, return the pointer to the old container */ + + newsym = curr; + } + } + else + { + /* curr is non-NULL and the symbol goes between prev and curr */ + + newsym = makeSymContainer(sym); + newsym->next = curr; + newsym->prev = prev; + + if (prev) + prev->next = newsym; + else + symHead = newsym; + } + + return newsym; +} + +/***********************************************************************/ +/* Add a symbol to the linear symbol table list. This list is necessary + * to quickly mapped a symbol index value (as might be found in the + * relocation data) to the unique representation of the symbol as + * deterimed by insertSymbol(). + */ + +static void addSymbolToList(symContainer_t *symbol, uint32 index) +{ + /* Check if we have allocated a symbol table buffer yet */ + + if (!symList) + { + /* No, allocate it now */ + + symList = (symContainer_t**)malloc(INITIAL_SYMBOL_LIST_SIZE); + if (!symList) + { + fatal(eNOMEMORY); + } + symListAlloc = INITIAL_SYMBOL_LIST_SIZE; + } + + /* Check if there is room for a new symbol */ + + if ((index + 1) * sizeof(symContainer_t*) > symListAlloc) + { + uint32 newAlloc = symListAlloc + SYMBOL_LIST_INCREMENT; + symContainer_t **tmp; + + /* Reallocate the file name buffer */ + + tmp = (symContainer_t**)realloc(symList, newAlloc); + if (!tmp) + { + fatal(eNOMEMORY); + } + + /* And set the new size */ + + symListAlloc = newAlloc; + symList = tmp; + } + + /* Save the new symbol information in the symbol table data */ + + symList[index] = symbol; +} + +/***********************************************************************/ + |