1 /*****************************************************************************/
5 /* Objectcode management for the ca65 macroassembler */
9 /* (C) 1998-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 /* Are we in absolute mode or in relocatable mode? */
66 unsigned long AbsPC = 0; /* PC if in absolute mode */
70 typedef struct Segment_ Segment;
72 Segment* List; /* List of all segments */
73 Fragment* Root; /* Root of fragment list */
74 Fragment* Last; /* Pointer to last fragment */
75 unsigned char Align; /* Segment alignment */
76 unsigned char SegType; /* True if zero page segment */
78 unsigned Num; /* Segment number */
79 char* Name; /* Segment name */
84 /* Predefined segments */
85 static Segment NullSeg = {
86 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
88 static Segment ZeropageSeg = {
89 &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
91 static Segment DataSeg = {
92 &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
94 static Segment BssSeg = {
95 &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
97 static Segment RODataSeg = {
98 &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
100 static Segment CodeSeg = {
101 &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
104 /* Number of segments */
105 static unsigned SegmentCount = 6;
107 /* List of all segments */
108 static Segment* SegmentList = &CodeSeg;
109 static Segment* SegmentLast = &NullSeg;
111 /* Currently active segment */
112 static Segment* ActiveSeg = &CodeSeg;
116 /*****************************************************************************/
117 /* Segment management */
118 /*****************************************************************************/
122 static Segment* NewSegment (const char* Name, unsigned SegType)
123 /* Create a new segment, insert it into the global list and return it */
128 /* Check for too many segments */
129 if (SegmentCount >= 256) {
130 Fatal (FAT_TOO_MANY_SEGMENTS);
133 /* Check the segment name for invalid names */
135 if ((*N != '_' && !IsAlpha (*N)) || strlen (Name) > 80) {
136 Error (ERR_ILLEGAL_SEGMENT, Name);
139 if (*N != '_' && !IsAlNum (*N)) {
140 Error (ERR_ILLEGAL_SEGMENT, Name);
146 /* Create a new segment */
147 S = xmalloc (sizeof (*S));
154 S->SegType = SegType;
156 S->Num = SegmentCount++;
157 S->Name = xstrdup (Name);
159 /* Insert it into the segment list */
160 SegmentLast->List = S;
163 /* And return it... */
169 void UseCodeSeg (void)
170 /* Use the code segment */
172 ActiveSeg = &CodeSeg;
177 void UseRODataSeg (void)
178 /* Use the r/o data segment */
180 ActiveSeg = &RODataSeg;
185 void UseDataSeg (void)
186 /* Use the data segment */
188 ActiveSeg = &DataSeg;
193 void UseBssSeg (void)
194 /* Use the BSS segment */
201 void UseZeropageSeg (void)
202 /* Use the zero page segment */
204 ActiveSeg = &ZeropageSeg;
209 void UseNullSeg (void)
210 /* Use the null segment */
212 ActiveSeg = &NullSeg;
217 void UseSeg (const char* Name, unsigned SegType)
218 /* Use the segment with the given name */
220 Segment* Seg = SegmentList;
222 if (strcmp (Seg->Name, Name) == 0) {
223 /* We found this segment. Check if the type is identical */
224 if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
225 Error (ERR_SEG_ATTR_MISMATCH);
226 /* Use the new attribute to avoid errors */
227 Seg->SegType = SegType;
232 /* Check next segment */
236 /* Segment is not in list, create a new one */
237 if (SegType == SEGTYPE_DEFAULT) {
238 SegType = SEGTYPE_ABS;
240 Seg = NewSegment (Name, SegType);
246 unsigned long GetPC (void)
247 /* Get the program counter of the current segment */
249 return RelocMode? ActiveSeg->PC : AbsPC;
254 void SetAbsPC (unsigned long PC)
255 /* Set the program counter in absolute mode */
263 unsigned GetSegNum (void)
264 /* Get the number of the current segment */
266 return ActiveSeg->Num;
271 void SegAlign (unsigned Power, int Val)
272 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
273 * actual fill value will be determined by the linker), otherwise use the
277 unsigned char Data [4];
278 unsigned long Align = (1UL << Power) - 1;
279 unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
280 unsigned long Count = NewPC - ActiveSeg->PC;
283 /* User defined fill value */
284 memset (Data, Val, sizeof (Data));
286 if (Count > sizeof (Data)) {
287 EmitData (Data, sizeof (Data));
288 Count -= sizeof (Data);
290 EmitData (Data, Count);
295 /* Linker defined fill value */
299 /* Remember the alignment in the header */
300 if (ActiveSeg->Align < Power) {
301 ActiveSeg->Align = Power;
308 /* Return true if the current segment is a zeropage segment */
310 return (ActiveSeg->SegType == SEGTYPE_ZP);
316 /* Return true if the current segment is a far segment */
318 return (ActiveSeg->SegType == SEGTYPE_FAR);
323 unsigned GetSegType (unsigned SegNum)
324 /* Return the type of the segment with the given number */
326 /* Search for the segment */
327 Segment* S = SegmentList;
328 while (S && SegNum) {
333 /* Did we find it? */
335 FAIL ("Invalid segment number");
338 /* Return the segment type */
345 /* Check the segments for range and other errors */
347 Segment* S = SegmentList;
349 Fragment* F = S->Root;
351 if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
352 F->V.Expr = FinalizeExpr (F->V.Expr);
353 if (IsConstExpr (F->V.Expr)) {
354 /* We are able to evaluate the expression. Get the value
355 * and check for range errors.
358 long Val = GetExprVal (F->V.Expr);
359 int Abs = (F->Type != FRAG_SEXPR);
365 PError (&F->Pos, ERR_RANGE);
368 /* PC relative value */
369 if (Val < -128 || Val > 127) {
370 PError (&F->Pos, ERR_RANGE);
373 } else if (F->Len == 2) {
377 PError (&F->Pos, ERR_RANGE);
380 /* PC relative value */
381 if (Val < -32768 || Val > 32767) {
382 PError (&F->Pos, ERR_RANGE);
387 /* Convert the fragment into a literal fragment */
388 for (I = 0; I < F->Len; ++I) {
389 F->V.Data [I] = Val & 0xFF;
392 F->Type = FRAG_LITERAL;
394 /* We cannot evaluate the expression now, leave the job for
395 * the linker. However, we are able to check for explicit
396 * byte expressions and we will do so.
398 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
399 PError (&F->Pos, ERR_RANGE);
412 /* Dump the contents of all segments */
415 Segment* S = SegmentList;
421 printf ("New segment: %s", S->Name);
424 if (F->Type == FRAG_LITERAL) {
426 printf ("\n Literal:");
430 for (I = 0; I < F->Len; ++I) {
431 printf (" %02X", F->V.Data [I]);
434 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
436 printf ("\n Expression (%u): ", F->Len);
437 DumpExpr (F->V.Expr);
438 } else if (F->Type == FRAG_FILL) {
440 printf ("\n Fill bytes (%u)", F->Len);
442 Internal ("Unknown fragment type: %u", F->Type);
449 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
457 static void WriteOneSeg (Segment* Seg)
458 /* Write one segment to the object file */
461 unsigned LineInfoIndex;
463 /* Write the segment name followed by the byte count in this segment */
464 ObjWriteStr (Seg->Name);
465 ObjWrite32 (Seg->PC);
466 ObjWrite8 (Seg->Align);
467 ObjWrite8 (Seg->SegType);
469 /* Now walk through the fragment list for this segment and write the
475 /* Write data depending on the type */
476 switch (Frag->Type) {
479 ObjWrite8 (FRAG_LITERAL);
480 ObjWriteVar (Frag->Len);
481 ObjWriteData (Frag->V.Data, Frag->Len);
486 case 1: ObjWrite8 (FRAG_EXPR8); break;
487 case 2: ObjWrite8 (FRAG_EXPR16); break;
488 case 3: ObjWrite8 (FRAG_EXPR24); break;
489 case 4: ObjWrite8 (FRAG_EXPR32); break;
490 default: Internal ("Invalid fragment size: %u", Frag->Len);
492 WriteExpr (Frag->V.Expr);
497 case 1: ObjWrite8 (FRAG_SEXPR8); break;
498 case 2: ObjWrite8 (FRAG_SEXPR16); break;
499 case 3: ObjWrite8 (FRAG_SEXPR24); break;
500 case 4: ObjWrite8 (FRAG_SEXPR32); break;
501 default: Internal ("Invalid fragment size: %u", Frag->Len);
503 WriteExpr (Frag->V.Expr);
507 ObjWrite8 (FRAG_FILL);
508 ObjWriteVar (Frag->Len);
512 Internal ("Invalid fragment type: %u", Frag->Type);
516 /* Write the file position of this fragment */
517 ObjWritePos (&Frag->Pos);
519 /* Write extra line info for this fragment. Zero is considered
520 * "no line info", so add one to the value.
522 LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
523 ObjWriteVar (LineInfoIndex);
532 void WriteSegments (void)
533 /* Write the segment data to the object file */
537 /* Tell the object file module that we're about to start the seg list */
540 /* First thing is segment count */
541 ObjWriteVar (SegmentCount);
543 /* Now walk through all segments and write them to the object file */
546 /* Write one segment */
552 /* Done writing segments */
558 /*****************************************************************************/
560 /*****************************************************************************/
564 static void IncPC (unsigned Value)
565 /* Increment the PC counter */
567 ActiveSeg->PC += Value;
575 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
576 /* Create, initialize and return a new fragment. The fragment will be inserted
577 * into the current segment.
582 /* Create a new fragment */
583 F = xmalloc (sizeof (*F));
590 F->LI = UseLineInfo (CurLineInfo);
594 /* Insert it into the list of all segments */
602 /* Insert it into the current segment */
603 if (ActiveSeg->Root) {
604 ActiveSeg->Last->Next = F;
607 ActiveSeg->Root = ActiveSeg->Last = F;
610 /* Add this fragment to the current listing line */
612 if (LineCur->FragList == 0) {
613 LineCur->FragList = F;
615 LineCur->FragLast->LineList = F;
617 LineCur->FragLast = F;
620 /* Increment the program counter */
629 void Emit0 (unsigned char OPC)
630 /* Emit an instruction with a zero sized operand */
632 /* First fragment, wrong type or out of space, create new one */
633 Fragment* F = NewFragment (FRAG_LITERAL, 1);
639 void Emit1 (unsigned char OPC, ExprNode* Value)
640 /* Emit an instruction with an one byte argument */
648 void Emit2 (unsigned char OPC, ExprNode* Value)
649 /* Emit an instruction with a two byte argument */
657 void Emit3 (unsigned char OPC, ExprNode* Expr)
658 /* Emit an instruction with a three byte argument */
666 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
667 /* Emit an instruction with a three byte argument and separate bank */
676 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
677 /* Emit an opcode with a PC relative argument of one or two bytes */
681 F = NewFragment (FRAG_SEXPR, Size);
687 void EmitData (const unsigned char* Data, unsigned Size)
688 /* Emit data into the current segment */
690 /* Create lots of fragments for the data */
694 /* Determine the length of the next fragment */
696 if (Len > sizeof (F->V.Data)) {
697 Len = sizeof (F->V.Data);
700 /* Create a new fragment */
701 F = NewFragment (FRAG_LITERAL, Len);
704 memcpy (F->V.Data, Data, Len);
715 void EmitByte (ExprNode* Expr)
718 if (IsConstExpr (Expr)) {
719 /* Constant expression, emit literal byte */
720 long Val = GetExprVal (Expr);
722 if ((Val & ~0xFF) != 0) {
727 /* Create a new fragment */
728 Fragment* F = NewFragment (FRAG_EXPR, 1);
737 void EmitWord (ExprNode* Expr)
740 if (IsConstExpr (Expr)) {
741 /* Constant expression, emit literal byte */
742 long Val = GetExprVal (Expr);
744 if ((Val & ~0xFFFF) != 0) {
748 Emit0 ((Val >> 8) & 0xFF);
750 /* Create a new fragment */
751 Fragment* F = NewFragment (FRAG_EXPR, 2);
760 void EmitFarAddr (ExprNode* Expr)
761 /* Emit a 24 bit expression */
763 if (IsConstExpr (Expr)) {
764 /* Constant expression, emit literal byte */
765 long Val = GetExprVal (Expr);
767 if ((Val & ~0xFFFFFF) != 0) {
771 Emit0 ((Val >> 8) & 0xFF);
772 Emit0 ((Val >> 16) & 0xFF);
774 /* Create a new fragment */
775 Fragment* F = NewFragment (FRAG_EXPR, 3);
784 void EmitDWord (ExprNode* Expr)
787 if (IsConstExpr (Expr)) {
788 /* Constant expression, emit literal byte */
789 long Val = GetExprVal (Expr);
792 Emit0 ((Val >> 8) & 0xFF);
793 Emit0 ((Val >> 16) & 0xFF);
794 Emit0 ((Val >> 24) & 0xFF);
796 /* Create a new fragment */
797 Fragment* F = NewFragment (FRAG_EXPR, 4);
806 void EmitFill (unsigned long Count)
807 /* Emit Count fill bytes */
810 /* Calculate the size of the next chunk */
811 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
815 NewFragment (FRAG_FILL, Chunk);