ref: c3fa922c2f7e09bdf577ca3041bfdbc683e55a91
dir: /src/asm/output.c/
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* INCLUDES
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asm/asm.h"
#include "asm/output.h"
#include "asm/symbol.h"
#include "asm/mylink.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"
#define SECTIONCHUNK 0x4000
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Internal structures
*
*/
void out_SetCurrentSection(struct Section * pSect);
struct Patch {
char tzFilename[_MAX_PATH + 1];
ULONG nLine;
ULONG nOffset;
UBYTE nType;
ULONG nRPNSize;
UBYTE *pRPN;
struct Patch *pNext;
};
struct PatchSymbol {
ULONG ID;
struct sSymbol *pSymbol;
struct PatchSymbol *pNext;
};
struct SectionStackEntry {
struct Section *pSection;
struct SectionStackEntry *pNext;
};
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* VARIABLES
*
*/
struct Section *pSectionList = NULL, *pCurrentSection = NULL;
struct PatchSymbol *pPatchSymbols = NULL;
char tzObjectname[_MAX_PATH];
struct SectionStackEntry *pSectionStack = NULL;
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Section stack routines
*
*/
void
out_PushSection(void)
{
struct SectionStackEntry *pSect;
if ((pSect =
(struct SectionStackEntry *)
malloc(sizeof(struct SectionStackEntry))) != NULL) {
pSect->pSection = pCurrentSection;
pSect->pNext = pSectionStack;
pSectionStack = pSect;
} else
fatalerror("No memory for section stack");
}
void
out_PopSection(void)
{
if (pSectionStack) {
struct SectionStackEntry *pSect;
pSect = pSectionStack;
out_SetCurrentSection(pSect->pSection);
pSectionStack = pSect->pNext;
free(pSect);
} else
fatalerror("No entries in the section stack");
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Count the number of symbols used in this object
*
*/
ULONG
countsymbols(void)
{
struct PatchSymbol *pSym;
ULONG count = 0;
pSym = pPatchSymbols;
while (pSym) {
count += 1;
pSym = pSym->pNext;
}
return (count);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Count the number of sections used in this object
*
*/
ULONG
countsections(void)
{
struct Section *pSect;
ULONG count = 0;
pSect = pSectionList;
while (pSect) {
count += 1;
pSect = pSect->pNext;
}
return (count);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Count the number of patches used in this object
*
*/
ULONG
countpatches(struct Section * pSect)
{
struct Patch *pPatch;
ULONG r = 0;
pPatch = pSect->pPatches;
while (pPatch) {
r += 1;
pPatch = pPatch->pNext;
}
return (r);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write a long to a file (little-endian)
*
*/
void
fputlong(ULONG i, FILE * f)
{
fputc(i, f);
fputc(i >> 8, f);
fputc(i >> 16, f);
fputc(i >> 24, f);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write a NULL-terminated string to a file
*
*/
void
fputstring(char *s, FILE * f)
{
while (*s)
fputc(*s++, f);
fputc(0, f);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Return a sections ID
*
*/
ULONG
getsectid(struct Section * pSect)
{
struct Section *sec;
ULONG ID = 0;
sec = pSectionList;
while (sec) {
if (sec == pSect)
return (ID);
ID += 1;
sec = sec->pNext;
}
fatalerror("INTERNAL: Unknown section");
return ((ULONG) - 1);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write a patch to a file
*
*/
void
writepatch(struct Patch * pPatch, FILE * f)
{
fputstring(pPatch->tzFilename, f);
fputlong(pPatch->nLine, f);
fputlong(pPatch->nOffset, f);
fputc(pPatch->nType, f);
fputlong(pPatch->nRPNSize, f);
fwrite(pPatch->pRPN, 1, pPatch->nRPNSize, f);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write a section to a file
*
*/
void
writesection(struct Section * pSect, FILE * f)
{
//printf("SECTION: %s, ID: %d\n", pSect->pzName, getsectid(pSect));
fputlong(pSect->nPC, f);
fputc(pSect->nType, f);
fputlong(pSect->nOrg, f);
//RGB1 addition
fputlong(pSect->nBank, f);
//RGB1 addition
if ((pSect->nType == SECT_HOME)
|| (pSect->nType == SECT_CODE)) {
struct Patch *pPatch;
fwrite(pSect->tData, 1, pSect->nPC, f);
fputlong(countpatches(pSect), f);
pPatch = pSect->pPatches;
while (pPatch) {
writepatch(pPatch, f);
pPatch = pPatch->pNext;
}
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write a symbol to a file
*
*/
void
writesymbol(struct sSymbol * pSym, FILE * f)
{
char symname[MAXSYMLEN * 2 + 1];
ULONG type;
ULONG offset;
SLONG sectid;
if (pSym->nType & SYMF_IMPORT) {
/* Symbol should be imported */
strcpy(symname, pSym->tzName);
offset = 0;
sectid = -1;
type = SYM_IMPORT;
} else if (pSym->nType & SYMF_EXPORT) {
/* Symbol should be exported */
strcpy(symname, pSym->tzName);
type = SYM_EXPORT;
offset = pSym->nValue;
if (pSym->nType & SYMF_CONST)
sectid = -1;
else
sectid = getsectid(pSym->pSection);
} else {
/* Symbol is local to this file */
if (pSym->nType & SYMF_LOCAL) {
strcpy(symname, pSym->pScope->tzName);
strcat(symname, pSym->tzName);
} else
strcpy(symname, pSym->tzName);
type = SYM_LOCAL;
offset = pSym->nValue;
sectid = getsectid(pSym->pSection);
}
fputstring(symname, f);
fputc(type, f);
if (type != SYM_IMPORT) {
fputlong(sectid, f);
fputlong(offset, f);
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Add a symbol to the object
*
*/
ULONG
addsymbol(struct sSymbol * pSym)
{
struct PatchSymbol *pPSym, **ppPSym;
ULONG ID = 0;
pPSym = pPatchSymbols;
ppPSym = &(pPatchSymbols);
while (pPSym) {
if (pSym == pPSym->pSymbol)
return (pPSym->ID);
ppPSym = &(pPSym->pNext);
pPSym = pPSym->pNext;
ID += 1;
}
if ((*ppPSym = pPSym =
(struct PatchSymbol *) malloc(sizeof(struct PatchSymbol))) !=
NULL) {
pPSym->pNext = NULL;
pPSym->pSymbol = pSym;
pPSym->ID = ID;
return (ID);
} else
fatalerror("No memory for patchsymbol");
return ((ULONG) - 1);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Add all exported symbols to the object
*
*/
void
addexports(void)
{
int i;
for (i = 0; i < HASHSIZE; i += 1) {
struct sSymbol *pSym;
pSym = tHashedSymbols[i];
while (pSym) {
if (pSym->nType & SYMF_EXPORT)
addsymbol(pSym);
pSym = pSym->pNext;
}
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Allocate a new patchstructure and link it into the list
*
*/
struct Patch *
allocpatch(void)
{
struct Patch *pPatch, **ppPatch;
pPatch = pCurrentSection->pPatches;
ppPatch = &(pCurrentSection->pPatches);
while (pPatch) {
ppPatch = &(pPatch->pNext);
pPatch = pPatch->pNext;
}
if ((*ppPatch = pPatch =
(struct Patch *) malloc(sizeof(struct Patch))) != NULL) {
pPatch->pNext = NULL;
pPatch->nRPNSize = 0;
pPatch->pRPN = NULL;
} else
fatalerror("No memory for patch");
return (pPatch);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Create a new patch (includes the rpn expr)
*
*/
void
createpatch(ULONG type, struct Expression * expr)
{
struct Patch *pPatch;
UWORD rpndata;
UBYTE rpnexpr[2048];
char tzSym[512];
ULONG rpnptr = 0, symptr;
pPatch = allocpatch();
pPatch->nType = type;
strcpy(pPatch->tzFilename, tzCurrentFileName);
pPatch->nLine = nLineNo;
pPatch->nOffset = nPC;
while ((rpndata = rpn_PopByte(expr)) != 0xDEAD) {
switch (rpndata) {
case RPN_CONST:
rpnexpr[rpnptr++] = RPN_CONST;
rpnexpr[rpnptr++] = rpn_PopByte(expr);
rpnexpr[rpnptr++] = rpn_PopByte(expr);
rpnexpr[rpnptr++] = rpn_PopByte(expr);
rpnexpr[rpnptr++] = rpn_PopByte(expr);
break;
case RPN_SYM:
symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0);
if (sym_isConstant(tzSym)) {
ULONG value;
value = sym_GetConstantValue(tzSym);
rpnexpr[rpnptr++] = RPN_CONST;
rpnexpr[rpnptr++] = value & 0xFF;
rpnexpr[rpnptr++] = value >> 8;
rpnexpr[rpnptr++] = value >> 16;
rpnexpr[rpnptr++] = value >> 24;
} else {
symptr = addsymbol(sym_FindSymbol(tzSym));
rpnexpr[rpnptr++] = RPN_SYM;
rpnexpr[rpnptr++] = symptr & 0xFF;
rpnexpr[rpnptr++] = symptr >> 8;
rpnexpr[rpnptr++] = symptr >> 16;
rpnexpr[rpnptr++] = symptr >> 24;
}
break;
case RPN_BANK:
symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0);
symptr = addsymbol(sym_FindSymbol(tzSym));
rpnexpr[rpnptr++] = RPN_BANK;
rpnexpr[rpnptr++] = symptr & 0xFF;
rpnexpr[rpnptr++] = symptr >> 8;
rpnexpr[rpnptr++] = symptr >> 16;
rpnexpr[rpnptr++] = symptr >> 24;
break;
default:
rpnexpr[rpnptr++] = rpndata;
break;
}
}
if ((pPatch->pRPN = (UBYTE *) malloc(rpnptr)) != NULL) {
memcpy(pPatch->pRPN, rpnexpr, rpnptr);
pPatch->nRPNSize = rpnptr;
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* A quick check to see if we have an initialized section
*
*/
void
checksection(void)
{
if (pCurrentSection)
return;
else
fatalerror("Code generation before SECTION directive");
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* A quick check to see if we have an initialized section that can contain
* this much initialized data
*
*/
void
checkcodesection(SLONG size)
{
checksection();
if ((pCurrentSection->nType == SECT_HOME
|| pCurrentSection->nType == SECT_CODE)
&& (pCurrentSection->nPC + size <= MAXSECTIONSIZE)) {
if (((pCurrentSection->nPC % SECTIONCHUNK) >
((pCurrentSection->nPC + size) % SECTIONCHUNK))
&& (pCurrentSection->nType == SECT_HOME
|| pCurrentSection->nType == SECT_CODE)) {
if ((pCurrentSection->tData =
(UBYTE *) realloc(pCurrentSection->tData,
((pCurrentSection->nPC +
size) / SECTIONCHUNK +
1) * SECTIONCHUNK)) != NULL) {
return;
} else
fatalerror
("Not enough memory to expand section");
}
return;
} else
fatalerror
("Section can't contain initialized data or section limit exceeded");
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Write an objectfile
*
*/
void
out_WriteObject(void)
{
FILE *f;
addexports();
if ((f = fopen(tzObjectname, "wb")) != NULL) {
struct PatchSymbol *pSym;
struct Section *pSect;
fwrite("RGB2", 1, 4, f);
fputlong(countsymbols(), f);
fputlong(countsections(), f);
pSym = pPatchSymbols;
while (pSym) {
writesymbol(pSym->pSymbol, f);
pSym = pSym->pNext;
}
pSect = pSectionList;
while (pSect) {
writesection(pSect, f);
pSect = pSect->pNext;
}
fclose(f);
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Prepare for pass #2
*
*/
void
out_PrepPass2(void)
{
struct Section *pSect;
pSect = pSectionList;
while (pSect) {
pSect->nPC = 0;
pSect = pSect->pNext;
}
pCurrentSection = NULL;
pSectionStack = NULL;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Set the objectfilename
*
*/
void
out_SetFileName(char *s)
{
strcpy(tzObjectname, s);
printf("Output filename %s\n", s);
pSectionList = NULL;
pCurrentSection = NULL;
pPatchSymbols = NULL;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Find a section by name and type. If it doesn't exist, create it
*
*/
struct Section *
out_FindSection(char *pzName, ULONG secttype, SLONG org,
SLONG bank)
{
struct Section *pSect, **ppSect;
ppSect = &pSectionList;
pSect = pSectionList;
while (pSect) {
if (strcmp(pzName, pSect->pzName) == 0) {
if (secttype == pSect->nType
&& ((ULONG) org) == pSect->nOrg
&& ((ULONG) bank) == pSect->nBank) {
return (pSect);
} else
fatalerror
("Section already exists but with a different type");
}
ppSect = &(pSect->pNext);
pSect = pSect->pNext;
}
if ((*ppSect =
(pSect =
(struct Section *) malloc(sizeof(struct Section)))) != NULL) {
if ((pSect->pzName =
(char *) malloc(strlen(pzName) + 1)) != NULL) {
strcpy(pSect->pzName, pzName);
pSect->nType = secttype;
pSect->nPC = 0;
pSect->nOrg = org;
pSect->nBank = bank;
pSect->pNext = NULL;
pSect->pPatches = NULL;
pPatchSymbols = NULL;
if ((pSect->tData =
(UBYTE *) malloc(SECTIONCHUNK)) != NULL) {
return (pSect);
} else
fatalerror("Not enough memory for section");
} else
fatalerror("Not enough memory for sectionname");
} else
fatalerror("Not enough memory for section");
return (NULL);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Set the current section
*
*/
void
out_SetCurrentSection(struct Section * pSect)
{
pCurrentSection = pSect;
nPC = pSect->nPC;
pPCSymbol->nValue = nPC;
pPCSymbol->pSection = pCurrentSection;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Set the current section by name and type
*
*/
void
out_NewSection(char *pzName, ULONG secttype)
{
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1));
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Set the current section by name and type
*
*/
void
out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank)
{
out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank));
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output an absolute byte
*
*/
void
out_AbsByte(int b)
{
checkcodesection(1);
b &= 0xFF;
if (nPass == 2)
pCurrentSection->tData[nPC] = b;
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Skip this many bytes
*
*/
void
out_Skip(int skip)
{
checksection();
if ((CurrentOptions.fillchar == -1)
|| !((pCurrentSection->nType == SECT_HOME)
|| (pCurrentSection->nType == SECT_CODE))) {
pCurrentSection->nPC += skip;
nPC += skip;
pPCSymbol->nValue += skip;
} else {
checkcodesection(skip);
while (skip--)
out_AbsByte(CurrentOptions.fillchar);
}
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a NULL terminated string (excluding the NULL-character)
*
*/
void
out_String(char *s)
{
checkcodesection(strlen(s));
while (*s)
out_AbsByte(*s++);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise.
*
*/
void
out_RelByte(struct Expression * expr)
{
checkcodesection(1);
if (rpn_isReloc(expr)) {
if (nPass == 2) {
pCurrentSection->tData[nPC] = 0;
createpatch(PATCH_BYTE, expr);
}
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
} else
out_AbsByte(expr->nVal);
rpn_Reset(expr);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output an absolute word
*
*/
void
out_AbsWord(int b)
{
checkcodesection(2);
b &= 0xFFFF;
if (nPass == 2) {
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8;
} else {
//Assume big endian
pCurrentSection->tData[nPC] = b >> 8;
pCurrentSection->tData[nPC + 1] = b & 0xFF;
}
}
pCurrentSection->nPC += 2;
nPC += 2;
pPCSymbol->nValue += 2;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a relocatable word. Checking will be done to see if
* is an absolute value in disguise.
*
*/
void
out_RelWord(struct Expression * expr)
{
ULONG b;
checkcodesection(2);
b = expr->nVal & 0xFFFF;
if (rpn_isReloc(expr)) {
if (nPass == 2) {
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8;
createpatch(PATCH_WORD_L, expr);
} else {
//Assume big endian
pCurrentSection->tData[nPC] = b >> 8;
pCurrentSection->tData[nPC + 1] = b & 0xFF;
createpatch(PATCH_WORD_B, expr);
}
}
pCurrentSection->nPC += 2;
nPC += 2;
pPCSymbol->nValue += 2;
} else
out_AbsWord(expr->nVal);
rpn_Reset(expr);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output an absolute longword
*
*/
void
out_AbsLong(SLONG b)
{
checkcodesection(sizeof(SLONG));
if (nPass == 2) {
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8;
pCurrentSection->tData[nPC + 2] = b >> 16;
pCurrentSection->tData[nPC + 3] = b >> 24;
} else {
//Assume big endian
pCurrentSection->tData[nPC] = b >> 24;
pCurrentSection->tData[nPC + 1] = b >> 16;
pCurrentSection->tData[nPC + 2] = b >> 8;
pCurrentSection->tData[nPC + 3] = b & 0xFF;
}
}
pCurrentSection->nPC += 4;
nPC += 4;
pPCSymbol->nValue += 4;
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a relocatable longword. Checking will be done to see if
* is an absolute value in disguise.
*
*/
void
out_RelLong(struct Expression * expr)
{
SLONG b;
checkcodesection(4);
b = expr->nVal;
if (rpn_isReloc(expr)) {
if (nPass == 2) {
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8;
pCurrentSection->tData[nPC + 2] = b >> 16;
pCurrentSection->tData[nPC + 3] = b >> 24;
createpatch(PATCH_LONG_L, expr);
} else {
//Assume big endian
pCurrentSection->tData[nPC] = b >> 24;
pCurrentSection->tData[nPC + 1] = b >> 16;
pCurrentSection->tData[nPC + 2] = b >> 8;
pCurrentSection->tData[nPC + 3] = b & 0xFF;
createpatch(PATCH_LONG_B, expr);
}
}
pCurrentSection->nPC += 4;
nPC += 4;
pPCSymbol->nValue += 4;
} else
out_AbsLong(expr->nVal);
rpn_Reset(expr);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a PC-relative byte
*
*/
void
out_PCRelByte(struct Expression * expr)
{
SLONG b = expr->nVal;
checkcodesection(1);
b = (b & 0xFFFF) - (nPC + 1);
if (nPass == 2 && (b < -128 || b > 127))
yyerror("PC-relative value must be 8-bit");
out_AbsByte(b);
rpn_Reset(expr);
}
/*
* RGBAsm - OUTPUT.C - Outputs an objectfile
*
* Output a binary file
*
*/
void
out_BinaryFile(char *s)
{
FILE *f;
fstk_FindFile(s);
if ((f = fopen(s, "rb")) != NULL) {
SLONG fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
checkcodesection(fsize);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = fsize;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += fsize;
nPC += fsize;
pPCSymbol->nValue += fsize;
fclose(f);
} else
fatalerror("File not found");
}
void
out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
{
FILE *f;
if (start_pos < 0)
fatalerror("Start position cannot be negative");
if (length < 0)
fatalerror("Number of bytes to read must be greater than zero");
fstk_FindFile(s);
if ((f = fopen(s, "rb")) != NULL) {
SLONG fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
if (start_pos >= fsize)
fatalerror("Specified start position is greater than length of file");
if ((start_pos + length) > fsize)
fatalerror("Specified range in INCBIN is out of bounds");
fseek(f, start_pos, SEEK_SET);
checkcodesection(length);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = length;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
}
pCurrentSection->nPC += length;
nPC += length;
pPCSymbol->nValue += length;
fclose(f);
} else
fatalerror("File not found");
}