1 /*****************************************************************************/
5 /* Objectcode management for the ca65 macroassembler */
9 /* (C) 1998-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 /* Are we in absolute mode or in relocatable mode? */
66 unsigned long AbsPC = 0; /* PC if in absolute mode */
70 typedef struct Segment_ 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 */
78 unsigned Num; /* Segment number */
79 char* Name; /* Segment name */
84 /* Predefined segments */
85 static Segment NullSeg = {
86 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
88 static Segment ZeropageSeg = {
89 &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
91 static Segment DataSeg = {
92 &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
94 static Segment BssSeg = {
95 &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
97 static Segment RODataSeg = {
98 &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
100 static Segment CodeSeg = {
101 &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
104 /* Number of segments */
105 static unsigned SegmentCount = 6;
107 /* List of all segments */
108 static Segment* SegmentList = &CodeSeg;
109 static Segment* SegmentLast = &NullSeg;
111 /* Currently active segment */
112 static Segment* ActiveSeg = &CodeSeg;
116 /*****************************************************************************/
117 /* Segment management */
118 /*****************************************************************************/
122 static Segment* NewSegment (const char* Name, unsigned SegType)
123 /* Create a new segment, insert it into the global list and return it */
128 /* Check for too many segments */
129 if (SegmentCount >= 256) {
130 Fatal (FAT_TOO_MANY_SEGMENTS);
133 /* Check the segment name for invalid names */
135 if ((*N != '_' && !IsAlpha (*N)) || strlen (Name) > 80) {
136 Error (ERR_ILLEGAL_SEGMENT, Name);
139 if (*N != '_' && !IsAlNum (*N)) {
140 Error (ERR_ILLEGAL_SEGMENT, Name);
146 /* Create a new segment */
147 S = xmalloc (sizeof (*S));
154 S->SegType = SegType;
156 S->Num = SegmentCount++;
157 S->Name = xstrdup (Name);
159 /* Insert it into the segment list */
160 SegmentLast->List = S;
163 /* And return it... */
169 void UseCodeSeg (void)
170 /* Use the code segment */
172 ActiveSeg = &CodeSeg;
177 void UseRODataSeg (void)
178 /* Use the r/o data segment */
180 ActiveSeg = &RODataSeg;
185 void UseDataSeg (void)
186 /* Use the data segment */
188 ActiveSeg = &DataSeg;
193 void UseBssSeg (void)
194 /* Use the BSS segment */
201 void UseZeropageSeg (void)
202 /* Use the zero page segment */
204 ActiveSeg = &ZeropageSeg;
209 void UseNullSeg (void)
210 /* Use the null segment */
212 ActiveSeg = &NullSeg;
217 void UseSeg (const char* Name, unsigned SegType)
218 /* Use the segment with the given name */
220 Segment* Seg = SegmentList;
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;
232 /* Check next segment */
236 /* Segment is not in list, create a new one */
237 if (SegType == SEGTYPE_DEFAULT) {
238 SegType = SEGTYPE_ABS;
240 Seg = NewSegment (Name, SegType);
246 unsigned long GetPC (void)
247 /* Get the program counter of the current segment */
249 return RelocMode? ActiveSeg->PC : AbsPC;
254 void SetAbsPC (unsigned long PC)
255 /* Set the program counter in absolute mode */
263 unsigned GetSegNum (void)
264 /* Get the number of the current segment */
266 return ActiveSeg->Num;
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
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;
283 /* User defined fill value */
284 memset (Data, Val, sizeof (Data));
286 if (Count > sizeof (Data)) {
287 EmitData (Data, sizeof (Data));
288 Count -= sizeof (Data);
290 EmitData (Data, Count);
295 /* Linker defined fill value */
299 /* Remember the alignment in the header */
300 if (ActiveSeg->Align < Power) {
301 ActiveSeg->Align = Power;
308 /* Return true if the current segment is a zeropage segment */
310 return (ActiveSeg->SegType == SEGTYPE_ZP);
316 /* Return true if the current segment is a far segment */
318 return (ActiveSeg->SegType == SEGTYPE_FAR);
323 unsigned GetSegType (unsigned SegNum)
324 /* Return the type of the segment with the given number */
326 /* Search for the segment */
327 Segment* S = SegmentList;
328 while (S && SegNum) {
333 /* Did we find it? */
335 FAIL ("Invalid segment number");
338 /* Return the segment type */
345 /* Check the segments for range and other errors */
347 Segment* S = SegmentList;
349 Fragment* F = S->Root;
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.
358 long Val = GetExprVal (F->V.Expr);
359 int Abs = (F->Type != FRAG_SEXPR);
365 PError (&F->Pos, ERR_RANGE);
368 /* PC relative value */
369 if (Val < -128 || Val > 127) {
370 PError (&F->Pos, ERR_RANGE);
373 } else if (F->Len == 2) {
377 PError (&F->Pos, ERR_RANGE);
380 /* PC relative value */
381 if (Val < -32768 || Val > 32767) {
382 PError (&F->Pos, ERR_RANGE);
387 /* Convert the fragment into a literal fragment */
388 for (I = 0; I < F->Len; ++I) {
389 F->V.Data [I] = Val & 0xFF;
392 F->Type = FRAG_LITERAL;
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.
398 if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
399 PError (&F->Pos, ERR_RANGE);
412 /* Dump the contents of all segments */
415 Segment* S = SegmentList;
421 printf ("New segment: %s", S->Name);
424 if (F->Type == FRAG_LITERAL) {
426 printf ("\n Literal:");
430 for (I = 0; I < F->Len; ++I) {
431 printf (" %02X", F->V.Data [I]);
434 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
436 printf ("\n Expression (%u): ", F->Len);
437 DumpExpr (F->V.Expr);
438 } else if (F->Type == FRAG_FILL) {
440 printf ("\n Fill bytes (%u)", F->Len);
442 Internal ("Unknown fragment type: %u", F->Type);
449 printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
457 static void WriteOneSeg (Segment* Seg)
458 /* Write one segment to the object file */
463 unsigned LineInfoIndex;
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);
471 /* Now walk through the fragment list for this segment and write the
477 /* Write data depending on the type */
478 switch (Frag->Type) {
481 /* To make the object file somewhat smaller, write all literal
482 * data of this and the following fragments preceeded by the
487 while (F && F->Type == FRAG_LITERAL) {
491 ObjWrite8 (FRAG_LITERAL);
494 /* Now write the literal data */
496 while (F && F->Type == FRAG_LITERAL) {
497 ObjWriteData (F->V.Data, F->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);
511 WriteExpr (Frag->V.Expr);
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);
522 WriteExpr (Frag->V.Expr);
526 ObjWrite8 (FRAG_FILL);
527 ObjWriteVar (Frag->Len);
531 Internal ("Invalid fragment type: %u", Frag->Type);
535 /* Write the file position of this fragment */
536 ObjWritePos (&Frag->Pos);
538 /* Write extra line info for this fragment. Zero is considered
539 * "no line info", so add one to the value.
541 LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
542 ObjWriteVar (LineInfoIndex);
551 void WriteSegments (void)
552 /* Write the segment data to the object file */
556 /* Tell the object file module that we're about to start the seg list */
559 /* First thing is segment count */
560 ObjWriteVar (SegmentCount);
562 /* Now walk through all segments and write them to the object file */
565 /* Write one segment */
571 /* Done writing segments */
577 /*****************************************************************************/
579 /*****************************************************************************/
583 static void IncPC (unsigned Value)
584 /* Increment the PC counter */
586 ActiveSeg->PC += Value;
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.
601 /* Create a new fragment */
602 F = xmalloc (sizeof (*F));
609 F->LI = UseLineInfo (CurLineInfo);
613 /* Insert it into the list of all segments */
621 /* Insert it into the current segment */
622 if (ActiveSeg->Root) {
623 ActiveSeg->Last->Next = F;
626 ActiveSeg->Root = ActiveSeg->Last = F;
629 /* Add this fragment to the current listing line */
631 if (LineCur->FragList == 0) {
632 LineCur->FragList = F;
634 LineCur->FragLast->LineList = F;
636 LineCur->FragLast = F;
639 /* Increment the program counter */
648 void Emit0 (unsigned char OPC)
649 /* Emit an instruction with a zero sized operand */
651 /* First fragment, wrong type or out of space, create new one */
652 Fragment* F = NewFragment (FRAG_LITERAL, 1);
658 void Emit1 (unsigned char OPC, ExprNode* Value)
659 /* Emit an instruction with an one byte argument */
667 void Emit2 (unsigned char OPC, ExprNode* Value)
668 /* Emit an instruction with a two byte argument */
676 void Emit3 (unsigned char OPC, ExprNode* Expr)
677 /* Emit an instruction with a three byte argument */
685 void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
686 /* Emit an instruction with a three byte argument and separate bank */
695 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
696 /* Emit an opcode with a PC relative argument of one or two bytes */
700 F = NewFragment (FRAG_SEXPR, Size);
706 void EmitData (const unsigned char* Data, unsigned Size)
707 /* Emit data into the current segment */
709 /* Create lots of fragments for the data */
713 /* Determine the length of the next fragment */
715 if (Len > sizeof (F->V.Data)) {
716 Len = sizeof (F->V.Data);
719 /* Create a new fragment */
720 F = NewFragment (FRAG_LITERAL, Len);
723 memcpy (F->V.Data, Data, Len);
734 void EmitByte (ExprNode* Expr)
737 if (IsConstExpr (Expr)) {
738 /* Constant expression, emit literal byte */
739 long Val = GetExprVal (Expr);
741 if ((Val & ~0xFF) != 0) {
746 /* Create a new fragment */
747 Fragment* F = NewFragment (FRAG_EXPR, 1);
756 void EmitWord (ExprNode* Expr)
759 if (IsConstExpr (Expr)) {
760 /* Constant expression, emit literal byte */
761 long Val = GetExprVal (Expr);
763 if ((Val & ~0xFFFF) != 0) {
767 Emit0 ((Val >> 8) & 0xFF);
769 /* Create a new fragment */
770 Fragment* F = NewFragment (FRAG_EXPR, 2);
779 void EmitFarAddr (ExprNode* Expr)
780 /* Emit a 24 bit expression */
782 if (IsConstExpr (Expr)) {
783 /* Constant expression, emit literal byte */
784 long Val = GetExprVal (Expr);
786 if ((Val & ~0xFFFFFF) != 0) {
790 Emit0 ((Val >> 8) & 0xFF);
791 Emit0 ((Val >> 16) & 0xFF);
793 /* Create a new fragment */
794 Fragment* F = NewFragment (FRAG_EXPR, 3);
803 void EmitDWord (ExprNode* Expr)
806 if (IsConstExpr (Expr)) {
807 /* Constant expression, emit literal byte */
808 long Val = GetExprVal (Expr);
811 Emit0 ((Val >> 8) & 0xFF);
812 Emit0 ((Val >> 16) & 0xFF);
813 Emit0 ((Val >> 24) & 0xFF);
815 /* Create a new fragment */
816 Fragment* F = NewFragment (FRAG_EXPR, 4);
825 void EmitFill (unsigned long Count)
826 /* Emit Count fill bytes */
829 /* Calculate the size of the next chunk */
830 unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
834 NewFragment (FRAG_FILL, Chunk);