]> git.sur5r.net Git - cc65/blob - src/ca65/objcode.c
Add co65 utility
[cc65] / src / ca65 / objcode.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 objcode.c                                 */
4 /*                                                                           */
5 /*             Objectcode management for the ca65 macroassembler             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <errno.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "segdefs.h"
43 #include "segnames.h"
44 #include "xmalloc.h"
45
46 /* cc65 */
47 #include "error.h"
48 #include "fragment.h"
49 #include "global.h"
50 #include "lineinfo.h"
51 #include "listing.h"
52 #include "objfile.h"
53 #include "scanner.h"
54 #include "symtab.h"
55 #include "objcode.h"
56
57
58
59 /*****************************************************************************/
60 /*                                   Data                                    */
61 /*****************************************************************************/
62
63
64
65 /* Are we in absolute mode or in relocatable mode? */
66 int             RelocMode = 1;
67 unsigned long   AbsPC     = 0;          /* PC if in absolute mode */
68
69
70
71 typedef struct Segment Segment;
72 struct Segment {
73     Segment*        List;               /* List of all segments */
74     Fragment*       Root;               /* Root of fragment list */
75     Fragment*       Last;               /* Pointer to last fragment */
76     unsigned        Num;                /* Segment number */
77     unsigned        Align;              /* Segment alignment */
78     unsigned long   PC;
79     SegDef*         Def;                /* Segment definition (name and type) */
80 };
81
82
83 #define SEG(segdef, num, prev)      \
84     { prev, 0, 0, num, 0, 0, segdef }
85
86 /* Definitions for predefined segments */
87 SegDef NullSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL,     SEGTYPE_ABS);
88 SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_ZEROPAGE, SEGTYPE_ZP);
89 SegDef DataSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_DATA,     SEGTYPE_ABS);
90 SegDef BssSegDef      = STATIC_SEGDEF_INITIALIZER (SEGNAME_BSS,      SEGTYPE_ABS);
91 SegDef RODataSegDef   = STATIC_SEGDEF_INITIALIZER (SEGNAME_RODATA,   SEGTYPE_ABS);
92 SegDef CodeSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_CODE,     SEGTYPE_ABS);
93
94 /* Predefined segments */
95 static Segment NullSeg     = SEG (&NullSegDef,     5, NULL);
96 static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg);
97 static Segment DataSeg     = SEG (&DataSegDef,     3, &ZeropageSeg);
98 static Segment BssSeg      = SEG (&BssSegDef,      2, &DataSeg);
99 static Segment RODataSeg   = SEG (&RODataSegDef,   1, &BssSeg);
100 static Segment CodeSeg     = SEG (&CodeSegDef,     0, &RODataSeg);
101
102 /* Number of segments */
103 static unsigned SegmentCount = 6;
104
105 /* List of all segments */
106 static Segment* SegmentList = &CodeSeg;
107 static Segment* SegmentLast = &NullSeg;
108
109 /* Currently active segment */
110 static Segment* ActiveSeg = &CodeSeg;
111
112
113
114 /*****************************************************************************/
115 /*                            Segment management                             */
116 /*****************************************************************************/
117
118
119
120 static Segment* NewSegment (const char* Name, unsigned SegType)
121 /* Create a new segment, insert it into the global list and return it */
122 {
123     Segment* S;
124
125     /* Check for too many segments */
126     if (SegmentCount >= 256) {
127         Fatal (FAT_TOO_MANY_SEGMENTS);
128     }
129
130     /* Check the segment name for invalid names */
131     if (!ValidSegName (Name)) {
132         Error (ERR_ILLEGAL_SEGMENT, Name);
133     }
134
135     /* Create a new segment */
136     S = xmalloc (sizeof (*S));
137
138     /* Initialize it */
139     S->List   = 0;
140     S->Root   = 0;
141     S->Last   = 0;
142     S->Num    = SegmentCount++;
143     S->Align  = 0;
144     S->PC     = 0;
145     S->Def    = NewSegDef (Name, SegType);
146
147     /* Insert it into the segment list */
148     SegmentLast->List = S;
149     SegmentLast = S;
150
151     /* And return it... */
152     return S;
153 }
154
155
156
157 void UseSeg (const SegDef* D)
158 /* Use the segment with the given name */
159 {
160     Segment* Seg = SegmentList;
161     while (Seg) {
162         if (strcmp (Seg->Def->Name, D->Name) == 0) {
163             /* We found this segment. Check if the type is identical */
164             if (D->Type != SEGTYPE_DEFAULT && Seg->Def->Type != D->Type) {
165                 Error (ERR_SEG_ATTR_MISMATCH);
166                 /* Use the new attribute to avoid errors */
167                 Seg->Def->Type = D->Type;
168             }
169             ActiveSeg = Seg;
170             return;
171         }
172         /* Check next segment */
173         Seg = Seg->List;
174     }
175
176     /* Segment is not in list, create a new one */
177     if (D->Type == SEGTYPE_DEFAULT) {
178         Seg = NewSegment (D->Name, SEGTYPE_ABS);
179     } else {
180         Seg = NewSegment (D->Name, D->Type);
181     }
182     ActiveSeg = Seg;
183 }
184
185
186
187 unsigned long GetPC (void)
188 /* Get the program counter of the current segment */
189 {
190     return RelocMode? ActiveSeg->PC : AbsPC;
191 }
192
193
194
195 void SetAbsPC (unsigned long PC)
196 /* Set the program counter in absolute mode */
197 {
198     RelocMode = 0;
199     AbsPC = PC;
200 }
201
202
203
204 const SegDef* GetCurrentSeg (void)
205 /* Get a pointer to the segment defininition of the current segment */
206 {
207     return ActiveSeg->Def;
208 }
209
210
211
212 unsigned GetSegNum (void)
213 /* Get the number of the current segment */
214 {
215     return ActiveSeg->Num;
216 }
217
218
219
220 void SegAlign (unsigned Power, int Val)
221 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
222  * actual fill value will be determined by the linker), otherwise use the
223  * given value.
224  */
225 {
226     unsigned char Data [4];
227     unsigned long Align = (1UL << Power) - 1;
228     unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
229     unsigned long Count = NewPC - ActiveSeg->PC;
230
231     if (Val != -1) {
232         /* User defined fill value */
233         memset (Data, Val, sizeof (Data));
234         while (Count) {
235             if (Count > sizeof (Data)) {
236                 EmitData (Data, sizeof (Data));
237                 Count -= sizeof (Data);
238             } else {
239                 EmitData (Data, Count);
240                 Count = 0;
241             }
242         }
243     } else {
244         /* Linker defined fill value */
245         EmitFill (Count);
246     }
247
248     /* Remember the alignment in the header */
249     if (ActiveSeg->Align < Power) {
250         ActiveSeg->Align = Power;
251     }
252 }
253
254
255
256 int IsZPSeg (void)
257 /* Return true if the current segment is a zeropage segment */
258 {
259     return (ActiveSeg->Def->Type == SEGTYPE_ZP);
260 }
261
262
263
264 int IsFarSeg (void)
265 /* Return true if the current segment is a far segment */
266 {
267     return (ActiveSeg->Def->Type == SEGTYPE_FAR);
268 }
269
270
271
272 unsigned GetSegType (unsigned SegNum)
273 /* Return the type of the segment with the given number */
274 {
275     /* Search for the segment */
276     Segment* S = SegmentList;
277     while (S && SegNum) {
278         --SegNum;
279         S = S->List;
280     }
281
282     /* Did we find it? */
283     if (S == 0) {
284         FAIL ("Invalid segment number");
285     }
286
287     /* Return the segment type */
288     return S->Def->Type;
289 }
290
291
292
293 void SegCheck (void)
294 /* Check the segments for range and other errors */
295 {
296     Segment* S = SegmentList;
297     while (S) {
298         Fragment* F = S->Root;
299         while (F) {
300             if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
301                 F->V.Expr = FinalizeExpr (F->V.Expr);
302                 if (IsConstExpr (F->V.Expr)) {
303                     /* We are able to evaluate the expression. Get the value
304                      * and check for range errors.
305                      */
306                     unsigned I;
307                     long Val = GetExprVal (F->V.Expr);
308                     int Abs = (F->Type != FRAG_SEXPR);
309
310                     if (F->Len == 1) {
311                         if (Abs) {
312                             /* Absolute value */
313                             if (Val > 255) {
314                                 PError (&F->Pos, ERR_RANGE);
315                             }
316                         } else {
317                             /* PC relative value */
318                             if (Val < -128 || Val > 127) {
319                                 PError (&F->Pos, ERR_RANGE);
320                             }
321                         }
322                     } else if (F->Len == 2) {
323                         if (Abs) {
324                             /* Absolute value */
325                             if (Val > 65535) {
326                                 PError (&F->Pos, ERR_RANGE);
327                             }
328                         } else {
329                             /* PC relative value */
330                             if (Val < -32768 || Val > 32767) {
331                                 PError (&F->Pos, ERR_RANGE);
332                             }
333                         }
334                     }
335
336                     /* Convert the fragment into a literal fragment */
337                     for (I = 0; I < F->Len; ++I) {
338                         F->V.Data [I] = Val & 0xFF;
339                         Val >>= 8;
340                     }
341                     F->Type = FRAG_LITERAL;
342                 } else {
343                     /* We cannot evaluate the expression now, leave the job for
344                      * the linker. However, we are able to check for explicit
345                      * byte expressions and we will do so.
346                      */
347                     if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
348                         PError (&F->Pos, ERR_RANGE);
349                     }
350                 }
351             }
352             F = F->Next;
353         }
354         S = S->List;
355     }
356 }
357
358
359
360 void SegDump (void)
361 /* Dump the contents of all segments */
362 {
363     unsigned X = 0;
364     Segment* S = SegmentList;
365     printf ("\n");
366     while (S) {
367         unsigned I;
368         Fragment* F;
369         int State = -1;
370         printf ("New segment: %s", S->Def->Name);
371         F = S->Root;
372         while (F) {
373             if (F->Type == FRAG_LITERAL) {
374                 if (State != 0) {
375                     printf ("\n  Literal:");
376                     X = 15;
377                     State = 0;
378                 }
379                 for (I = 0; I < F->Len; ++I) {
380                     printf (" %02X", F->V.Data [I]);
381                     X += 3;
382                 }
383             } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
384                 State = 1;
385                 printf ("\n  Expression (%u): ", F->Len);
386                 DumpExpr (F->V.Expr);
387             } else if (F->Type == FRAG_FILL) {
388                 State = 1;
389                 printf ("\n  Fill bytes (%u)", F->Len);
390             } else {
391                 Internal ("Unknown fragment type: %u", F->Type);
392             }
393             if (X > 65) {
394                 State = -1;
395             }
396             F = F->Next;
397         }
398         printf ("\n  End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
399         S = S->List;
400     }
401     printf ("\n");
402 }
403
404
405
406 static void WriteOneSeg (Segment* Seg)
407 /* Write one segment to the object file */
408 {
409     Fragment* Frag;
410     unsigned LineInfoIndex;
411
412     /* Write the segment name followed by the byte count in this segment */
413     ObjWriteStr (Seg->Def->Name);
414     ObjWrite32 (Seg->PC);
415     ObjWrite8 (Seg->Align);
416     ObjWrite8 (Seg->Def->Type);
417
418     /* Now walk through the fragment list for this segment and write the
419      * fragments.
420      */
421     Frag = Seg->Root;
422     while (Frag) {
423
424         /* Write data depending on the type */
425         switch (Frag->Type) {
426
427             case FRAG_LITERAL:
428                 ObjWrite8 (FRAG_LITERAL);
429                 ObjWriteVar (Frag->Len);
430                 ObjWriteData (Frag->V.Data, Frag->Len);
431                 break;
432
433             case FRAG_EXPR:
434                 switch (Frag->Len) {
435                     case 1:   ObjWrite8 (FRAG_EXPR8);   break;
436                     case 2:   ObjWrite8 (FRAG_EXPR16);  break;
437                     case 3:   ObjWrite8 (FRAG_EXPR24);  break;
438                     case 4:   ObjWrite8 (FRAG_EXPR32);  break;
439                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
440                 }
441                 WriteExpr (Frag->V.Expr);
442                 break;
443
444             case FRAG_SEXPR:
445                 switch (Frag->Len) {
446                     case 1:   ObjWrite8 (FRAG_SEXPR8);  break;
447                     case 2:   ObjWrite8 (FRAG_SEXPR16); break;
448                     case 3:   ObjWrite8 (FRAG_SEXPR24); break;
449                     case 4:   ObjWrite8 (FRAG_SEXPR32); break;
450                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
451                 }
452                 WriteExpr (Frag->V.Expr);
453                 break;
454
455             case FRAG_FILL:
456                 ObjWrite8 (FRAG_FILL);
457                 ObjWriteVar (Frag->Len);
458                 break;
459
460             default:
461                 Internal ("Invalid fragment type: %u", Frag->Type);
462
463         }
464
465         /* Write the file position of this fragment */
466         ObjWritePos (&Frag->Pos);
467
468         /* Write extra line info for this fragment. Zero is considered
469          * "no line info", so add one to the value.
470          */
471         LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
472         ObjWriteVar (LineInfoIndex);
473
474         /* Next fragment */
475         Frag = Frag->Next;
476     }
477 }
478
479
480
481 void WriteSegments (void)
482 /* Write the segment data to the object file */
483 {
484     Segment* Seg;
485
486     /* Tell the object file module that we're about to start the seg list */
487     ObjStartSegments ();
488
489     /* First thing is segment count */
490     ObjWriteVar (SegmentCount);
491
492     /* Now walk through all segments and write them to the object file */
493     Seg = SegmentList;
494     while (Seg) {
495         /* Write one segment */
496         WriteOneSeg (Seg);
497         /* Next segment */
498         Seg = Seg->List;
499     }
500
501     /* Done writing segments */
502     ObjEndSegments ();
503 }
504
505
506
507 /*****************************************************************************/
508 /*                                   Code                                    */
509 /*****************************************************************************/
510
511
512
513 static void IncPC (unsigned Value)
514 /* Increment the PC counter */
515 {
516     ActiveSeg->PC += Value;
517     if (!RelocMode) {
518         AbsPC += Value;
519     }
520 }
521
522
523
524 static Fragment* NewFragment (unsigned char Type, unsigned short Len)
525 /* Create, initialize and return a new fragment. The fragment will be inserted
526  * into the current segment.
527  */
528 {
529     Fragment* F;
530
531     /* Create a new fragment */
532     F = xmalloc (sizeof (*F));
533
534     /* Initialize it */
535     F->List     = 0;
536     F->Next     = 0;
537     F->LineList = 0;
538     F->Pos      = CurPos;
539     F->LI       = UseLineInfo (CurLineInfo);
540     F->Len      = Len;
541     F->Type     = Type;
542
543     /* Insert it into the list of all segments */
544     if (FragList == 0) {
545         FragList = F;
546     } else {
547         FragLast->List = F;
548     }
549     FragLast = F;
550
551     /* Insert it into the current segment */
552     if (ActiveSeg->Root) {
553         ActiveSeg->Last->Next = F;
554         ActiveSeg->Last = F;
555     } else {
556         ActiveSeg->Root = ActiveSeg->Last = F;
557     }
558
559     /* Add this fragment to the current listing line */
560     if (LineCur) {
561         if (LineCur->FragList == 0) {
562             LineCur->FragList = F;
563         } else {
564             LineCur->FragLast->LineList = F;
565         }
566         LineCur->FragLast = F;
567     }
568
569     /* Increment the program counter */
570     IncPC (Len);
571
572     /* And return it */
573     return F;
574 }
575
576
577
578 void Emit0 (unsigned char OPC)
579 /* Emit an instruction with a zero sized operand */
580 {
581     /* First fragment, wrong type or out of space, create new one */
582     Fragment* F = NewFragment (FRAG_LITERAL, 1);
583     F->V.Data [0] = OPC;
584 }
585
586
587
588 void Emit1 (unsigned char OPC, ExprNode* Value)
589 /* Emit an instruction with an one byte argument */
590 {
591     Emit0 (OPC);
592     EmitByte (Value);
593 }
594
595
596
597 void Emit2 (unsigned char OPC, ExprNode* Value)
598 /* Emit an instruction with a two byte argument */
599 {
600     Emit0 (OPC);
601     EmitWord (Value);
602 }
603
604
605
606 void Emit3 (unsigned char OPC, ExprNode* Expr)
607 /* Emit an instruction with a three byte argument */
608 {
609     Emit0 (OPC);
610     EmitFarAddr (Expr);
611 }
612
613
614
615 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
616 /* Emit an instruction with a three byte argument and separate bank */
617 {
618     Emit0 (OPC);
619     EmitWord (Expr);
620     EmitByte (Bank);
621 }
622
623
624
625 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
626 /* Emit an opcode with a PC relative argument of one or two bytes */
627 {
628     Fragment* F;
629     Emit0 (OPC);
630     F = NewFragment (FRAG_SEXPR, Size);
631     F->V.Expr = Expr;
632 }
633
634
635
636 void EmitData (const unsigned char* Data, unsigned Size)
637 /* Emit data into the current segment */
638 {
639     /* Create lots of fragments for the data */
640     while (Size) {
641         Fragment* F;
642
643         /* Determine the length of the next fragment */
644         unsigned Len = Size;
645         if (Len > sizeof (F->V.Data)) {
646             Len = sizeof (F->V.Data);
647         }
648
649         /* Create a new fragment */
650         F = NewFragment (FRAG_LITERAL, Len);
651
652         /* Copy the data */
653         memcpy (F->V.Data, Data, Len);
654
655         /* Next chunk */
656         Data += Len;
657         Size -= Len;
658
659     }
660 }
661
662
663
664 void EmitByte (ExprNode* Expr)
665 /* Emit one byte */
666 {
667     if (IsConstExpr (Expr)) {
668         /* Constant expression, emit literal byte */
669         long Val = GetExprVal (Expr);
670         FreeExpr (Expr);
671         if ((Val & ~0xFF) != 0) {
672             Error (ERR_RANGE);
673         }
674         Emit0 (Val & 0xFF);
675     } else {
676         /* Create a new fragment */
677         Fragment* F = NewFragment (FRAG_EXPR, 1);
678
679         /* Set the data */
680         F->V.Expr = Expr;
681     }
682 }
683
684
685
686 void EmitWord (ExprNode* Expr)
687 /* Emit one word */
688 {
689     if (IsConstExpr (Expr)) {
690         /* Constant expression, emit literal byte */
691         long Val = GetExprVal (Expr);
692         FreeExpr (Expr);
693         if ((Val & ~0xFFFF) != 0) {
694             Error (ERR_RANGE);
695         }
696         Emit0 (Val & 0xFF);
697         Emit0 ((Val >> 8) & 0xFF);
698     } else {
699         /* Create a new fragment */
700         Fragment* F = NewFragment (FRAG_EXPR, 2);
701
702         /* Set the data */
703         F->V.Expr = Expr;
704     }
705 }
706
707
708
709 void EmitFarAddr (ExprNode* Expr)
710 /* Emit a 24 bit expression */
711 {
712     if (IsConstExpr (Expr)) {
713         /* Constant expression, emit literal byte */
714         long Val = GetExprVal (Expr);
715         FreeExpr (Expr);
716         if ((Val & ~0xFFFFFF) != 0) {
717             Error (ERR_RANGE);
718         }
719         Emit0 (Val & 0xFF);
720         Emit0 ((Val >> 8) & 0xFF);
721         Emit0 ((Val >> 16) & 0xFF);
722     } else {
723         /* Create a new fragment */
724         Fragment* F = NewFragment (FRAG_EXPR, 3);
725
726         /* Set the data */
727         F->V.Expr = Expr;
728     }
729 }
730
731
732
733 void EmitDWord (ExprNode* Expr)
734 /* Emit one dword */
735 {
736     if (IsConstExpr (Expr)) {
737         /* Constant expression, emit literal byte */
738         long Val = GetExprVal (Expr);
739         FreeExpr (Expr);
740         Emit0 (Val & 0xFF);
741         Emit0 ((Val >> 8) & 0xFF);
742         Emit0 ((Val >> 16) & 0xFF);
743         Emit0 ((Val >> 24) & 0xFF);
744     } else {
745         /* Create a new fragment */
746         Fragment* F = NewFragment (FRAG_EXPR, 4);
747
748         /* Set the data */
749         F->V.Expr = Expr;
750     }
751 }
752
753
754
755 void EmitFill (unsigned long Count)
756 /* Emit Count fill bytes */
757 {
758     while (Count) {
759         /* Calculate the size of the next chunk */
760         unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
761         Count -= Chunk;
762
763         /* Emit one chunk */
764         NewFragment (FRAG_FILL, Chunk);
765     }
766 }
767
768
769