You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
544 lines
16 KiB
544 lines
16 KiB
/********************************************************************** |
|
* pfopt.c |
|
* Finalization of optimized image |
|
* |
|
* Copyright (C) 2008-2009 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 <stdint.h> |
|
#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_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(); |
|
} |
|
|
|
/**********************************************************************/
|
|
|