forked from Archive/PX4-Autopilot
545 lines
16 KiB
C
545 lines
16 KiB
C
/**********************************************************************
|
|
* 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();
|
|
}
|
|
|
|
/**********************************************************************/
|