329 lines
7.7 KiB
C++
329 lines
7.7 KiB
C++
#pragma once
|
|
|
|
#include "MachineTypes.h"
|
|
#include "Ident.h"
|
|
#include "Array.h"
|
|
#include "Errors.h"
|
|
#include "Disassembler.h"
|
|
#include "DiskImage.h"
|
|
#include "CompilerTypes.h"
|
|
|
|
class InterCodeProcedure;
|
|
class InterVariable;
|
|
class NativeCodeProcedure;
|
|
|
|
enum LinkerObjectType
|
|
{
|
|
LOT_NONE,
|
|
LOT_PAD,
|
|
LOT_BASIC,
|
|
LOT_BYTE_CODE,
|
|
LOT_NATIVE_CODE,
|
|
LOT_RUNTIME,
|
|
LOT_DATA,
|
|
LOT_BSS,
|
|
LOT_HEAP,
|
|
LOT_STACK,
|
|
LOT_INLAY,
|
|
LOT_SECTION_START,
|
|
LOT_SECTION_END
|
|
};
|
|
|
|
enum LinkerSectionType
|
|
{
|
|
LST_NONE,
|
|
LST_DATA,
|
|
LST_BSS,
|
|
LST_HEAP,
|
|
LST_STACK,
|
|
LST_STATIC_STACK,
|
|
LST_ZEROPAGE
|
|
|
|
};
|
|
|
|
struct ZeroPageSet
|
|
{
|
|
ZeroPageSet(void)
|
|
{
|
|
for (int i = 0; i < 8; i++)
|
|
mBits[i] = 0;
|
|
}
|
|
|
|
uint32 mBits[8];
|
|
|
|
void operator += (int n)
|
|
{
|
|
mBits[n >> 5] |= 1 << (n & 31);
|
|
}
|
|
|
|
void operator -= (int n)
|
|
{
|
|
mBits[n >> 5] &= ~(1 << (n & 31));
|
|
}
|
|
|
|
bool operator[] (int n) const
|
|
{
|
|
return (mBits[n >> 5] & (1 << (n & 31))) != 0;
|
|
}
|
|
|
|
ZeroPageSet& operator |= (const ZeroPageSet& set)
|
|
{
|
|
for (int i = 0; i < 8; i++)
|
|
mBits[i] |= set.mBits[i];
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
class LinkerObject;
|
|
class LinkerSection;
|
|
|
|
class LinkerRegion
|
|
{
|
|
public:
|
|
const Ident* mIdent;
|
|
|
|
uint32 mFlags;
|
|
int mStart, mEnd, mUsed, mNonzero, mReloc;
|
|
uint64 mCartridgeBanks;
|
|
LinkerObject * mInlayObject;
|
|
|
|
GrowingArray<LinkerSection*> mSections;
|
|
|
|
LinkerRegion(void);
|
|
|
|
struct FreeChunk
|
|
{
|
|
int mStart, mEnd;
|
|
LinkerObject* mLastObject;
|
|
};
|
|
|
|
GrowingArray<FreeChunk> mFreeChunks;
|
|
LinkerObject * mLastObject;
|
|
|
|
bool AllocateAppend(Linker* linker, LinkerObject* obj);
|
|
bool Allocate(Linker * linker, LinkerObject* obj, bool merge, bool retry);
|
|
void PlaceStackSection(LinkerSection* stackSection, LinkerSection* section);
|
|
};
|
|
|
|
static const uint32 LREF_LOWBYTE = 0x00000001;
|
|
static const uint32 LREF_HIGHBYTE = 0x00000002;
|
|
static const uint32 LREF_TEMPORARY = 0x00000004;
|
|
static const uint32 LREF_INBLOCK = 0x00000008;
|
|
static const uint32 LREF_LOWBYTE_OFFSET = 0x00000010;
|
|
static const uint32 LREF_BREAKPOINT = 0x00000020;
|
|
|
|
class LinkerReference
|
|
{
|
|
public:
|
|
LinkerObject* mObject, * mRefObject;
|
|
int mOffset, mRefOffset;
|
|
uint32 mFlags;
|
|
|
|
bool operator==(const LinkerReference& ref);
|
|
bool operator!=(const LinkerReference& ref);
|
|
|
|
};
|
|
|
|
static const uint32 LSECF_PACKED = 0x00000001;
|
|
static const uint32 LSECF_PLACED = 0x00000002;
|
|
|
|
class LinkerSection
|
|
{
|
|
public:
|
|
const Ident* mIdent;
|
|
|
|
GrowingArray <LinkerObject*> mObjects;
|
|
GrowingArray <LinkerSection*> mSections;
|
|
|
|
int mStart, mEnd, mSize;
|
|
LinkerSectionType mType;
|
|
uint32 mFlags;
|
|
|
|
LinkerSection(void);
|
|
|
|
void RemObject(LinkerObject* obj);
|
|
void AddObject(LinkerObject* obj);
|
|
};
|
|
|
|
static const uint32 LOBJF_REFERENCED = 0x00000001;
|
|
static const uint32 LOBJF_PLACED = 0x00000002;
|
|
static const uint32 LOBJF_NO_FRAME = 0x00000004;
|
|
static const uint32 LOBJF_INLINE = 0x00000008;
|
|
static const uint32 LOBJF_CONST = 0x00000010;
|
|
static const uint32 LOBJF_RELEVANT = 0x00000020;
|
|
static const uint32 LOBJF_STATIC_STACK = 0x00000040;
|
|
static const uint32 LOBJF_NO_CROSS = 0x00000080;
|
|
static const uint32 LOBJF_ZEROPAGE = 0x00000100;
|
|
static const uint32 LOBJF_FORCE_ALIGN = 0x00000200;
|
|
static const uint32 LOBJF_ZEROPAGESET = 0x00000400;
|
|
|
|
static const uint32 LOBJF_ARG_REG_A = 0x00001000;
|
|
static const uint32 LOBJF_ARG_REG_X = 0x00002000;
|
|
static const uint32 LOBJF_ARG_REG_Y = 0x00004000;
|
|
|
|
static const uint32 LOBJF_RET_REG_A = 0x00010000;
|
|
static const uint32 LOBJF_RET_REG_X = 0x00020000;
|
|
|
|
static const uint32 LOBJF_LOCAL_VAR = 0x00100000;
|
|
static const uint32 LOBJF_LOCAL_USED = 0x00200000;
|
|
|
|
class LinkerObjectRange
|
|
{
|
|
public:
|
|
const Ident * mIdent;
|
|
int mOffset, mSize;
|
|
};
|
|
|
|
struct CodeLocation
|
|
{
|
|
Location mLocation;
|
|
int mStart, mEnd;
|
|
bool mWeak;
|
|
};
|
|
|
|
|
|
class LinkerObject
|
|
{
|
|
public:
|
|
Location mLocation;
|
|
const Ident * mIdent, * mFullIdent;
|
|
LinkerObjectType mType;
|
|
int mID, mMapID;
|
|
int mAddress, mRefAddress;
|
|
int mSize, mAlignment, mStripe, mStartUsed, mEndUsed;
|
|
LinkerSection * mSection;
|
|
LinkerRegion * mRegion;
|
|
uint8 * mData, * mMemory;
|
|
InterCodeProcedure * mProc;
|
|
NativeCodeProcedure * mNativeProc;
|
|
InterVariable * mVariable;
|
|
uint32 mFlags;
|
|
uint8 mTemporaries[16], mTempSizes[16];
|
|
int mNumTemporaries;
|
|
ZeroPageSet mZeroPageSet;
|
|
LinkerSection * mStackSection;
|
|
LinkerObject * mPrefix, * mSuffix;
|
|
int mSuffixReference;
|
|
|
|
ExpandingArray<LinkerObjectRange> mRanges;
|
|
ExpandingArray<CodeLocation> mCodeLocations;
|
|
ExpandingArray<LinkerObjectRange> mZeroPageRanges;
|
|
|
|
LinkerObject(void);
|
|
~LinkerObject(void);
|
|
|
|
LinkerObject* CloneAssembler(Linker * linker) const;
|
|
|
|
void AddData(const uint8* data, int size);
|
|
void AddLocations(const ExpandingArray<CodeLocation>& locations);
|
|
uint8* AddSpace(int size);
|
|
void EnsureSpace(int offset, int size);
|
|
|
|
GrowingArray<LinkerReference*> mReferences;
|
|
|
|
LinkerReference* FindReference(int64 offset);
|
|
|
|
void AddReference(const LinkerReference& ref);
|
|
|
|
void MoveToSection(LinkerSection* section);
|
|
|
|
void MarkRelevant(void);
|
|
|
|
bool IsSameConst(const LinkerObject* obj) const;
|
|
|
|
bool IsBefore(const LinkerObject* obj) const;
|
|
int FirstBank(void) const;
|
|
};
|
|
|
|
class LinkerOverlay
|
|
{
|
|
public:
|
|
LinkerOverlay(void);
|
|
~LinkerOverlay(void);
|
|
|
|
Location mLocation;
|
|
const Ident * mIdent;
|
|
int mBank;
|
|
};
|
|
|
|
class Linker
|
|
{
|
|
public:
|
|
Linker(Errors * errors);
|
|
~Linker(void);
|
|
|
|
LinkerRegion * AddRegion(const Ident* region, int start, int end);
|
|
LinkerRegion* FindRegion(const Ident* region);
|
|
|
|
LinkerSection * AddSection(const Ident* section, LinkerSectionType type);
|
|
LinkerSection* FindSection(const Ident* section);
|
|
|
|
LinkerRegion* FindRegionOfSection(LinkerSection* section);
|
|
|
|
LinkerObject* FindObjectByAddr(int addr);
|
|
LinkerObject* FindObjectByAddr(int bank, int addr);
|
|
|
|
bool IsSectionPlaced(LinkerSection* section);
|
|
|
|
LinkerObject * AddObject(const Location & location, const Ident* ident, LinkerSection * section, LinkerObjectType type, int alignment = 1);
|
|
LinkerObject* FindSame(LinkerObject* obj);
|
|
|
|
LinkerOverlay* AddOverlay(const Location& location, const Ident* ident, int bank);
|
|
|
|
void SortObjects(void);
|
|
|
|
// void AddReference(const LinkerReference& ref);
|
|
|
|
bool WritePrgFile(DiskImage * image, const char* filename);
|
|
bool WritePrgFile(const char* filename, const char * pathname);
|
|
bool WriteXexFile(const char* filename);
|
|
bool WriteMapFile(const char* filename);
|
|
bool WriteAsmFile(const char* filename, const char * version);
|
|
bool WriteLblFile(const char* filename);
|
|
bool WriteCrtFile(const char* filename, uint16 id);
|
|
bool WriteBinFile(const char* filename);
|
|
bool WriteNesFile(const char* filename, TargetMachine machine);
|
|
bool WriteMlbFile(const char* filename, TargetMachine machine);
|
|
bool WriteDbjFile(FILE * file);
|
|
|
|
int TranslateMlbAddress(int address, int bank, TargetMachine machine);
|
|
|
|
uint64 mCompilerOptions;
|
|
|
|
GrowingArray<LinkerReference*> mReferences;
|
|
GrowingArray<LinkerRegion*> mRegions;
|
|
GrowingArray<LinkerSection*> mSections;
|
|
GrowingArray<LinkerObject*> mObjects;
|
|
GrowingArray<LinkerOverlay*> mOverlays;
|
|
GrowingArray<uint32> mBreakpoints;
|
|
|
|
uint8 mMemory[0x10000], mWorkspace[0x10000];
|
|
uint8 mCartridge[64][0x10000];
|
|
|
|
bool mCartridgeBankUsed[64];
|
|
|
|
int mCartridgeBankStart[64], mCartridgeBankEnd[64];
|
|
|
|
int mProgramStart, mProgramEnd;
|
|
|
|
void ReferenceObject(LinkerObject* obj);
|
|
|
|
void CheckDirectJumps(void);
|
|
void CollectReferences(void);
|
|
void CombineSameConst(void);
|
|
void InlineSimpleJumps(void);
|
|
void PatchReferences(bool inlays);
|
|
void CopyObjects(bool inlays);
|
|
void PlaceObjects(bool retry);
|
|
void Link(void);
|
|
void CollectBreakpoints(void);
|
|
protected:
|
|
NativeCodeDisassembler mNativeDisassembler;
|
|
ByteCodeDisassembler mByteCodeDisassembler;
|
|
|
|
bool Forwards(LinkerObject* pobj, LinkerObject* lobj);
|
|
void SortObjectsPartition(int l, int r);
|
|
|
|
Errors* mErrors;
|
|
};
|