oscar64/oscar64/Linker.h

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;
};