/********************************************************************** * pfopt.c * Finalization of optimized image * * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 #include #include #include #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_t 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; int32_t symIndex; int32_t 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. */ int32_t 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_t pc; uint32_t 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. */ int32_t 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. */ int32_t 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. */ int32_t 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_t entryLabel; int32_t entryOffset; uint8_t 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(); } /**********************************************************************/