diff options
Diffstat (limited to 'misc/pascal/insn32/popt/pfopt.c')
-rw-r--r-- | misc/pascal/insn32/popt/pfopt.c | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/misc/pascal/insn32/popt/pfopt.c b/misc/pascal/insn32/popt/pfopt.c new file mode 100644 index 000000000..de07400bf --- /dev/null +++ b/misc/pascal/insn32/popt/pfopt.c @@ -0,0 +1,543 @@ +/********************************************************************** + * pfopt.c + * Finalization of optimized image + * + * 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 "keywords.h" +#include "pdefs.h" +#include "podefs.h" +#include "pedefs.h" +#include "pinsn32.h" +#include "poff.h" + +#include "paslib.h" +#include "pofflib.h" +#include "popt.h" +#include "pfopt.h" +#include "pinsn.h" +#include "perr.h" + +/********************************************************************** + * Definitions + **********************************************************************/ + +/********************************************************************** + * Private Types + **********************************************************************/ + +/********************************************************************** + * Private Data + **********************************************************************/ + +/********************************************************************** + * Private Function Prototypes + **********************************************************************/ + +/********************************************************************** + * Private Inline Functions + **********************************************************************/ + +/********************************************************************** + * Private Functions + **********************************************************************/ + +/**********************************************************************/ + +static void pass1(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle) +{ + OPTYPE op; + uint32 pc; + int opsize; + int fileno = 0; + + /* Build label / line number reference table + * + * CASE 1: LABEL + * Add label number + PC to table + * discard + * CASE 2: LINE + * genereate a line number reference + * discard + * ELSE: + * pass through with no additional action + */ + + pc = 0; + do + { + opsize = insn_GetOpCode(poffHandle, &op); + if (GETOP(&op) == oLABEL) + { + poffAddToDefinedLabelTable(GETARG(&op), pc); + } + else if (GETOP(&op) == oINCLUDE) + { + fileno = GETARG(&op); + } + else if (GETOP(&op) == oLINE) + { + poffAddLineNumber(poffHandle, GETARG(&op), fileno, pc); + } + else + { + insn_AddTmpOpCode(poffProgHandle, &op); + pc += opsize; + } + } + while (GETOP(&op) != oEND); + + /* Replace the original program data with the new program data */ + + poffReplaceProgData(poffHandle, poffProgHandle); +} + +/**********************************************************************/ + +static void pass2(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle) +{ + poffSymHandle_t poffSymHandle; + sint32 symIndex; + sint32 nchanges = 0; + + /* Get a container to temporarily hold any modifications that we + * make to the symbol table. + */ + + poffSymHandle = poffCreateSymHandle(); + if (poffSymHandle == NULL) + { + fatal(eNOMEMORY); + } + + /* Now read all of the symbols. (1) Add each undefined code reference + * to the label reference table, and (2) Change each defined code + * reference from a label to a program data section offset. + */ + + do + { + poffLibSymbol_t symbol; + symIndex = poffGetSymbol(poffHandle, &symbol); + if (symIndex >= 0) + { + if ((symbol.type == STT_PROC) || (symbol.type == STT_FUNC)) + { + /* It is a symbol associated with the program data section. + * Has is value been defined? + */ + + if ((symbol.flags & STF_UNDEFINED) != 0) + { + /* No... Add it to the list of undefined labels */ + + poffAddToUndefinedLabelTable(symbol.value, symIndex); + } + else + { + /* It is a defined symbol. In this case, we should have + * encountered its LABEL marker in the pass1 processing + * and the following look up should not fail. + */ + sint32 value = poffGetPcForDefinedLabel(symbol.value); + if (value < 0) + { + DEBUG(stdout, "Failed to find label L%04lx\n", symbol.value); + fatal(ePOFFCONFUSION); + } + else + { + /* Replace the lavel value with the section offset + * (pc) value. + */ + + symbol.value = value; + nchanges++; + } + } + } + + /* In either event, we will want to save the symbol in case + * we need to re-write the symbol table. + */ + + (void)poffAddTmpSymbol(poffHandle, poffSymHandle, &symbol); + } + } + while (symIndex >= 0); + + /* We any changes made to the symbol table in the temporary container? */ + + if (nchanges != 0) + { + /* Yes, update the symbol table */ + + poffReplaceSymbolTable(poffHandle, poffSymHandle); + + } + + /* Release the symbol container. */ + + poffDestroySymHandle(poffSymHandle); +} + +/**********************************************************************/ + +static void pass3(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle) +{ + OPTYPE op; + uint32 pc; + uint32 opsize; + + /* Read each opcode, generate relocation information and + * replace label references with program section offsets. + * + * CASE 1: LAC + * generate RODATA relocation entry + * CASE 2: PCAL instructions + * replace label with I-space offset, OR + * generate a PROGRAM relocation entry + * CASE 3: J* instructions + * replace label with I-space offset + * CASE 4: LDS*, STS*, and LAS* instructions + * generate a STACK relocation (if imported?) + * ELSE: + * pass through with no additional action + */ + + pc = 0; + do + { + opsize = insn_GetOpCode(poffHandle, &op); + switch (GETOP(&op)) + { + /* Load of an address in the rodata section */ + + case oLAC: + /* We are referencing something from the rodata section. + * No special action need be taken. + */ + break; + + /* Call to a procedure or function. */ + + case oPCAL: + { + /* Check if this is a defined label, i.e., a call to + * procedure or function in the same file. + */ + + sint32 value = poffGetPcForDefinedLabel(GETARG(&op)); + if (value >= 0) + { + /* Yes... replace the label reference with + * a text section offset. No relocation record + * is needed in this case. The only relocation + * may be performed is a subsequent program data + * section offset. + */ + + PUTARG(&op, value); + } + else + { + /* Check if this is a undefined label. This would + * occur for a call to a procedure or a function that + * is defined in some other unit file. + */ + + value = poffGetSymIndexForUndefinedLabel(GETARG(&op)); + if (value >= 0) + { + /* Use the value zero now */ + + PUTARG(&op, 0); + + /* And generate a symbol-based relocation */ + + (void)poffAddRelocation(poffHandle, RLT_PCAL, value, pc); + } + else + { + DEBUG(stdout, "Failed to find call label L%04x\n", + GETARG(&op)); + fatal(ePOFFCONFUSION); + } + } + } + break; + + /* Jumps to "nearby" addresses */ + + case oJMP: /* Unconditional */ + case oJEQUZ: /* Unary comparisons with zero */ + case oJNEQZ: + case oJLTZ: + case oJGTEZ: + case oJGTZ: + case oJLTEZ: + case oJEQU: /* Binary comparisons */ + case oJNEQ: + case oJLT: + case oJGTE: + case oJGT: + case oJLTE: + { + /* Check if this is a defined label. This must be the case + * because there can be no jumps into a unit file. + */ + + sint32 value = poffGetPcForDefinedLabel(GETARG(&op)); + if (value >= 0) + { + /* Yes... replace the label reference with + * a text section offset. No relocation record + * is needed in this case. The only relocation + * may be performed is a subsequent program data + * sectioin offset. + */ + + PUTARG(&op, value); + } + else + { + DEBUG(stdout, "Failed to find jump label L%04x\n", + GETARG(&op)); + fatal(ePOFFCONFUSION); + } + } + break; + + /* References to stack via level offset */ + + case oLAS: /* Load stack address */ + case oLASX: + case oLDS: /* Load value */ + case oLDSH: + case oLDSB: + case oLDSM: + case oSTS: /* Store value */ + case oSTSH: + case oSTSB: + case oSTSM: + case oLDSX: + case oLDSXH: /* Load value indexed */ + case oLDSXB: + case oLDSXM: + case oSTSX: /* Store value indexed */ + case oSTSXH: + case oSTSXB: + case oSTSXM: + { +#warning REVISIT + } + break; + + /* Otherwise, it is not an interesting opcode */ + default: + break; + } + + /* Save the potentially modified opcode in the temporary + * program data container. + */ + + insn_AddTmpOpCode(poffProgHandle, &op); + pc += opsize; + } + while (GETOP(&op) != oEND); + + /* Replace the original program data with the new program data */ + + poffReplaceProgData(poffHandle, poffProgHandle); +} + +/**********************************************************************/ +/* Fixed label references in the debug function information */ + +static void pass4(poffHandle_t poffHandle) +{ + poffLibDebugFuncInfo_t *pDebugInfoHead = NULL; + poffLibDebugFuncInfo_t *pDebugInfoTail = NULL; + poffLibDebugFuncInfo_t *pDebugInfo; + poffLibDebugFuncInfo_t *pNextDebugInfo; + + /* Read all function debug information into a link list */ + + while ((pDebugInfo = poffGetDebugFuncInfo(poffHandle)) != NULL) + { + if (!pDebugInfoHead) + { + pDebugInfoHead = pDebugInfo; + } + else + { + pDebugInfoTail->next = pDebugInfo; + } + pDebugInfoTail = pDebugInfo; + } + + /* Convert all of the label references to pcode offsets */ + + for (pDebugInfo = pDebugInfoHead; pDebugInfo; pDebugInfo = pDebugInfo->next) + { + /* Check if this is a defined label. This must be the case + * because there can be no jumps into a unit file. + */ + + sint32 value = poffGetPcForDefinedLabel(pDebugInfo->value); + if (value >= 0) + { + /* Yes... replace the label reference with a text section offset. */ + + pDebugInfo->value = value; + } + else + { + fatal(ePOFFCONFUSION); + } + } + + /* Then put all of the debug info back into the POFF object */ + + poffDiscardDebugFuncInfo(poffHandle); + + for (pDebugInfo = pDebugInfoHead; pDebugInfo; pDebugInfo = pDebugInfo->next) + { + poffAddDebugFuncInfo(poffHandle, pDebugInfo); + } + + /* Release the bufferred debug information */ + + pDebugInfo = pDebugInfoHead; + while (pDebugInfo) + { + pNextDebugInfo = pDebugInfo->next; + poffReleaseDebugFuncContainer(pDebugInfo); + pDebugInfo = pNextDebugInfo; + } +} + +/**********************************************************************/ + +static void pass5(poffHandle_t poffHandle) +{ + uint32 entryLabel; + sint32 entryOffset; + ubyte fileType; + + /* What kind of a file did we just process. Was it a program file? + * or was it a unit file? + */ + + fileType = poffGetFileType(poffHandle); + if (fileType == FHT_PROGRAM) + { + /* It is a program file. In this case, it must have a valid + * entry point label. Get it. + */ + + entryLabel = poffGetEntryPoint(poffHandle); + + /* Convert the label into a program data section offset */ + + entryOffset = poffGetPcForDefinedLabel(entryLabel); + if (entryOffset < 0) + { + fatal(ePOFFCONFUSION); + } + + /* Replace file header entry point with the program data + * section offset + */ + + poffSetEntryPoint(poffHandle, entryOffset); + } +} + +/********************************************************************** + * Global Functions + **********************************************************************/ + +void optFinalize(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle) +{ + /* Build label / line number reference table */ + + pass1(poffHandle, poffProgHandle); + + /* Reset for next pass */ + + insn_ResetOpCodeRead(poffHandle); + insn_ResetTmpOpCodeWrite(poffProgHandle); + + /* Now process all of the symbols */ + + pass2(poffHandle, poffProgHandle); + + /* Reset for next pass */ + + insn_ResetOpCodeRead(poffHandle); + + /* Generate relocation information and replace all label references + * in the code with actual program section data offsets. + */ + + pass3(poffHandle, poffProgHandle); + + /* Fixed label references in the debug function information */ + + pass4(poffHandle); + + /* Reset for next pass */ + + insn_ResetOpCodeRead(poffHandle); + insn_ResetTmpOpCodeWrite(poffProgHandle); + + /* Finally, replace file header entry point with the I-space offset */ + + pass5(poffHandle); + + /* Clean up after ourselves */ + + poffReleaseLabelReferences(); +} + +/**********************************************************************/ |