1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* codeseg.c */ |
4 | /* */ |
5 | /* Code segment structure */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2011, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 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 <ctype.h> |
38 | |
39 | /* common */ |
40 | #include "chartype.h" |
41 | #include "check.h" |
42 | #include "debugflag.h" |
43 | #include "global.h" |
44 | #include "hashfunc.h" |
45 | #include "strbuf.h" |
46 | #include "strutil.h" |
47 | #include "xmalloc.h" |
48 | |
49 | /* cc65 */ |
50 | #include "asmlabel.h" |
51 | #include "codeent.h" |
52 | #include "codeinfo.h" |
53 | #include "codeseg.h" |
54 | #include "datatype.h" |
55 | #include "error.h" |
56 | #include "global.h" |
57 | #include "ident.h" |
58 | #include "output.h" |
59 | #include "symentry.h" |
60 | |
61 | |
62 | |
63 | /*****************************************************************************/ |
64 | /* Helper functions */ |
65 | /*****************************************************************************/ |
66 | |
67 | |
68 | |
69 | static void (const CodeSeg* S) |
70 | /* Print a comment with the function signature to the output file */ |
71 | { |
72 | /* Get the associated function */ |
73 | const SymEntry* Func = S->Func; |
74 | |
75 | /* If this is a global code segment, do nothing */ |
76 | if (Func) { |
77 | WriteOutput ("; ---------------------------------------------------------------\n" |
78 | "; " ); |
79 | PrintFuncSig (OutputFile, Func->Name, Func->Type); |
80 | WriteOutput ("\n" |
81 | "; ---------------------------------------------------------------\n" |
82 | "\n" ); |
83 | } |
84 | } |
85 | |
86 | |
87 | |
88 | static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E) |
89 | /* Move all labels from the label pool to the given entry and remove them |
90 | ** from the pool. |
91 | */ |
92 | { |
93 | /* Transfer the labels if we have any */ |
94 | unsigned I; |
95 | unsigned LabelCount = CollCount (&S->Labels); |
96 | for (I = 0; I < LabelCount; ++I) { |
97 | |
98 | /* Get the label */ |
99 | CodeLabel* L = CollAt (&S->Labels, I); |
100 | |
101 | /* Attach it to the entry */ |
102 | CE_AttachLabel (E, L); |
103 | } |
104 | |
105 | /* Delete the transfered labels */ |
106 | CollDeleteAll (&S->Labels); |
107 | } |
108 | |
109 | |
110 | |
111 | static void CS_MoveLabelsToPool (CodeSeg* S, CodeEntry* E) |
112 | /* Move the labels of the code entry E to the label pool of the code segment */ |
113 | { |
114 | unsigned LabelCount = CE_GetLabelCount (E); |
115 | while (LabelCount--) { |
116 | CodeLabel* L = CE_GetLabel (E, LabelCount); |
117 | L->Owner = 0; |
118 | CollAppend (&S->Labels, L); |
119 | } |
120 | CollDeleteAll (&E->Labels); |
121 | } |
122 | |
123 | |
124 | |
125 | static CodeLabel* CS_FindLabel (CodeSeg* S, const char* Name, unsigned Hash) |
126 | /* Find the label with the given name. Return the label or NULL if not found */ |
127 | { |
128 | /* Get the first hash chain entry */ |
129 | CodeLabel* L = S->LabelHash[Hash]; |
130 | |
131 | /* Search the list */ |
132 | while (L) { |
133 | if (strcmp (Name, L->Name) == 0) { |
134 | /* Found */ |
135 | break; |
136 | } |
137 | L = L->Next; |
138 | } |
139 | return L; |
140 | } |
141 | |
142 | |
143 | |
144 | static CodeLabel* CS_NewCodeLabel (CodeSeg* S, const char* Name, unsigned Hash) |
145 | /* Create a new label and insert it into the label hash table */ |
146 | { |
147 | /* Create a new label */ |
148 | CodeLabel* L = NewCodeLabel (Name, Hash); |
149 | |
150 | /* Enter the label into the hash table */ |
151 | L->Next = S->LabelHash[L->Hash]; |
152 | S->LabelHash[L->Hash] = L; |
153 | |
154 | /* Return the new label */ |
155 | return L; |
156 | } |
157 | |
158 | |
159 | |
160 | static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L) |
161 | /* Remove the given code label from the hash list */ |
162 | { |
163 | /* Get the first entry in the hash chain */ |
164 | CodeLabel* List = S->LabelHash[L->Hash]; |
165 | CHECK (List != 0); |
166 | |
167 | /* First, remove the label from the hash chain */ |
168 | if (List == L) { |
169 | /* First entry in hash chain */ |
170 | S->LabelHash[L->Hash] = L->Next; |
171 | } else { |
172 | /* Must search through the chain */ |
173 | while (List->Next != L) { |
174 | /* If we've reached the end of the chain, something is *really* wrong */ |
175 | CHECK (List->Next != 0); |
176 | /* Next entry */ |
177 | List = List->Next; |
178 | } |
179 | /* The next entry is the one, we have been searching for */ |
180 | List->Next = L->Next; |
181 | } |
182 | } |
183 | |
184 | |
185 | |
186 | /*****************************************************************************/ |
187 | /* Functions for parsing instructions */ |
188 | /*****************************************************************************/ |
189 | |
190 | |
191 | |
192 | static const char* SkipSpace (const char* S) |
193 | /* Skip white space and return an updated pointer */ |
194 | { |
195 | while (IsSpace (*S)) { |
196 | ++S; |
197 | } |
198 | return S; |
199 | } |
200 | |
201 | |
202 | |
203 | static const char* ReadToken (const char* L, const char* Term, |
204 | char* Buf, unsigned BufSize) |
205 | /* Read the next token into Buf, return the updated line pointer. The |
206 | ** token is terminated by one of the characters given in term. |
207 | */ |
208 | { |
209 | /* Read/copy the token */ |
210 | unsigned I = 0; |
211 | unsigned ParenCount = 0; |
212 | while (*L && (ParenCount > 0 || strchr (Term, *L) == 0)) { |
213 | if (I < BufSize-1) { |
214 | Buf[I] = *L; |
215 | } else if (I == BufSize-1) { |
216 | /* Cannot store this character, this is an input error (maybe |
217 | ** identifier too long or similar). |
218 | */ |
219 | Error ("ASM code error: syntax error" ); |
220 | } |
221 | ++I; |
222 | if (*L == ')') { |
223 | --ParenCount; |
224 | } else if (*L == '(') { |
225 | ++ParenCount; |
226 | } |
227 | ++L; |
228 | } |
229 | |
230 | /* Terminate the buffer contents */ |
231 | Buf[I] = '\0'; |
232 | |
233 | /* Return the updated line pointer */ |
234 | return L; |
235 | } |
236 | |
237 | |
238 | |
239 | static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) |
240 | /* Parse an instruction nnd generate a code entry from it. If the line contains |
241 | ** errors, output an error message and return NULL. |
242 | ** For simplicity, we don't accept the broad range of input a "real" assembler |
243 | ** does. The instruction and the argument are expected to be separated by |
244 | ** white space, for example. |
245 | */ |
246 | { |
247 | char Mnemo[IDENTSIZE+10]; |
248 | const OPCDesc* OPC; |
249 | am_t AM = 0; /* Initialize to keep gcc silent */ |
250 | char Arg[IDENTSIZE+10]; |
251 | char Reg; |
252 | CodeEntry* E; |
253 | CodeLabel* Label; |
254 | |
255 | /* Read the first token and skip white space after it */ |
256 | L = SkipSpace (ReadToken (L, " \t:" , Mnemo, sizeof (Mnemo))); |
257 | |
258 | /* Check if we have a label */ |
259 | if (*L == ':') { |
260 | |
261 | /* Skip the colon and following white space */ |
262 | L = SkipSpace (L+1); |
263 | |
264 | /* Add the label */ |
265 | CS_AddLabel (S, Mnemo); |
266 | |
267 | /* If we have reached end of line, bail out, otherwise a mnemonic |
268 | ** may follow. |
269 | */ |
270 | if (*L == '\0') { |
271 | return 0; |
272 | } |
273 | |
274 | L = SkipSpace (ReadToken (L, " \t" , Mnemo, sizeof (Mnemo))); |
275 | } |
276 | |
277 | /* Try to find the opcode description for the mnemonic */ |
278 | OPC = FindOP65 (Mnemo); |
279 | |
280 | /* If we didn't find the opcode, print an error and bail out */ |
281 | if (OPC == 0) { |
282 | Error ("ASM code error: %s is not a valid mnemonic" , Mnemo); |
283 | return 0; |
284 | } |
285 | |
286 | /* Get the addressing mode */ |
287 | Arg[0] = '\0'; |
288 | switch (*L) { |
289 | |
290 | case '\0': |
291 | /* Implicit or accu */ |
292 | if (OPC->Info & OF_NOIMP) { |
293 | AM = AM65_ACC; |
294 | } else { |
295 | AM = AM65_IMP; |
296 | } |
297 | break; |
298 | |
299 | case '#': |
300 | /* Immidiate */ |
301 | StrCopy (Arg, sizeof (Arg), L+1); |
302 | AM = AM65_IMM; |
303 | break; |
304 | |
305 | case '(': |
306 | /* Indirect */ |
307 | L = ReadToken (L+1, ",)" , Arg, sizeof (Arg)); |
308 | |
309 | /* Check for errors */ |
310 | if (*L == '\0') { |
311 | Error ("ASM code error: syntax error" ); |
312 | return 0; |
313 | } |
314 | |
315 | /* Check the different indirect modes */ |
316 | if (*L == ',') { |
317 | /* Expect zp x indirect */ |
318 | L = SkipSpace (L+1); |
319 | if (toupper (*L) != 'X') { |
320 | Error ("ASM code error: 'X' expected" ); |
321 | return 0; |
322 | } |
323 | L = SkipSpace (L+1); |
324 | if (*L != ')') { |
325 | Error ("ASM code error: ')' expected" ); |
326 | return 0; |
327 | } |
328 | L = SkipSpace (L+1); |
329 | if (*L != '\0') { |
330 | Error ("ASM code error: syntax error" ); |
331 | return 0; |
332 | } |
333 | AM = AM65_ZPX_IND; |
334 | } else if (*L == ')') { |
335 | /* zp indirect or zp indirect, y */ |
336 | L = SkipSpace (L+1); |
337 | if (*L == ',') { |
338 | L = SkipSpace (L+1); |
339 | if (toupper (*L) != 'Y') { |
340 | Error ("ASM code error: 'Y' expected" ); |
341 | return 0; |
342 | } |
343 | L = SkipSpace (L+1); |
344 | if (*L != '\0') { |
345 | Error ("ASM code error: syntax error" ); |
346 | return 0; |
347 | } |
348 | AM = AM65_ZP_INDY; |
349 | } else if (*L == '\0') { |
350 | AM = AM65_ZP_IND; |
351 | } else { |
352 | Error ("ASM code error: syntax error" ); |
353 | return 0; |
354 | } |
355 | } |
356 | break; |
357 | |
358 | case 'a': |
359 | case 'A': |
360 | /* Accumulator? */ |
361 | if (L[1] == '\0') { |
362 | AM = AM65_ACC; |
363 | break; |
364 | } |
365 | /* FALLTHROUGH */ |
366 | |
367 | default: |
368 | /* Absolute, maybe indexed */ |
369 | L = ReadToken (L, "," , Arg, sizeof (Arg)); |
370 | if (*L == '\0') { |
371 | /* Absolute, zeropage or branch */ |
372 | if ((OPC->Info & OF_BRA) != 0) { |
373 | /* Branch */ |
374 | AM = AM65_BRA; |
375 | } else if (GetZPInfo(Arg) != 0) { |
376 | AM = AM65_ZP; |
377 | } else { |
378 | /* Check for subroutine call to local label */ |
379 | if ((OPC->Info & OF_CALL) && IsLocalLabelName (Arg)) { |
380 | Error ("ASM code error: " |
381 | "Cannot use local label '%s' in subroutine call" , |
382 | Arg); |
383 | } |
384 | AM = AM65_ABS; |
385 | } |
386 | } else if (*L == ',') { |
387 | /* Indexed */ |
388 | L = SkipSpace (L+1); |
389 | if (*L == '\0') { |
390 | Error ("ASM code error: syntax error" ); |
391 | return 0; |
392 | } else { |
393 | Reg = toupper (*L); |
394 | L = SkipSpace (L+1); |
395 | if (Reg == 'X') { |
396 | if (GetZPInfo(Arg) != 0) { |
397 | AM = AM65_ZPX; |
398 | } else { |
399 | AM = AM65_ABSX; |
400 | } |
401 | } else if (Reg == 'Y') { |
402 | AM = AM65_ABSY; |
403 | } else { |
404 | Error ("ASM code error: syntax error" ); |
405 | return 0; |
406 | } |
407 | if (*L != '\0') { |
408 | Error ("ASM code error: syntax error" ); |
409 | return 0; |
410 | } |
411 | } |
412 | } |
413 | break; |
414 | |
415 | } |
416 | |
417 | /* If the instruction is a branch, check for the label and generate it |
418 | ** if it does not exist. This may lead to unused labels (if the label |
419 | ** is actually an external one) which are removed by the CS_MergeLabels |
420 | ** function later. |
421 | */ |
422 | Label = 0; |
423 | if (AM == AM65_BRA) { |
424 | |
425 | /* Generate the hash over the label, then search for the label */ |
426 | unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE; |
427 | Label = CS_FindLabel (S, Arg, Hash); |
428 | |
429 | /* If we don't have the label, it's a forward ref - create it unless |
430 | ** it's an external function. |
431 | */ |
432 | if (Label == 0 && (OPC->OPC != OP65_JMP || IsLocalLabelName (Arg)) ) { |
433 | /* Generate a new label */ |
434 | Label = CS_NewCodeLabel (S, Arg, Hash); |
435 | } |
436 | } |
437 | |
438 | /* We do now have the addressing mode in AM. Allocate a new CodeEntry |
439 | ** structure and initialize it. |
440 | */ |
441 | E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI); |
442 | |
443 | /* Return the new code entry */ |
444 | return E; |
445 | } |
446 | |
447 | |
448 | |
449 | /*****************************************************************************/ |
450 | /* Code */ |
451 | /*****************************************************************************/ |
452 | |
453 | |
454 | |
455 | CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func) |
456 | /* Create a new code segment, initialize and return it */ |
457 | { |
458 | unsigned I; |
459 | const Type* RetType; |
460 | |
461 | /* Allocate memory */ |
462 | CodeSeg* S = xmalloc (sizeof (CodeSeg)); |
463 | |
464 | /* Initialize the fields */ |
465 | S->SegName = xstrdup (SegName); |
466 | S->Func = Func; |
467 | InitCollection (&S->Entries); |
468 | InitCollection (&S->Labels); |
469 | for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) { |
470 | S->LabelHash[I] = 0; |
471 | } |
472 | |
473 | /* If we have a function given, get the return type of the function. |
474 | ** Assume ANY return type besides void will use the A and X registers. |
475 | */ |
476 | if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) { |
477 | if (SizeOf (RetType) == SizeOf (type_long)) { |
478 | S->ExitRegs = REG_EAX; |
479 | } else { |
480 | S->ExitRegs = REG_AX; |
481 | } |
482 | } else { |
483 | S->ExitRegs = REG_NONE; |
484 | } |
485 | |
486 | /* Copy the global optimization settings */ |
487 | S->Optimize = (unsigned char) IS_Get (&Optimize); |
488 | S->CodeSizeFactor = (unsigned) IS_Get (&CodeSizeFactor); |
489 | |
490 | /* Return the new struct */ |
491 | return S; |
492 | } |
493 | |
494 | |
495 | |
496 | void CS_AddEntry (CodeSeg* S, struct CodeEntry* E) |
497 | /* Add an entry to the given code segment */ |
498 | { |
499 | /* Transfer the labels if we have any */ |
500 | CS_MoveLabelsToEntry (S, E); |
501 | |
502 | /* Add the entry to the list of code entries in this segment */ |
503 | CollAppend (&S->Entries, E); |
504 | } |
505 | |
506 | |
507 | |
508 | void CS_AddVLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) |
509 | /* Add a line to the given code segment */ |
510 | { |
511 | const char* L; |
512 | CodeEntry* E; |
513 | char Token[IDENTSIZE+10]; |
514 | |
515 | /* Format the line */ |
516 | StrBuf Buf = STATIC_STRBUF_INITIALIZER; |
517 | SB_VPrintf (&Buf, Format, ap); |
518 | |
519 | /* Skip whitespace */ |
520 | L = SkipSpace (SB_GetConstBuf (&Buf)); |
521 | |
522 | /* Check which type of instruction we have */ |
523 | E = 0; /* Assume no insn created */ |
524 | switch (*L) { |
525 | |
526 | case '\0': |
527 | /* Empty line, just ignore it */ |
528 | break; |
529 | |
530 | case ';': |
531 | /* Comment or hint, ignore it for now */ |
532 | break; |
533 | |
534 | case '.': |
535 | /* Control instruction */ |
536 | ReadToken (L, " \t" , Token, sizeof (Token)); |
537 | Error ("ASM code error: Pseudo instruction '%s' not supported" , Token); |
538 | break; |
539 | |
540 | default: |
541 | E = ParseInsn (S, LI, L); |
542 | break; |
543 | } |
544 | |
545 | /* If we have a code entry, transfer the labels and insert it */ |
546 | if (E) { |
547 | CS_AddEntry (S, E); |
548 | } |
549 | |
550 | /* Cleanup the string buffer */ |
551 | SB_Done (&Buf); |
552 | } |
553 | |
554 | |
555 | |
556 | void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...) |
557 | /* Add a line to the given code segment */ |
558 | { |
559 | va_list ap; |
560 | va_start (ap, Format); |
561 | CS_AddVLine (S, LI, Format, ap); |
562 | va_end (ap); |
563 | } |
564 | |
565 | |
566 | |
567 | void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index) |
568 | /* Insert the code entry at the index given. Following code entries will be |
569 | ** moved to slots with higher indices. |
570 | */ |
571 | { |
572 | /* Insert the entry into the collection */ |
573 | CollInsert (&S->Entries, E, Index); |
574 | } |
575 | |
576 | |
577 | |
578 | void CS_DelEntry (CodeSeg* S, unsigned Index) |
579 | /* Delete an entry from the code segment. This includes moving any associated |
580 | ** labels, removing references to labels and even removing the referenced labels |
581 | ** if the reference count drops to zero. |
582 | ** Note: Labels are moved forward if possible, that is, they are moved to the |
583 | ** next insn (not the preceeding one). |
584 | */ |
585 | { |
586 | /* Get the code entry for the given index */ |
587 | CodeEntry* E = CS_GetEntry (S, Index); |
588 | |
589 | /* If the entry has a labels, we have to move this label to the next insn. |
590 | ** If there is no next insn, move the label into the code segement label |
591 | ** pool. The operation is further complicated by the fact that the next |
592 | ** insn may already have a label. In that case change all reference to |
593 | ** this label and delete the label instead of moving it. |
594 | */ |
595 | unsigned Count = CE_GetLabelCount (E); |
596 | if (Count > 0) { |
597 | |
598 | /* The instruction has labels attached. Check if there is a next |
599 | ** instruction. |
600 | */ |
601 | if (Index == CS_GetEntryCount (S)-1) { |
602 | |
603 | /* No next instruction, move to the codeseg label pool */ |
604 | CS_MoveLabelsToPool (S, E); |
605 | |
606 | } else { |
607 | |
608 | /* There is a next insn, get it */ |
609 | CodeEntry* N = CS_GetEntry (S, Index+1); |
610 | |
611 | /* Move labels to the next entry */ |
612 | CS_MoveLabels (S, E, N); |
613 | |
614 | } |
615 | } |
616 | |
617 | /* If this insn references a label, remove the reference. And, if the |
618 | ** the reference count for this label drops to zero, remove this label. |
619 | */ |
620 | if (E->JumpTo) { |
621 | /* Remove the reference */ |
622 | CS_RemoveLabelRef (S, E); |
623 | } |
624 | |
625 | /* Delete the pointer to the insn */ |
626 | CollDelete (&S->Entries, Index); |
627 | |
628 | /* Delete the instruction itself */ |
629 | FreeCodeEntry (E); |
630 | } |
631 | |
632 | |
633 | |
634 | void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count) |
635 | /* Delete a range of code entries. This includes removing references to labels, |
636 | ** labels attached to the entries and so on. |
637 | */ |
638 | { |
639 | /* Start deleting the entries from the rear, because this involves less |
640 | ** memory moving. |
641 | */ |
642 | while (Count--) { |
643 | CS_DelEntry (S, Start + Count); |
644 | } |
645 | } |
646 | |
647 | |
648 | |
649 | void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos) |
650 | /* Move a range of entries from one position to another. Start is the index |
651 | ** of the first entry to move, Count is the number of entries and NewPos is |
652 | ** the index of the target entry. The entry with the index Start will later |
653 | ** have the index NewPos. All entries with indices NewPos and above are |
654 | ** moved to higher indices. If the code block is moved to the end of the |
655 | ** current code, and if pending labels exist, these labels will get attached |
656 | ** to the first instruction of the moved block (the first one after the |
657 | ** current code end) |
658 | */ |
659 | { |
660 | /* Transparently handle an empty range */ |
661 | if (Count == 0) { |
662 | return; |
663 | } |
664 | |
665 | /* If NewPos is at the end of the code segment, move any labels from the |
666 | ** label pool to the first instruction of the moved range. |
667 | */ |
668 | if (NewPos == CS_GetEntryCount (S)) { |
669 | CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start)); |
670 | } |
671 | |
672 | /* Move the code block to the destination */ |
673 | CollMoveMultiple (&S->Entries, Start, Count, NewPos); |
674 | } |
675 | |
676 | |
677 | |
678 | struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index) |
679 | /* Get the code entry preceeding the one with the index Index. If there is no |
680 | ** preceeding code entry, return NULL. |
681 | */ |
682 | { |
683 | if (Index == 0) { |
684 | /* This is the first entry */ |
685 | return 0; |
686 | } else { |
687 | /* Previous entry available */ |
688 | return CollAtUnchecked (&S->Entries, Index-1); |
689 | } |
690 | } |
691 | |
692 | |
693 | |
694 | struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index) |
695 | /* Get the code entry following the one with the index Index. If there is no |
696 | ** following code entry, return NULL. |
697 | */ |
698 | { |
699 | if (Index >= CollCount (&S->Entries)-1) { |
700 | /* This is the last entry */ |
701 | return 0; |
702 | } else { |
703 | /* Code entries left */ |
704 | return CollAtUnchecked (&S->Entries, Index+1); |
705 | } |
706 | } |
707 | |
708 | |
709 | |
710 | int CS_GetEntries (CodeSeg* S, struct CodeEntry** List, |
711 | unsigned Start, unsigned Count) |
712 | /* Get Count code entries into List starting at index start. Return true if |
713 | ** we got the lines, return false if not enough lines were available. |
714 | */ |
715 | { |
716 | /* Check if enough entries are available */ |
717 | if (Start + Count > CollCount (&S->Entries)) { |
718 | return 0; |
719 | } |
720 | |
721 | /* Copy the entries */ |
722 | while (Count--) { |
723 | *List++ = CollAtUnchecked (&S->Entries, Start++); |
724 | } |
725 | |
726 | /* We have the entries */ |
727 | return 1; |
728 | } |
729 | |
730 | |
731 | |
732 | unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E) |
733 | /* Return the index of a code entry */ |
734 | { |
735 | int Index = CollIndex (&S->Entries, E); |
736 | CHECK (Index >= 0); |
737 | return Index; |
738 | } |
739 | |
740 | |
741 | |
742 | int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count) |
743 | /* Return true if any of the code entries in the given range has a label |
744 | ** attached. If the code segment does not span the given range, check the |
745 | ** possible span instead. |
746 | */ |
747 | { |
748 | unsigned EntryCount = CS_GetEntryCount(S); |
749 | |
750 | /* Adjust count. We expect at least Start to be valid. */ |
751 | CHECK (Start < EntryCount); |
752 | if (Start + Count > EntryCount) { |
753 | Count = EntryCount - Start; |
754 | } |
755 | |
756 | /* Check each entry. Since we have validated the index above, we may |
757 | ** use the unchecked access function in the loop which is faster. |
758 | */ |
759 | while (Count--) { |
760 | const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++); |
761 | if (CE_HasLabel (E)) { |
762 | return 1; |
763 | } |
764 | } |
765 | |
766 | /* No label in the complete range */ |
767 | return 0; |
768 | } |
769 | |
770 | |
771 | |
772 | CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name) |
773 | /* Add a code label for the next instruction to follow */ |
774 | { |
775 | /* Calculate the hash from the name */ |
776 | unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE; |
777 | |
778 | /* Try to find the code label if it does already exist */ |
779 | CodeLabel* L = CS_FindLabel (S, Name, Hash); |
780 | |
781 | /* Did we find it? */ |
782 | if (L) { |
783 | /* We found it - be sure it does not already have an owner */ |
784 | if (L->Owner) { |
785 | Error ("ASM label '%s' is already defined" , Name); |
786 | return L; |
787 | } |
788 | } else { |
789 | /* Not found - create a new one */ |
790 | L = CS_NewCodeLabel (S, Name, Hash); |
791 | } |
792 | |
793 | /* Safety. This call is quite costly, but safety is better */ |
794 | if (CollIndex (&S->Labels, L) >= 0) { |
795 | Error ("ASM label '%s' is already defined" , Name); |
796 | return L; |
797 | } |
798 | |
799 | /* We do now have a valid label. Remember it for later */ |
800 | CollAppend (&S->Labels, L); |
801 | |
802 | /* Return the label */ |
803 | return L; |
804 | } |
805 | |
806 | |
807 | |
808 | CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E) |
809 | /* If the code entry E does already have a label, return it. Otherwise |
810 | ** create a new label, attach it to E and return it. |
811 | */ |
812 | { |
813 | CodeLabel* L; |
814 | |
815 | if (CE_HasLabel (E)) { |
816 | |
817 | /* Get the label from this entry */ |
818 | L = CE_GetLabel (E, 0); |
819 | |
820 | } else { |
821 | |
822 | /* Get a new name */ |
823 | const char* Name = LocalLabelName (GetLocalLabel ()); |
824 | |
825 | /* Generate the hash over the name */ |
826 | unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE; |
827 | |
828 | /* Create a new label */ |
829 | L = CS_NewCodeLabel (S, Name, Hash); |
830 | |
831 | /* Attach this label to the code entry */ |
832 | CE_AttachLabel (E, L); |
833 | |
834 | } |
835 | |
836 | /* Return the label */ |
837 | return L; |
838 | } |
839 | |
840 | |
841 | |
842 | void CS_DelLabel (CodeSeg* S, CodeLabel* L) |
843 | /* Remove references from this label and delete it. */ |
844 | { |
845 | unsigned Count, I; |
846 | |
847 | /* First, remove the label from the hash chain */ |
848 | CS_RemoveLabelFromHash (S, L); |
849 | |
850 | /* Remove references from insns jumping to this label */ |
851 | Count = CollCount (&L->JumpFrom); |
852 | for (I = 0; I < Count; ++I) { |
853 | /* Get the insn referencing this label */ |
854 | CodeEntry* E = CollAt (&L->JumpFrom, I); |
855 | /* Remove the reference */ |
856 | CE_ClearJumpTo (E); |
857 | } |
858 | CollDeleteAll (&L->JumpFrom); |
859 | |
860 | /* Remove the reference to the owning instruction if it has one. The |
861 | ** function may be called for a label without an owner when deleting |
862 | ** unfinished parts of the code. This is unfortunate since it allows |
863 | ** errors to slip through. |
864 | */ |
865 | if (L->Owner) { |
866 | CollDeleteItem (&L->Owner->Labels, L); |
867 | } |
868 | |
869 | /* All references removed, delete the label itself */ |
870 | FreeCodeLabel (L); |
871 | } |
872 | |
873 | |
874 | |
875 | void CS_MergeLabels (CodeSeg* S) |
876 | /* Merge code labels. That means: For each instruction, remove all labels but |
877 | ** one and adjust references accordingly. |
878 | */ |
879 | { |
880 | unsigned I; |
881 | unsigned J; |
882 | |
883 | /* First, remove all labels from the label symbol table that don't have an |
884 | ** owner (this means that they are actually external labels but we didn't |
885 | ** know that previously since they may have also been forward references). |
886 | */ |
887 | for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) { |
888 | |
889 | /* Get the first label in this hash chain */ |
890 | CodeLabel** L = &S->LabelHash[I]; |
891 | while (*L) { |
892 | if ((*L)->Owner == 0) { |
893 | |
894 | /* The label does not have an owner, remove it from the chain */ |
895 | CodeLabel* X = *L; |
896 | *L = X->Next; |
897 | |
898 | /* Cleanup any entries jumping to this label */ |
899 | for (J = 0; J < CL_GetRefCount (X); ++J) { |
900 | /* Get the entry referencing this label */ |
901 | CodeEntry* E = CL_GetRef (X, J); |
902 | /* And remove the reference. Do NOT call CE_ClearJumpTo |
903 | ** here, because this will also clear the label name, |
904 | ** which is not what we want. |
905 | */ |
906 | E->JumpTo = 0; |
907 | } |
908 | |
909 | /* Print some debugging output */ |
910 | if (Debug) { |
911 | printf ("Removing unused global label '%s'" , X->Name); |
912 | } |
913 | |
914 | /* And free the label */ |
915 | FreeCodeLabel (X); |
916 | } else { |
917 | /* Label is owned, point to next code label pointer */ |
918 | L = &((*L)->Next); |
919 | } |
920 | } |
921 | } |
922 | |
923 | /* Walk over all code entries */ |
924 | for (I = 0; I < CS_GetEntryCount (S); ++I) { |
925 | |
926 | CodeLabel* RefLab; |
927 | unsigned J; |
928 | |
929 | /* Get a pointer to the next entry */ |
930 | CodeEntry* E = CS_GetEntry (S, I); |
931 | |
932 | /* If this entry has zero labels, continue with the next one */ |
933 | unsigned LabelCount = CE_GetLabelCount (E); |
934 | if (LabelCount == 0) { |
935 | continue; |
936 | } |
937 | |
938 | /* We have at least one label. Use the first one as reference label. */ |
939 | RefLab = CE_GetLabel (E, 0); |
940 | |
941 | /* Walk through the remaining labels and change references to these |
942 | ** labels to a reference to the one and only label. Delete the labels |
943 | ** that are no longer used. To increase performance, walk backwards |
944 | ** through the list. |
945 | */ |
946 | for (J = LabelCount-1; J >= 1; --J) { |
947 | |
948 | /* Get the next label */ |
949 | CodeLabel* L = CE_GetLabel (E, J); |
950 | |
951 | /* Move all references from this label to the reference label */ |
952 | CL_MoveRefs (L, RefLab); |
953 | |
954 | /* Remove the label completely. */ |
955 | CS_DelLabel (S, L); |
956 | } |
957 | |
958 | /* The reference label is the only remaining label. Check if there |
959 | ** are any references to this label, and delete it if this is not |
960 | ** the case. |
961 | */ |
962 | if (CollCount (&RefLab->JumpFrom) == 0) { |
963 | /* Delete the label */ |
964 | CS_DelLabel (S, RefLab); |
965 | } |
966 | } |
967 | } |
968 | |
969 | |
970 | |
971 | void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New) |
972 | /* Move all labels from Old to New. The routine will move the labels itself |
973 | ** if New does not have any labels, and move references if there is at least |
974 | ** a label for new. If references are moved, the old label is deleted |
975 | ** afterwards. |
976 | */ |
977 | { |
978 | /* Get the number of labels to move */ |
979 | unsigned OldLabelCount = CE_GetLabelCount (Old); |
980 | |
981 | /* Does the new entry have itself a label? */ |
982 | if (CE_HasLabel (New)) { |
983 | |
984 | /* The new entry does already have a label - move references */ |
985 | CodeLabel* NewLabel = CE_GetLabel (New, 0); |
986 | while (OldLabelCount--) { |
987 | |
988 | /* Get the next label */ |
989 | CodeLabel* OldLabel = CE_GetLabel (Old, OldLabelCount); |
990 | |
991 | /* Move references */ |
992 | CL_MoveRefs (OldLabel, NewLabel); |
993 | |
994 | /* Delete the label */ |
995 | CS_DelLabel (S, OldLabel); |
996 | |
997 | } |
998 | |
999 | } else { |
1000 | |
1001 | /* The new entry does not have a label, just move them */ |
1002 | while (OldLabelCount--) { |
1003 | |
1004 | /* Move the label to the new entry */ |
1005 | CE_MoveLabel (CE_GetLabel (Old, OldLabelCount), New); |
1006 | |
1007 | } |
1008 | |
1009 | } |
1010 | } |
1011 | |
1012 | |
1013 | |
1014 | void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E) |
1015 | /* Remove the reference between E and the label it jumps to. The reference |
1016 | ** will be removed on both sides and E->JumpTo will be 0 after that. If |
1017 | ** the reference was the only one for the label, the label will get |
1018 | ** deleted. |
1019 | */ |
1020 | { |
1021 | /* Get a pointer to the label and make sure it exists */ |
1022 | CodeLabel* L = E->JumpTo; |
1023 | CHECK (L != 0); |
1024 | |
1025 | /* Delete the entry from the label */ |
1026 | CollDeleteItem (&L->JumpFrom, E); |
1027 | |
1028 | /* The entry jumps no longer to L */ |
1029 | CE_ClearJumpTo (E); |
1030 | |
1031 | /* If there are no more references, delete the label */ |
1032 | if (CollCount (&L->JumpFrom) == 0) { |
1033 | CS_DelLabel (S, L); |
1034 | } |
1035 | } |
1036 | |
1037 | |
1038 | |
1039 | void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L) |
1040 | /* Change the reference of E to L instead of the current one. If this |
1041 | ** was the only reference to the old label, the old label will get |
1042 | ** deleted. |
1043 | */ |
1044 | { |
1045 | /* Get the old label */ |
1046 | CodeLabel* OldLabel = E->JumpTo; |
1047 | |
1048 | /* Be sure that code entry references a label */ |
1049 | PRECONDITION (OldLabel != 0); |
1050 | |
1051 | /* Remove the reference to our label */ |
1052 | CS_RemoveLabelRef (S, E); |
1053 | |
1054 | /* Use the new label */ |
1055 | CL_AddRef (L, E); |
1056 | } |
1057 | |
1058 | |
1059 | |
1060 | void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last) |
1061 | /* Delete all entries between first and last, both inclusive. The function |
1062 | ** can only handle basic blocks (First is the only entry, Last the only exit) |
1063 | ** and no open labels. It will call FAIL if any of these preconditions are |
1064 | ** violated. |
1065 | */ |
1066 | { |
1067 | unsigned I; |
1068 | CodeEntry* FirstEntry; |
1069 | |
1070 | /* Do some sanity checks */ |
1071 | CHECK (First <= Last && Last < CS_GetEntryCount (S)); |
1072 | |
1073 | /* If Last is actually the last insn, call CS_DelCodeAfter instead, which |
1074 | ** is more flexible in this case. |
1075 | */ |
1076 | if (Last == CS_GetEntryCount (S) - 1) { |
1077 | CS_DelCodeAfter (S, First); |
1078 | return; |
1079 | } |
1080 | |
1081 | /* Get the first entry and check if it has any labels. If it has, move |
1082 | ** them to the insn following Last. If Last is the last insn of the code |
1083 | ** segment, make them ownerless and move them to the label pool. |
1084 | */ |
1085 | FirstEntry = CS_GetEntry (S, First); |
1086 | if (CE_HasLabel (FirstEntry)) { |
1087 | /* Get the entry following last */ |
1088 | CodeEntry* FollowingEntry = CS_GetNextEntry (S, Last); |
1089 | if (FollowingEntry) { |
1090 | /* There is an entry after Last - move the labels */ |
1091 | CS_MoveLabels (S, FirstEntry, FollowingEntry); |
1092 | } else { |
1093 | /* Move the labels to the pool and clear the owner pointer */ |
1094 | CS_MoveLabelsToPool (S, FirstEntry); |
1095 | } |
1096 | } |
1097 | |
1098 | /* First pass: Delete all references to labels. If the reference count |
1099 | ** for a label drops to zero, delete it. |
1100 | */ |
1101 | for (I = Last; I >= First; --I) { |
1102 | |
1103 | /* Get the next entry */ |
1104 | CodeEntry* E = CS_GetEntry (S, I); |
1105 | |
1106 | /* Check if this entry has a label reference */ |
1107 | if (E->JumpTo) { |
1108 | |
1109 | /* If the label is a label in the label pool, this is an error */ |
1110 | CodeLabel* L = E->JumpTo; |
1111 | CHECK (CollIndex (&S->Labels, L) < 0); |
1112 | |
1113 | /* Remove the reference to the label */ |
1114 | CS_RemoveLabelRef (S, E); |
1115 | } |
1116 | } |
1117 | |
1118 | /* Second pass: Delete the instructions. If a label attached to an |
1119 | ** instruction still has references, it must be references from outside |
1120 | ** the deleted area, which is an error. |
1121 | */ |
1122 | for (I = Last; I >= First; --I) { |
1123 | |
1124 | /* Get the next entry */ |
1125 | CodeEntry* E = CS_GetEntry (S, I); |
1126 | |
1127 | /* Check if this entry has a label attached */ |
1128 | CHECK (!CE_HasLabel (E)); |
1129 | |
1130 | /* Delete the pointer to the entry */ |
1131 | CollDelete (&S->Entries, I); |
1132 | |
1133 | /* Delete the entry itself */ |
1134 | FreeCodeEntry (E); |
1135 | } |
1136 | } |
1137 | |
1138 | |
1139 | |
1140 | void CS_DelCodeAfter (CodeSeg* S, unsigned Last) |
1141 | /* Delete all entries including the given one */ |
1142 | { |
1143 | /* Get the number of entries in this segment */ |
1144 | unsigned Count = CS_GetEntryCount (S); |
1145 | |
1146 | /* First pass: Delete all references to labels. If the reference count |
1147 | ** for a label drops to zero, delete it. |
1148 | */ |
1149 | unsigned C = Count; |
1150 | while (Last < C--) { |
1151 | |
1152 | /* Get the next entry */ |
1153 | CodeEntry* E = CS_GetEntry (S, C); |
1154 | |
1155 | /* Check if this entry has a label reference */ |
1156 | if (E->JumpTo) { |
1157 | /* If the label is a label in the label pool and this is the last |
1158 | ** reference to the label, remove the label from the pool. |
1159 | */ |
1160 | CodeLabel* L = E->JumpTo; |
1161 | int Index = CollIndex (&S->Labels, L); |
1162 | if (Index >= 0 && CollCount (&L->JumpFrom) == 1) { |
1163 | /* Delete it from the pool */ |
1164 | CollDelete (&S->Labels, Index); |
1165 | } |
1166 | |
1167 | /* Remove the reference to the label */ |
1168 | CS_RemoveLabelRef (S, E); |
1169 | } |
1170 | |
1171 | } |
1172 | |
1173 | /* Second pass: Delete the instructions. If a label attached to an |
1174 | ** instruction still has references, it must be references from outside |
1175 | ** the deleted area. Don't delete the label in this case, just make it |
1176 | ** ownerless and move it to the label pool. |
1177 | */ |
1178 | C = Count; |
1179 | while (Last < C--) { |
1180 | |
1181 | /* Get the next entry */ |
1182 | CodeEntry* E = CS_GetEntry (S, C); |
1183 | |
1184 | /* Check if this entry has a label attached */ |
1185 | if (CE_HasLabel (E)) { |
1186 | /* Move the labels to the pool and clear the owner pointer */ |
1187 | CS_MoveLabelsToPool (S, E); |
1188 | } |
1189 | |
1190 | /* Delete the pointer to the entry */ |
1191 | CollDelete (&S->Entries, C); |
1192 | |
1193 | /* Delete the entry itself */ |
1194 | FreeCodeEntry (E); |
1195 | } |
1196 | } |
1197 | |
1198 | |
1199 | |
1200 | void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last) |
1201 | /* Remove all user marks from the entries in the given range */ |
1202 | { |
1203 | while (First <= Last) { |
1204 | CE_ResetMark (CS_GetEntry (S, First++)); |
1205 | } |
1206 | } |
1207 | |
1208 | |
1209 | |
1210 | int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last) |
1211 | /* Check if the given code segment range is a basic block. That is, check if |
1212 | ** First is the only entrance and Last is the only exit. This means that no |
1213 | ** jump/branch inside the block may jump to an insn below First or after(!) |
1214 | ** Last, and that no insn may jump into this block from the outside. |
1215 | */ |
1216 | { |
1217 | unsigned I; |
1218 | |
1219 | /* Don't accept invalid ranges */ |
1220 | CHECK (First <= Last); |
1221 | |
1222 | /* First pass: Walk over the range and remove all marks from the entries */ |
1223 | CS_ResetMarks (S, First, Last); |
1224 | |
1225 | /* Second pass: Walk over the range checking all labels. Note: There may be |
1226 | ** label on the first insn which is ok. |
1227 | */ |
1228 | I = First + 1; |
1229 | while (I <= Last) { |
1230 | |
1231 | /* Get the next entry */ |
1232 | CodeEntry* E = CS_GetEntry (S, I); |
1233 | |
1234 | /* Check if this entry has one or more labels, if so, check which |
1235 | ** entries jump to this label. |
1236 | */ |
1237 | unsigned LabelCount = CE_GetLabelCount (E); |
1238 | unsigned LabelIndex; |
1239 | for (LabelIndex = 0; LabelIndex < LabelCount; ++LabelIndex) { |
1240 | |
1241 | /* Get this label */ |
1242 | CodeLabel* L = CE_GetLabel (E, LabelIndex); |
1243 | |
1244 | /* Walk over all entries that jump to this label. Check for each |
1245 | ** of the entries if it is out of the range. |
1246 | */ |
1247 | unsigned RefCount = CL_GetRefCount (L); |
1248 | unsigned RefIndex; |
1249 | for (RefIndex = 0; RefIndex < RefCount; ++RefIndex) { |
1250 | |
1251 | /* Get the code entry that jumps here */ |
1252 | CodeEntry* Ref = CL_GetRef (L, RefIndex); |
1253 | |
1254 | /* Walk over out complete range and check if we find the |
1255 | ** refering entry. This is cheaper than using CS_GetEntryIndex, |
1256 | ** because CS_GetEntryIndex will search the complete code |
1257 | ** segment and not just our range. |
1258 | */ |
1259 | unsigned J; |
1260 | for (J = First; J <= Last; ++J) { |
1261 | if (Ref == CS_GetEntry (S, J)) { |
1262 | break; |
1263 | } |
1264 | } |
1265 | if (J > Last) { |
1266 | /* We did not find the entry. This means that the jump to |
1267 | ** out code segment entry E came from outside the range, |
1268 | ** which in turn means that the given range is not a basic |
1269 | ** block. |
1270 | */ |
1271 | CS_ResetMarks (S, First, Last); |
1272 | return 0; |
1273 | } |
1274 | |
1275 | /* If we come here, we found the entry. Mark it, so we know |
1276 | ** that the branch to the label is in range. |
1277 | */ |
1278 | CE_SetMark (Ref); |
1279 | } |
1280 | } |
1281 | |
1282 | /* Next entry */ |
1283 | ++I; |
1284 | } |
1285 | |
1286 | /* Third pass: Walk again over the range and check all branches. If we |
1287 | ** find a branch that is not marked, its target is not inside the range |
1288 | ** (since we checked all the labels in the range before). |
1289 | */ |
1290 | I = First; |
1291 | while (I <= Last) { |
1292 | |
1293 | /* Get the next entry */ |
1294 | CodeEntry* E = CS_GetEntry (S, I); |
1295 | |
1296 | /* Check if this is a branch and if so, if it has a mark */ |
1297 | if (E->Info & (OF_UBRA | OF_CBRA)) { |
1298 | if (!CE_HasMark (E)) { |
1299 | /* No mark means not a basic block. Before bailing out, be sure |
1300 | ** to remove the marks from the remaining entries. |
1301 | */ |
1302 | CS_ResetMarks (S, I+1, Last); |
1303 | return 0; |
1304 | } |
1305 | |
1306 | /* Remove the mark */ |
1307 | CE_ResetMark (E); |
1308 | } |
1309 | |
1310 | /* Next entry */ |
1311 | ++I; |
1312 | } |
1313 | |
1314 | /* Done - this is a basic block */ |
1315 | return 1; |
1316 | } |
1317 | |
1318 | |
1319 | |
1320 | void CS_OutputPrologue (const CodeSeg* S) |
1321 | /* If the given code segment is a code segment for a function, output the |
1322 | ** assembler prologue into the file. That is: Output a comment header, switch |
1323 | ** to the correct segment and enter the local function scope. If the code |
1324 | ** segment is global, do nothing. |
1325 | */ |
1326 | { |
1327 | /* Get the function associated with the code segment */ |
1328 | SymEntry* Func = S->Func; |
1329 | |
1330 | /* If the code segment is associated with a function, print a function |
1331 | ** header and enter a local scope. Be sure to switch to the correct |
1332 | ** segment before outputing the function label. |
1333 | */ |
1334 | if (Func) { |
1335 | /* Get the function descriptor */ |
1336 | CS_PrintFunctionHeader (S); |
1337 | WriteOutput (".segment\t\"%s\"\n\n.proc\t_%s" , S->SegName, Func->Name); |
1338 | if (IsQualNear (Func->Type)) { |
1339 | WriteOutput (": near" ); |
1340 | } else if (IsQualFar (Func->Type)) { |
1341 | WriteOutput (": far" ); |
1342 | } |
1343 | WriteOutput ("\n\n" ); |
1344 | } |
1345 | |
1346 | } |
1347 | |
1348 | |
1349 | |
1350 | void CS_OutputEpilogue (const CodeSeg* S) |
1351 | /* If the given code segment is a code segment for a function, output the |
1352 | ** assembler epilogue into the file. That is: Close the local function scope. |
1353 | */ |
1354 | { |
1355 | if (S->Func) { |
1356 | WriteOutput ("\n.endproc\n\n" ); |
1357 | } |
1358 | } |
1359 | |
1360 | |
1361 | |
1362 | void CS_Output (CodeSeg* S) |
1363 | /* Output the code segment data to the output file */ |
1364 | { |
1365 | unsigned I; |
1366 | const LineInfo* LI; |
1367 | |
1368 | /* Get the number of entries in this segment */ |
1369 | unsigned Count = CS_GetEntryCount (S); |
1370 | |
1371 | /* If the code segment is empty, bail out here */ |
1372 | if (Count == 0) { |
1373 | return; |
1374 | } |
1375 | |
1376 | /* Generate register info */ |
1377 | CS_GenRegInfo (S); |
1378 | |
1379 | /* Output the segment directive */ |
1380 | WriteOutput (".segment\t\"%s\"\n\n" , S->SegName); |
1381 | |
1382 | /* Output all entries, prepended by the line information if it has changed */ |
1383 | LI = 0; |
1384 | for (I = 0; I < Count; ++I) { |
1385 | /* Get the next entry */ |
1386 | const CodeEntry* E = CollConstAt (&S->Entries, I); |
1387 | /* Check if the line info has changed. If so, output the source line |
1388 | ** if the option is enabled and output debug line info if the debug |
1389 | ** option is enabled. |
1390 | */ |
1391 | if (E->LI != LI) { |
1392 | /* Line info has changed, remember the new line info */ |
1393 | LI = E->LI; |
1394 | |
1395 | /* Add the source line as a comment. Beware: When line continuation |
1396 | ** was used, the line may contain newlines. |
1397 | */ |
1398 | if (AddSource) { |
1399 | const char* L = LI->Line; |
1400 | WriteOutput (";\n; " ); |
1401 | while (*L) { |
1402 | const char* N = strchr (L, '\n'); |
1403 | if (N) { |
1404 | /* We have a newline, just write the first part */ |
1405 | WriteOutput ("%.*s\n; " , (int) (N - L), L); |
1406 | L = N+1; |
1407 | } else { |
1408 | /* No Newline, write as is */ |
1409 | WriteOutput ("%s\n" , L); |
1410 | break; |
1411 | } |
1412 | } |
1413 | WriteOutput (";\n" ); |
1414 | } |
1415 | |
1416 | /* Add line debug info */ |
1417 | if (DebugInfo) { |
1418 | WriteOutput ("\t.dbg\tline, \"%s\", %u\n" , |
1419 | GetInputName (LI), GetInputLine (LI)); |
1420 | } |
1421 | } |
1422 | /* Output the code */ |
1423 | CE_Output (E); |
1424 | } |
1425 | |
1426 | /* If debug info is enabled, terminate the last line number information */ |
1427 | if (DebugInfo) { |
1428 | WriteOutput ("\t.dbg\tline\n" ); |
1429 | } |
1430 | |
1431 | /* Free register info */ |
1432 | CS_FreeRegInfo (S); |
1433 | } |
1434 | |
1435 | |
1436 | |
1437 | void CS_FreeRegInfo (CodeSeg* S) |
1438 | /* Free register infos for all instructions */ |
1439 | { |
1440 | unsigned I; |
1441 | for (I = 0; I < CS_GetEntryCount (S); ++I) { |
1442 | CE_FreeRegInfo (CS_GetEntry(S, I)); |
1443 | } |
1444 | } |
1445 | |
1446 | |
1447 | |
1448 | void CS_GenRegInfo (CodeSeg* S) |
1449 | /* Generate register infos for all instructions */ |
1450 | { |
1451 | unsigned I; |
1452 | RegContents Regs; /* Initial register contents */ |
1453 | RegContents* CurrentRegs; /* Current register contents */ |
1454 | int WasJump; /* True if last insn was a jump */ |
1455 | int Done; /* All runs done flag */ |
1456 | |
1457 | /* Be sure to delete all register infos */ |
1458 | CS_FreeRegInfo (S); |
1459 | |
1460 | /* We may need two runs to get back references right */ |
1461 | do { |
1462 | |
1463 | /* Assume we're done after this run */ |
1464 | Done = 1; |
1465 | |
1466 | /* On entry, the register contents are unknown */ |
1467 | RC_Invalidate (&Regs); |
1468 | CurrentRegs = &Regs; |
1469 | |
1470 | /* Walk over all insns and note just the changes from one insn to the |
1471 | ** next one. |
1472 | */ |
1473 | WasJump = 0; |
1474 | for (I = 0; I < CS_GetEntryCount (S); ++I) { |
1475 | |
1476 | CodeEntry* P; |
1477 | |
1478 | /* Get the next instruction */ |
1479 | CodeEntry* E = CollAtUnchecked (&S->Entries, I); |
1480 | |
1481 | /* If the instruction has a label, we need some special handling */ |
1482 | unsigned LabelCount = CE_GetLabelCount (E); |
1483 | if (LabelCount > 0) { |
1484 | |
1485 | /* Loop over all entry points that jump here. If these entry |
1486 | ** points already have register info, check if all values are |
1487 | ** known and identical. If all values are identical, and the |
1488 | ** preceeding instruction was not an unconditional branch, check |
1489 | ** if the register value on exit of the preceeding instruction |
1490 | ** is also identical. If all these values are identical, the |
1491 | ** value of a register is known, otherwise it is unknown. |
1492 | */ |
1493 | CodeLabel* Label = CE_GetLabel (E, 0); |
1494 | unsigned Entry; |
1495 | if (WasJump) { |
1496 | /* Preceeding insn was an unconditional branch */ |
1497 | CodeEntry* J = CL_GetRef(Label, 0); |
1498 | if (J->RI) { |
1499 | Regs = J->RI->Out2; |
1500 | } else { |
1501 | RC_Invalidate (&Regs); |
1502 | } |
1503 | Entry = 1; |
1504 | } else { |
1505 | Regs = *CurrentRegs; |
1506 | Entry = 0; |
1507 | } |
1508 | |
1509 | while (Entry < CL_GetRefCount (Label)) { |
1510 | /* Get this entry */ |
1511 | CodeEntry* J = CL_GetRef (Label, Entry); |
1512 | if (J->RI == 0) { |
1513 | /* No register info for this entry. This means that the |
1514 | ** instruction that jumps here is at higher addresses and |
1515 | ** the jump is a backward jump. We need a second run to |
1516 | ** get the register info right in this case. Until then, |
1517 | ** assume unknown register contents. |
1518 | */ |
1519 | Done = 0; |
1520 | RC_Invalidate (&Regs); |
1521 | break; |
1522 | } |
1523 | if (J->RI->Out2.RegA != Regs.RegA) { |
1524 | Regs.RegA = UNKNOWN_REGVAL; |
1525 | } |
1526 | if (J->RI->Out2.RegX != Regs.RegX) { |
1527 | Regs.RegX = UNKNOWN_REGVAL; |
1528 | } |
1529 | if (J->RI->Out2.RegY != Regs.RegY) { |
1530 | Regs.RegY = UNKNOWN_REGVAL; |
1531 | } |
1532 | if (J->RI->Out2.SRegLo != Regs.SRegLo) { |
1533 | Regs.SRegLo = UNKNOWN_REGVAL; |
1534 | } |
1535 | if (J->RI->Out2.SRegHi != Regs.SRegHi) { |
1536 | Regs.SRegHi = UNKNOWN_REGVAL; |
1537 | } |
1538 | if (J->RI->Out2.Tmp1 != Regs.Tmp1) { |
1539 | Regs.Tmp1 = UNKNOWN_REGVAL; |
1540 | } |
1541 | ++Entry; |
1542 | } |
1543 | |
1544 | /* Use this register info */ |
1545 | CurrentRegs = &Regs; |
1546 | |
1547 | } |
1548 | |
1549 | /* Generate register info for this instruction */ |
1550 | CE_GenRegInfo (E, CurrentRegs); |
1551 | |
1552 | /* Remember for the next insn if this insn was an uncondition branch */ |
1553 | WasJump = (E->Info & OF_UBRA) != 0; |
1554 | |
1555 | /* Output registers for this insn are input for the next */ |
1556 | CurrentRegs = &E->RI->Out; |
1557 | |
1558 | /* If this insn is a branch on zero flag, we may have more info on |
1559 | ** register contents for one of both flow directions, but only if |
1560 | ** there is a previous instruction. |
1561 | */ |
1562 | if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) { |
1563 | |
1564 | /* Get the branch condition */ |
1565 | bc_t BC = GetBranchCond (E->OPC); |
1566 | |
1567 | /* Check the previous instruction */ |
1568 | switch (P->OPC) { |
1569 | |
1570 | case OP65_ADC: |
1571 | case OP65_AND: |
1572 | case OP65_DEA: |
1573 | case OP65_EOR: |
1574 | case OP65_INA: |
1575 | case OP65_LDA: |
1576 | case OP65_ORA: |
1577 | case OP65_PLA: |
1578 | case OP65_SBC: |
1579 | /* A is zero in one execution flow direction */ |
1580 | if (BC == BC_EQ) { |
1581 | E->RI->Out2.RegA = 0; |
1582 | } else { |
1583 | E->RI->Out.RegA = 0; |
1584 | } |
1585 | break; |
1586 | |
1587 | case OP65_CMP: |
1588 | /* If this is an immidiate compare, the A register has |
1589 | ** the value of the compare later. |
1590 | */ |
1591 | if (CE_IsConstImm (P)) { |
1592 | if (BC == BC_EQ) { |
1593 | E->RI->Out2.RegA = (unsigned char)P->Num; |
1594 | } else { |
1595 | E->RI->Out.RegA = (unsigned char)P->Num; |
1596 | } |
1597 | } |
1598 | break; |
1599 | |
1600 | case OP65_CPX: |
1601 | /* If this is an immidiate compare, the X register has |
1602 | ** the value of the compare later. |
1603 | */ |
1604 | if (CE_IsConstImm (P)) { |
1605 | if (BC == BC_EQ) { |
1606 | E->RI->Out2.RegX = (unsigned char)P->Num; |
1607 | } else { |
1608 | E->RI->Out.RegX = (unsigned char)P->Num; |
1609 | } |
1610 | } |
1611 | break; |
1612 | |
1613 | case OP65_CPY: |
1614 | /* If this is an immidiate compare, the Y register has |
1615 | ** the value of the compare later. |
1616 | */ |
1617 | if (CE_IsConstImm (P)) { |
1618 | if (BC == BC_EQ) { |
1619 | E->RI->Out2.RegY = (unsigned char)P->Num; |
1620 | } else { |
1621 | E->RI->Out.RegY = (unsigned char)P->Num; |
1622 | } |
1623 | } |
1624 | break; |
1625 | |
1626 | case OP65_DEX: |
1627 | case OP65_INX: |
1628 | case OP65_LDX: |
1629 | case OP65_PLX: |
1630 | /* X is zero in one execution flow direction */ |
1631 | if (BC == BC_EQ) { |
1632 | E->RI->Out2.RegX = 0; |
1633 | } else { |
1634 | E->RI->Out.RegX = 0; |
1635 | } |
1636 | break; |
1637 | |
1638 | case OP65_DEY: |
1639 | case OP65_INY: |
1640 | case OP65_LDY: |
1641 | case OP65_PLY: |
1642 | /* X is zero in one execution flow direction */ |
1643 | if (BC == BC_EQ) { |
1644 | E->RI->Out2.RegY = 0; |
1645 | } else { |
1646 | E->RI->Out.RegY = 0; |
1647 | } |
1648 | break; |
1649 | |
1650 | case OP65_TAX: |
1651 | case OP65_TXA: |
1652 | /* If the branch is a beq, both A and X are zero at the |
1653 | ** branch target, otherwise they are zero at the next |
1654 | ** insn. |
1655 | */ |
1656 | if (BC == BC_EQ) { |
1657 | E->RI->Out2.RegA = E->RI->Out2.RegX = 0; |
1658 | } else { |
1659 | E->RI->Out.RegA = E->RI->Out.RegX = 0; |
1660 | } |
1661 | break; |
1662 | |
1663 | case OP65_TAY: |
1664 | case OP65_TYA: |
1665 | /* If the branch is a beq, both A and Y are zero at the |
1666 | ** branch target, otherwise they are zero at the next |
1667 | ** insn. |
1668 | */ |
1669 | if (BC == BC_EQ) { |
1670 | E->RI->Out2.RegA = E->RI->Out2.RegY = 0; |
1671 | } else { |
1672 | E->RI->Out.RegA = E->RI->Out.RegY = 0; |
1673 | } |
1674 | break; |
1675 | |
1676 | default: |
1677 | break; |
1678 | |
1679 | } |
1680 | } |
1681 | } |
1682 | } while (!Done); |
1683 | |
1684 | } |
1685 | |