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