X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fobjcode.c;h=d1ab4f6bd781cf3fbb31a56fd3681e320c2a74b4;hb=aa4a7735d7e29defcef036b45e68e4fb7a4ddf91;hp=a231b289ba3101447bcb70440431eb143608f667;hpb=bfbedfa54b98d059c62f82609a0966f4acddd174;p=cc65 diff --git a/src/ca65/objcode.c b/src/ca65/objcode.c index a231b289b..d1ab4f6bd 100644 --- a/src/ca65/objcode.c +++ b/src/ca65/objcode.c @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* objcode.c */ +/* objcode.c */ /* */ -/* Objectcode management for the ca65 macroassembler */ +/* Objectcode management for the ca65 macroassembler */ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@cc65.org */ +/* (C) 1998-2011, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -36,639 +36,90 @@ #include #include -/* common */ -#include "chartype.h" -#include "check.h" -#include "segdefs.h" -#include "xmalloc.h" - /* cc65 */ #include "error.h" #include "fragment.h" -#include "global.h" -#include "lineinfo.h" -#include "listing.h" -#include "objfile.h" -#include "scanner.h" -#include "symtab.h" #include "objcode.h" +#include "segment.h" /*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Are we in absolute mode or in relocatable mode? */ -int RelocMode = 1; -unsigned long AbsPC = 0; /* PC if in absolute mode */ - - - -typedef struct Segment_ Segment; -struct Segment_ { - Segment* List; /* List of all segments */ - Fragment* Root; /* Root of fragment list */ - Fragment* Last; /* Pointer to last fragment */ - unsigned char Align; /* Segment alignment */ - unsigned char SegType; /* True if zero page segment */ - unsigned long PC; - unsigned Num; /* Segment number */ - char* Name; /* Segment name */ -}; - - - -/* Predefined segments */ -static Segment NullSeg = { - 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL" -}; -static Segment ZeropageSeg = { - &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE" -}; -static Segment DataSeg = { - &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA" -}; -static Segment BssSeg = { - &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS" -}; -static Segment RODataSeg = { - &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA" -}; -static Segment CodeSeg = { - &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE" -}; - -/* Number of segments */ -static unsigned SegmentCount = 6; - -/* List of all segments */ -static Segment* SegmentList = &CodeSeg; -static Segment* SegmentLast = &NullSeg; - -/* Currently active segment */ -static Segment* ActiveSeg = &CodeSeg; - - - -/*****************************************************************************/ -/* Segment management */ +/* Code */ /*****************************************************************************/ -static Segment* NewSegment (const char* Name, unsigned SegType) -/* Create a new segment, insert it into the global list and return it */ -{ - Segment* S; - const char* N; - - /* Check for too many segments */ - if (SegmentCount >= 256) { - Fatal (FAT_TOO_MANY_SEGMENTS); - } - - /* Check the segment name for invalid names */ - N = Name; - if ((*N != '_' && !IsAlpha (*N)) || strlen (Name) > 80) { - Error (ERR_ILLEGAL_SEGMENT, Name); - } - do { - if (*N != '_' && !IsAlNum (*N)) { - Error (ERR_ILLEGAL_SEGMENT, Name); - break; - } - ++N; - } while (*N); - - /* Create a new segment */ - S = xmalloc (sizeof (*S)); - - /* Initialize it */ - S->List = 0; - S->Root = 0; - S->Last = 0; - S->Align = 0; - S->SegType = SegType; - S->PC = 0; - S->Num = SegmentCount++; - S->Name = xstrdup (Name); - - /* Insert it into the segment list */ - SegmentLast->List = S; - SegmentLast = S; - - /* And return it... */ - return S; -} - - - -void UseCodeSeg (void) -/* Use the code segment */ -{ - ActiveSeg = &CodeSeg; -} - - - -void UseRODataSeg (void) -/* Use the r/o data segment */ -{ - ActiveSeg = &RODataSeg; -} - - - -void UseDataSeg (void) -/* Use the data segment */ -{ - ActiveSeg = &DataSeg; -} - - - -void UseBssSeg (void) -/* Use the BSS segment */ -{ - ActiveSeg = &BssSeg; -} - - - -void UseZeropageSeg (void) -/* Use the zero page segment */ -{ - ActiveSeg = &ZeropageSeg; -} - - - -void UseNullSeg (void) -/* Use the null segment */ -{ - ActiveSeg = &NullSeg; -} - - - -void UseSeg (const char* Name, unsigned SegType) -/* Use the segment with the given name */ -{ - Segment* Seg = SegmentList; - while (Seg) { - if (strcmp (Seg->Name, Name) == 0) { - /* We found this segment. Check if the type is identical */ - if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) { - Error (ERR_SEG_ATTR_MISMATCH); - /* Use the new attribute to avoid errors */ - Seg->SegType = SegType; - } - ActiveSeg = Seg; - return; - } - /* Check next segment */ - Seg = Seg->List; - } - - /* Segment is not in list, create a new one */ - if (SegType == SEGTYPE_DEFAULT) { - SegType = SEGTYPE_ABS; - } - Seg = NewSegment (Name, SegType); - ActiveSeg = Seg; -} - - - -unsigned long GetPC (void) -/* Get the program counter of the current segment */ +void Emit0 (unsigned char OPC) +/* Emit an instruction with a zero sized operand */ { - return RelocMode? ActiveSeg->PC : AbsPC; + Fragment* F = GenFragment (FRAG_LITERAL, 1); + F->V.Data[0] = OPC; } -void SetAbsPC (unsigned long PC) -/* Set the program counter in absolute mode */ +void Emit1 (unsigned char OPC, ExprNode* Value) +/* Emit an instruction with an one byte argument */ { - RelocMode = 0; - AbsPC = PC; -} - - + long V; + Fragment* F; -unsigned GetSegNum (void) -/* Get the number of the current segment */ -{ - return ActiveSeg->Num; -} + if (IsEasyConst (Value, &V)) { + /* Must be in byte range */ + if (!IsByteRange (V)) { + Error ("Range error (%ld not in [0..255])", V); + } + /* Create a literal fragment */ + F = GenFragment (FRAG_LITERAL, 2); + F->V.Data[0] = OPC; + F->V.Data[1] = (unsigned char) V; + FreeExpr (Value); -void SegAlign (unsigned Power, int Val) -/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the - * actual fill value will be determined by the linker), otherwise use the - * given value. - */ -{ - unsigned char Data [4]; - unsigned long Align = (1UL << Power) - 1; - unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align; - unsigned long Count = NewPC - ActiveSeg->PC; - - if (Val != -1) { - /* User defined fill value */ - memset (Data, Val, sizeof (Data)); - while (Count) { - if (Count > sizeof (Data)) { - EmitData (Data, sizeof (Data)); - Count -= sizeof (Data); - } else { - EmitData (Data, Count); - Count = 0; - } - } } else { - /* Linker defined fill value */ - EmitFill (Count); - } - - /* Remember the alignment in the header */ - if (ActiveSeg->Align < Power) { - ActiveSeg->Align = Power; - } -} - - - -int IsZPSeg (void) -/* Return true if the current segment is a zeropage segment */ -{ - return (ActiveSeg->SegType == SEGTYPE_ZP); -} - - - -int IsFarSeg (void) -/* Return true if the current segment is a far segment */ -{ - return (ActiveSeg->SegType == SEGTYPE_FAR); -} + /* Emit the opcode */ + Emit0 (OPC); - -unsigned GetSegType (unsigned SegNum) -/* Return the type of the segment with the given number */ -{ - /* Search for the segment */ - Segment* S = SegmentList; - while (S && SegNum) { - --SegNum; - S = S->List; - } - - /* Did we find it? */ - if (S == 0) { - FAIL ("Invalid segment number"); + /* Emit the argument as an expression */ + F = GenFragment (FRAG_EXPR, 1); + F->V.Expr = Value; } - - /* Return the segment type */ - return S->SegType; } -void SegCheck (void) -/* Check the segments for range and other errors */ -{ - Segment* S = SegmentList; - while (S) { - Fragment* F = S->Root; - while (F) { - if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) { - F->V.Expr = FinalizeExpr (F->V.Expr); - if (IsConstExpr (F->V.Expr)) { - /* We are able to evaluate the expression. Get the value - * and check for range errors. - */ - unsigned I; - long Val = GetExprVal (F->V.Expr); - int Abs = (F->Type != FRAG_SEXPR); - - if (F->Len == 1) { - if (Abs) { - /* Absolute value */ - if (Val > 255) { - PError (&F->Pos, ERR_RANGE); - } - } else { - /* PC relative value */ - if (Val < -128 || Val > 127) { - PError (&F->Pos, ERR_RANGE); - } - } - } else if (F->Len == 2) { - if (Abs) { - /* Absolute value */ - if (Val > 65535) { - PError (&F->Pos, ERR_RANGE); - } - } else { - /* PC relative value */ - if (Val < -32768 || Val > 32767) { - PError (&F->Pos, ERR_RANGE); - } - } - } - - /* Convert the fragment into a literal fragment */ - for (I = 0; I < F->Len; ++I) { - F->V.Data [I] = Val & 0xFF; - Val >>= 8; - } - F->Type = FRAG_LITERAL; - } else { - /* We cannot evaluate the expression now, leave the job for - * the linker. However, we are able to check for explicit - * byte expressions and we will do so. - */ - if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) { - PError (&F->Pos, ERR_RANGE); - } - } - } - F = F->Next; - } - S = S->List; - } -} - - - -void SegDump (void) -/* Dump the contents of all segments */ -{ - unsigned X = 0; - Segment* S = SegmentList; - printf ("\n"); - while (S) { - unsigned I; - Fragment* F; - int State = -1; - printf ("New segment: %s", S->Name); - F = S->Root; - while (F) { - if (F->Type == FRAG_LITERAL) { - if (State != 0) { - printf ("\n Literal:"); - X = 15; - State = 0; - } - for (I = 0; I < F->Len; ++I) { - printf (" %02X", F->V.Data [I]); - X += 3; - } - } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) { - State = 1; - printf ("\n Expression (%u): ", F->Len); - DumpExpr (F->V.Expr); - } else if (F->Type == FRAG_FILL) { - State = 1; - printf ("\n Fill bytes (%u)", F->Len); - } else { - Internal ("Unknown fragment type: %u", F->Type); - } - if (X > 65) { - State = -1; - } - F = F->Next; - } - printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF)); - S = S->List; - } - printf ("\n"); -} - - - -static void WriteOneSeg (Segment* Seg) -/* Write one segment to the object file */ +void Emit2 (unsigned char OPC, ExprNode* Value) +/* Emit an instruction with a two byte argument */ { - Fragment* Frag; + long V; Fragment* F; - unsigned long Size; - unsigned LineInfoIndex; - - /* Write the segment name followed by the byte count in this segment */ - ObjWriteStr (Seg->Name); - ObjWrite32 (Seg->PC); - ObjWrite8 (Seg->Align); - ObjWrite8 (Seg->SegType); - - /* Now walk through the fragment list for this segment and write the - * fragments. - */ - Frag = Seg->Root; - while (Frag) { - - /* Write data depending on the type */ - switch (Frag->Type) { - - case FRAG_LITERAL: - /* To make the object file somewhat smaller, write all literal - * data of this and the following fragments preceeded by the - * length. - */ - F = Frag; - Size = 0; - while (F && F->Type == FRAG_LITERAL) { - Size += F->Len; - F = F->Next; - } - ObjWrite8 (FRAG_LITERAL); - ObjWriteVar (Size); - - /* Now write the literal data */ - F = Frag; - while (F && F->Type == FRAG_LITERAL) { - ObjWriteData (F->V.Data, F->Len); - Frag = F; - F = F->Next; - } - break; - - case FRAG_EXPR: - switch (Frag->Len) { - case 1: ObjWrite8 (FRAG_EXPR8); break; - case 2: ObjWrite8 (FRAG_EXPR16); break; - case 3: ObjWrite8 (FRAG_EXPR24); break; - case 4: ObjWrite8 (FRAG_EXPR32); break; - default: Internal ("Invalid fragment size: %u", Frag->Len); - } - WriteExpr (Frag->V.Expr); - break; - - case FRAG_SEXPR: - switch (Frag->Len) { - case 1: ObjWrite8 (FRAG_SEXPR8); break; - case 2: ObjWrite8 (FRAG_SEXPR16); break; - case 3: ObjWrite8 (FRAG_SEXPR24); break; - case 4: ObjWrite8 (FRAG_SEXPR32); break; - default: Internal ("Invalid fragment size: %u", Frag->Len); - } - WriteExpr (Frag->V.Expr); - break; - - case FRAG_FILL: - ObjWrite8 (FRAG_FILL); - ObjWriteVar (Frag->Len); - break; - - default: - Internal ("Invalid fragment type: %u", Frag->Type); - - } - - /* Write the file position of this fragment */ - ObjWritePos (&Frag->Pos); - - /* Write extra line info for this fragment. Zero is considered - * "no line info", so add one to the value. - */ - LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0; - ObjWriteVar (LineInfoIndex); - - /* Next fragment */ - Frag = Frag->Next; - } -} - - - -void WriteSegments (void) -/* Write the segment data to the object file */ -{ - Segment* Seg; - - /* Tell the object file module that we're about to start the seg list */ - ObjStartSegments (); - - /* First thing is segment count */ - ObjWriteVar (SegmentCount); - - /* Now walk through all segments and write them to the object file */ - Seg = SegmentList; - while (Seg) { - /* Write one segment */ - WriteOneSeg (Seg); - /* Next segment */ - Seg = Seg->List; - } - - /* Done writing segments */ - ObjEndSegments (); -} - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -static void IncPC (unsigned Value) -/* Increment the PC counter */ -{ - ActiveSeg->PC += Value; - if (!RelocMode) { - AbsPC += Value; - } -} + if (IsEasyConst (Value, &V)) { + /* Must be in byte range */ + if (!IsWordRange (V)) { + Error ("Range error (%ld not in [0..65535])", V); + } -static Fragment* NewFragment (unsigned char Type, unsigned short Len) -/* Create, initialize and return a new fragment. The fragment will be inserted - * into the current segment. - */ -{ - Fragment* F; + /* Create a literal fragment */ + F = GenFragment (FRAG_LITERAL, 3); + F->V.Data[0] = OPC; + F->V.Data[1] = (unsigned char) V; + F->V.Data[2] = (unsigned char) (V >> 8); + FreeExpr (Value); - /* Create a new fragment */ - F = xmalloc (sizeof (*F)); - - /* Initialize it */ - F->List = 0; - F->Next = 0; - F->LineList = 0; - F->Pos = CurPos; - F->LI = UseLineInfo (CurLineInfo); - F->Len = Len; - F->Type = Type; - - /* Insert it into the list of all segments */ - if (FragList == 0) { - FragList = F; } else { - FragLast->List = F; - } - FragLast = F; - /* Insert it into the current segment */ - if (ActiveSeg->Root) { - ActiveSeg->Last->Next = F; - ActiveSeg->Last = F; - } else { - ActiveSeg->Root = ActiveSeg->Last = F; - } + /* Emit the opcode */ + Emit0 (OPC); - /* Add this fragment to the current listing line */ - if (LineCur) { - if (LineCur->FragList == 0) { - LineCur->FragList = F; - } else { - LineCur->FragLast->LineList = F; - } - LineCur->FragLast = F; + /* Emit the argument as an expression */ + F = GenFragment (FRAG_EXPR, 2); + F->V.Expr = Value; } - - /* Increment the program counter */ - IncPC (Len); - - /* And return it */ - return F; -} - - - -void Emit0 (unsigned char OPC) -/* Emit an instruction with a zero sized operand */ -{ - /* First fragment, wrong type or out of space, create new one */ - Fragment* F = NewFragment (FRAG_LITERAL, 1); - F->V.Data [0] = OPC; -} - - - -void Emit1 (unsigned char OPC, ExprNode* Value) -/* Emit an instruction with an one byte argument */ -{ - Emit0 (OPC); - EmitByte (Value); -} - - - -void Emit2 (unsigned char OPC, ExprNode* Value) -/* Emit an instruction with a two byte argument */ -{ - Emit0 (OPC); - EmitWord (Value); } @@ -682,12 +133,11 @@ void Emit3 (unsigned char OPC, ExprNode* Expr) -void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank) -/* Emit an instruction with a three byte argument and separate bank */ +void EmitSigned (ExprNode* Expr, unsigned Size) +/* Emit a signed expression with the given size */ { - Emit0 (OPC); - EmitWord (Expr); - EmitByte (Bank); + Fragment* F = GenFragment (FRAG_SEXPR, Size); + F->V.Expr = Expr; } @@ -695,59 +145,72 @@ void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank) void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size) /* Emit an opcode with a PC relative argument of one or two bytes */ { - Fragment* F; Emit0 (OPC); - F = NewFragment (FRAG_SEXPR, Size); - F->V.Expr = Expr; + EmitSigned (Expr, Size); } -void EmitData (const unsigned char* Data, unsigned Size) +void EmitData (const void* D, unsigned Size) /* Emit data into the current segment */ { + /* Make a useful pointer from Data */ + const unsigned char* Data = D; + /* Create lots of fragments for the data */ while (Size) { - Fragment* F; + Fragment* F; - /* Determine the length of the next fragment */ - unsigned Len = Size; - if (Len > sizeof (F->V.Data)) { - Len = sizeof (F->V.Data); - } + /* Determine the length of the next fragment */ + unsigned Len = Size; + if (Len > sizeof (F->V.Data)) { + Len = sizeof (F->V.Data); + } - /* Create a new fragment */ - F = NewFragment (FRAG_LITERAL, Len); + /* Create a new fragment */ + F = GenFragment (FRAG_LITERAL, Len); - /* Copy the data */ - memcpy (F->V.Data, Data, Len); + /* Copy the data */ + memcpy (F->V.Data, Data, Len); - /* Next chunk */ - Data += Len; - Size -= Len; + /* Next chunk */ + Data += Len; + Size -= Len; } } +void EmitStrBuf (const StrBuf* Data) +/* Emit a string into the current segment */ +{ + /* Use EmitData to output the data */ + EmitData (SB_GetConstBuf (Data), SB_GetLen (Data)); +} + + + void EmitByte (ExprNode* Expr) /* Emit one byte */ { - if (IsConstExpr (Expr)) { - /* Constant expression, emit literal byte */ - long Val = GetExprVal (Expr); - FreeExpr (Expr); - if ((Val & ~0xFF) != 0) { - Error (ERR_RANGE); - } - Emit0 (Val & 0xFF); - } else { - /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 1); + long V; + Fragment* F; + + if (IsEasyConst (Expr, &V)) { + /* Must be in byte range */ + if (!IsByteRange (V)) { + Error ("Range error (%ld not in [0..255])", V); + } - /* Set the data */ - F->V.Expr = Expr; + /* Create a literal fragment */ + F = GenFragment (FRAG_LITERAL, 1); + F->V.Data[0] = (unsigned char) V; + FreeExpr (Expr); + } else { + /* Emit the argument as an expression */ + F = GenFragment (FRAG_EXPR, 1); + F->V.Expr = Expr; } } @@ -756,21 +219,24 @@ void EmitByte (ExprNode* Expr) void EmitWord (ExprNode* Expr) /* Emit one word */ { - if (IsConstExpr (Expr)) { - /* Constant expression, emit literal byte */ - long Val = GetExprVal (Expr); - FreeExpr (Expr); - if ((Val & ~0xFFFF) != 0) { - Error (ERR_RANGE); - } - Emit0 (Val & 0xFF); - Emit0 ((Val >> 8) & 0xFF); - } else { - /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 2); + long V; + Fragment* F; - /* Set the data */ - F->V.Expr = Expr; + if (IsEasyConst (Expr, &V)) { + /* Must be in byte range */ + if (!IsWordRange (V)) { + Error ("Range error (%ld not in [0..65535])", V); + } + + /* Create a literal fragment */ + F = GenFragment (FRAG_LITERAL, 2); + F->V.Data[0] = (unsigned char) V; + F->V.Data[1] = (unsigned char) (V >> 8); + FreeExpr (Expr); + } else { + /* Emit the argument as an expression */ + Fragment* F = GenFragment (FRAG_EXPR, 2); + F->V.Expr = Expr; } } @@ -779,23 +245,11 @@ void EmitWord (ExprNode* Expr) void EmitFarAddr (ExprNode* Expr) /* Emit a 24 bit expression */ { - if (IsConstExpr (Expr)) { - /* Constant expression, emit literal byte */ - long Val = GetExprVal (Expr); - FreeExpr (Expr); - if ((Val & ~0xFFFFFF) != 0) { - Error (ERR_RANGE); - } - Emit0 (Val & 0xFF); - Emit0 ((Val >> 8) & 0xFF); - Emit0 ((Val >> 16) & 0xFF); - } else { - /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 3); + /* Create a new fragment */ + Fragment* F = GenFragment (FRAG_EXPR, 3); - /* Set the data */ - F->V.Expr = Expr; - } + /* Set the data */ + F->V.Expr = Expr; } @@ -803,21 +257,11 @@ void EmitFarAddr (ExprNode* Expr) void EmitDWord (ExprNode* Expr) /* Emit one dword */ { - if (IsConstExpr (Expr)) { - /* Constant expression, emit literal byte */ - long Val = GetExprVal (Expr); - FreeExpr (Expr); - Emit0 (Val & 0xFF); - Emit0 ((Val >> 8) & 0xFF); - Emit0 ((Val >> 16) & 0xFF); - Emit0 ((Val >> 24) & 0xFF); - } else { - /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 4); + /* Create a new fragment */ + Fragment* F = GenFragment (FRAG_EXPR, 4); - /* Set the data */ - F->V.Expr = Expr; - } + /* Set the data */ + F->V.Expr = Expr; } @@ -826,14 +270,11 @@ void EmitFill (unsigned long Count) /* Emit Count fill bytes */ { while (Count) { - /* Calculate the size of the next chunk */ - unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count; - Count -= Chunk; + /* Calculate the size of the next chunk */ + unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count; + Count -= Chunk; - /* Emit one chunk */ - NewFragment (FRAG_FILL, Chunk); + /* Emit one chunk */ + GenFragment (FRAG_FILL, Chunk); } } - - -