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