]> git.sur5r.net Git - cc65/blob - src/ca65/segment.c
Address size fixes
[cc65] / src / ca65 / segment.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 segment.c                                 */
4 /*                                                                           */
5 /*                   Segments for the ca65 macroassembler                    */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 52                                              */
11 /*               D-70794 Filderstadt                                         */
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 "segnames.h"
41 #include "xmalloc.h"
42
43 /* cc65 */
44 #include "error.h"
45 #include "fragment.h"
46 #include "global.h"
47 #include "lineinfo.h"
48 #include "listing.h"
49 #include "objcode.h"
50 #include "objfile.h"
51 #include "segment.h"
52 #include "spool.h"
53 #include "symtab.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 /* Segment initializer macro */
68 #define SEG(segdef, num, prev)      \
69     { prev, 0, 0, 0, num, 0, 0, segdef }
70
71 /* Definitions for predefined segments */
72 SegDef NullSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL,     ADDR_SIZE_ABS);
73 SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_ZEROPAGE, ADDR_SIZE_ZP);
74 SegDef DataSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_DATA,     ADDR_SIZE_ABS);
75 SegDef BssSegDef      = STATIC_SEGDEF_INITIALIZER (SEGNAME_BSS,      ADDR_SIZE_ABS);
76 SegDef RODataSegDef   = STATIC_SEGDEF_INITIALIZER (SEGNAME_RODATA,   ADDR_SIZE_ABS);
77 SegDef CodeSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_CODE,     ADDR_SIZE_ABS);
78
79 /* Predefined segments */
80 static Segment NullSeg     = SEG (&NullSegDef,     5, NULL);
81 static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg);
82 static Segment DataSeg     = SEG (&DataSegDef,     3, &ZeropageSeg);
83 static Segment BssSeg      = SEG (&BssSegDef,      2, &DataSeg);
84 static Segment RODataSeg   = SEG (&RODataSegDef,   1, &BssSeg);
85 static Segment CodeSeg     = SEG (&CodeSegDef,     0, &RODataSeg);
86
87 /* Number of segments */
88 static unsigned SegmentCount = 6;
89
90 /* List of all segments */
91 static Segment* SegmentList = &CodeSeg;
92 static Segment* SegmentLast = &NullSeg;
93
94 /* Currently active segment */
95 Segment* ActiveSeg = &CodeSeg;
96
97
98
99 /*****************************************************************************/
100 /*                                   Code                                    */
101 /*****************************************************************************/
102
103
104
105 static Segment* NewSegment (const char* Name, unsigned AddrSize)
106 /* Create a new segment, insert it into the global list and return it */
107 {
108     Segment* S;
109
110     /* Check for too many segments */
111     if (SegmentCount >= 256) {
112         Fatal ("Too many segments");
113     }
114
115     /* Check the segment name for invalid names */
116     if (!ValidSegName (Name)) {
117         Error ("Illegal segment name: `%s'", Name);
118     }
119
120     /* Create a new segment */
121     S = xmalloc (sizeof (*S));
122
123     /* Initialize it */
124     S->List      = 0;
125     S->Root      = 0;
126     S->Last      = 0;
127     S->FragCount = 0;
128     S->Num       = SegmentCount++;
129     S->Align     = 0;
130     S->PC        = 0;
131     S->Def       = NewSegDef (Name, AddrSize);
132
133     /* Insert it into the segment list */
134     SegmentLast->List = S;
135     SegmentLast = S;
136
137     /* And return it... */
138     return S;
139 }
140
141
142
143 Fragment* GenFragment (unsigned char Type, unsigned short Len)
144 /* Generate a new fragment, add it to the current segment and return it. */
145 {
146     /* Create the new fragment */
147     Fragment* F = NewFragment (Type, Len);
148
149     /* Insert the fragment into the current segment */
150     if (ActiveSeg->Root) {
151         ActiveSeg->Last->Next = F;
152         ActiveSeg->Last = F;
153     } else {
154         ActiveSeg->Root = ActiveSeg->Last = F;
155     }
156     ++ActiveSeg->FragCount;
157
158     /* Add this fragment to the current listing line */
159     if (LineCur) {
160         if (LineCur->FragList == 0) {
161             LineCur->FragList = F;
162         } else {
163             LineCur->FragLast->LineList = F;
164         }
165         LineCur->FragLast = F;
166     }
167
168     /* Increment the program counter */
169     ActiveSeg->PC += F->Len;
170     if (!RelocMode) {
171         AbsPC += F->Len;
172     }
173
174     /* Return the fragment */
175     return F;
176 }
177
178
179
180 void UseSeg (const SegDef* D)
181 /* Use the segment with the given name */
182 {
183     Segment* Seg = SegmentList;
184     while (Seg) {
185         if (strcmp (Seg->Def->Name, D->Name) == 0) {
186             /* We found this segment. Check if the type is identical */
187             if (D->AddrSize != ADDR_SIZE_DEFAULT &&
188                 Seg->Def->AddrSize != D->AddrSize) {
189                 Error ("Segment attribute mismatch");
190                 /* Use the new attribute to avoid errors */
191                 Seg->Def->AddrSize = D->AddrSize;
192             }
193             ActiveSeg = Seg;
194             return;
195         }
196         /* Check next segment */
197         Seg = Seg->List;
198     }
199
200     /* Segment is not in list, create a new one */
201     if (D->AddrSize == ADDR_SIZE_DEFAULT) {
202         Seg = NewSegment (D->Name, ADDR_SIZE_ABS);
203     } else {
204         Seg = NewSegment (D->Name, D->AddrSize);
205     }
206     ActiveSeg = Seg;
207 }
208
209
210
211 unsigned long GetPC (void)
212 /* Get the program counter of the current segment */
213 {
214     return RelocMode? ActiveSeg->PC : AbsPC;
215 }
216
217
218
219 void SetAbsPC (unsigned long PC)
220 /* Set the program counter in absolute mode */
221 {
222     RelocMode = 0;
223     AbsPC = PC;
224 }
225
226
227
228 void SegAlign (unsigned Power, int Val)
229 /* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
230  * actual fill value will be determined by the linker), otherwise use the
231  * given value.
232  */
233 {
234     unsigned char Data [4];
235     unsigned long Align = (1UL << Power) - 1;
236     unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
237     unsigned long Count = NewPC - ActiveSeg->PC;
238
239     if (Val != -1) {
240         /* User defined fill value */
241         memset (Data, Val, sizeof (Data));
242         while (Count) {
243             if (Count > sizeof (Data)) {
244                 EmitData (Data, sizeof (Data));
245                 Count -= sizeof (Data);
246             } else {
247                 EmitData (Data, Count);
248                 Count = 0;
249             }
250         }
251     } else {
252         /* Linker defined fill value */
253         EmitFill (Count);
254     }
255
256     /* Remember the alignment in the header */
257     if (ActiveSeg->Align < Power) {
258         ActiveSeg->Align = Power;
259     }
260 }
261
262
263
264 unsigned GetSegAddrSize (unsigned SegNum)
265 /* Return the address size of the segment with the given number */
266 {
267     /* Search for the segment */
268     Segment* S = SegmentList;
269     while (S && SegNum) {
270         --SegNum;
271         S = S->List;
272     }
273
274     /* Did we find it? */
275     if (S == 0) {
276         FAIL ("Invalid segment number");
277     }
278
279     /* Return the address size */
280     return S->Def->AddrSize;
281 }
282
283
284
285 void SegCheck (void)
286 /* Check the segments for range and other errors */
287 {
288     Segment* S = SegmentList;
289     while (S) {
290         Fragment* F = S->Root;
291         while (F) {
292             if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
293                 long Val;
294                 if (IsConstExpr (F->V.Expr, &Val)) {
295                     /* We are able to evaluate the expression. Check for
296                      * range errors.
297                      */
298                     unsigned I;
299                     int Abs = (F->Type != FRAG_SEXPR);
300
301                     if (F->Len == 1) {
302                         if (Abs) {
303                             /* Absolute value */
304                             if (Val > 255) {
305                                 PError (&F->Pos, "Range error");
306                             }
307                         } else {
308                             /* PC relative value */
309                             if (Val < -128 || Val > 127) {
310                                 PError (&F->Pos, "Range error");
311                             }
312                         }
313                     } else if (F->Len == 2) {
314                         if (Abs) {
315                             /* Absolute value */
316                             if (Val > 65535) {
317                                 PError (&F->Pos, "Range error");
318                             }
319                         } else {
320                             /* PC relative value */
321                             if (Val < -32768 || Val > 32767) {
322                                 PError (&F->Pos, "Range error");
323                             }
324                         }
325                     }
326
327                     /* We don't need the expression tree any longer */
328                     FreeExpr (F->V.Expr);
329
330                     /* Convert the fragment into a literal fragment */
331                     for (I = 0; I < F->Len; ++I) {
332                         F->V.Data [I] = Val & 0xFF;
333                         Val >>= 8;
334                     }
335                     F->Type = FRAG_LITERAL;
336                 } else {
337                     /* We cannot evaluate the expression now, leave the job for
338                      * the linker. However, we are able to check for explicit
339                      * byte expressions and we will do so.
340                      */
341                     if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
342                         PError (&F->Pos, "Range error");
343                     }
344                 }
345             }
346             F = F->Next;
347         }
348         S = S->List;
349     }
350 }
351
352
353
354 void SegDump (void)
355 /* Dump the contents of all segments */
356 {
357     unsigned X = 0;
358     Segment* S = SegmentList;
359     printf ("\n");
360     while (S) {
361         unsigned I;
362         Fragment* F;
363         int State = -1;
364         printf ("New segment: %s", S->Def->Name);
365         F = S->Root;
366         while (F) {
367             if (F->Type == FRAG_LITERAL) {
368                 if (State != 0) {
369                     printf ("\n  Literal:");
370                     X = 15;
371                     State = 0;
372                 }
373                 for (I = 0; I < F->Len; ++I) {
374                     printf (" %02X", F->V.Data [I]);
375                     X += 3;
376                 }
377             } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
378                 State = 1;
379                 printf ("\n  Expression (%u): ", F->Len);
380                 DumpExpr (F->V.Expr, SymResolve);
381             } else if (F->Type == FRAG_FILL) {
382                 State = 1;
383                 printf ("\n  Fill bytes (%u)", F->Len);
384             } else {
385                 Internal ("Unknown fragment type: %u", F->Type);
386             }
387             if (X > 65) {
388                 State = -1;
389             }
390             F = F->Next;
391         }
392         printf ("\n  End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
393         S = S->List;
394     }
395     printf ("\n");
396 }
397
398
399
400 static void WriteOneSeg (Segment* Seg)
401 /* Write one segment to the object file */
402 {
403     Fragment* Frag;
404     unsigned LineInfoIndex;
405     unsigned long DataSize;
406     unsigned long EndPos;
407
408     /* Remember the file position, then write a dummy for the size of the
409      * following data
410      */
411     unsigned long SizePos = ObjGetFilePos ();
412     ObjWrite32 (0);
413
414     /* Write the segment data */
415     ObjWriteVar (GetStringId (Seg->Def->Name)); /* Name of the segment */
416     ObjWrite32 (Seg->PC);                       /* Size */
417     ObjWrite8 (Seg->Align);                     /* Segment alignment */
418     ObjWrite8 (Seg->Def->AddrSize);             /* Address size of the segment */
419     ObjWriteVar (Seg->FragCount);               /* Number of fragments */
420
421     /* Now walk through the fragment list for this segment and write the
422      * fragments.
423      */
424     Frag = Seg->Root;
425     while (Frag) {
426
427         /* Write data depending on the type */
428         switch (Frag->Type) {
429
430             case FRAG_LITERAL:
431                 ObjWrite8 (FRAG_LITERAL);
432                 ObjWriteVar (Frag->Len);
433                 ObjWriteData (Frag->V.Data, Frag->Len);
434                 break;
435
436             case FRAG_EXPR:
437                 switch (Frag->Len) {
438                     case 1:   ObjWrite8 (FRAG_EXPR8);   break;
439                     case 2:   ObjWrite8 (FRAG_EXPR16);  break;
440                     case 3:   ObjWrite8 (FRAG_EXPR24);  break;
441                     case 4:   ObjWrite8 (FRAG_EXPR32);  break;
442                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
443                 }
444                 WriteExpr (Frag->V.Expr);
445                 break;
446
447             case FRAG_SEXPR:
448                 switch (Frag->Len) {
449                     case 1:   ObjWrite8 (FRAG_SEXPR8);  break;
450                     case 2:   ObjWrite8 (FRAG_SEXPR16); break;
451                     case 3:   ObjWrite8 (FRAG_SEXPR24); break;
452                     case 4:   ObjWrite8 (FRAG_SEXPR32); break;
453                     default:  Internal ("Invalid fragment size: %u", Frag->Len);
454                 }
455                 WriteExpr (Frag->V.Expr);
456                 break;
457
458             case FRAG_FILL:
459                 ObjWrite8 (FRAG_FILL);
460                 ObjWriteVar (Frag->Len);
461                 break;
462
463             default:
464                 Internal ("Invalid fragment type: %u", Frag->Type);
465
466         }
467
468         /* Write the file position of this fragment */
469         ObjWritePos (&Frag->Pos);
470
471         /* Write extra line info for this fragment. Zero is considered
472          * "no line info", so add one to the value.
473          */
474         LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
475         ObjWriteVar (LineInfoIndex);
476
477         /* Next fragment */
478         Frag = Frag->Next;
479     }
480
481     /* Calculate the size of the data, seek back and write it */
482     EndPos = ObjGetFilePos ();          /* Remember where we are */
483     DataSize = EndPos - SizePos - 4;    /* Don't count size itself */
484     ObjSetFilePos (SizePos);            /* Seek back to the size */
485     ObjWrite32 (DataSize);              /* Write the size */
486     ObjSetFilePos (EndPos);             /* Seek back to the end */
487 }
488
489
490
491 void WriteSegments (void)
492 /* Write the segment data to the object file */
493 {
494     Segment* Seg;
495
496     /* Tell the object file module that we're about to start the seg list */
497     ObjStartSegments ();
498
499     /* First thing is segment count */
500     ObjWriteVar (SegmentCount);
501
502     /* Now walk through all segments and write them to the object file */
503     Seg = SegmentList;
504     while (Seg) {
505         /* Write one segment */
506         WriteOneSeg (Seg);
507         /* Next segment */
508         Seg = Seg->List;
509     }
510
511     /* Done writing segments */
512     ObjEndSegments ();
513 }
514
515
516