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