1/*****************************************************************************/
2/* */
3/* segments.c */
4/* */
5/* Lightweight segment management stuff */
6/* */
7/* */
8/* */
9/* (C) 2001-2009, 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 <stdarg.h>
37#include <string.h>
38
39/* common */
40#include "chartype.h"
41#include "check.h"
42#include "coll.h"
43#include "scanner.h"
44#include "segnames.h"
45#include "strstack.h"
46#include "xmalloc.h"
47
48/* cc65 */
49#include "codeent.h"
50#include "codeseg.h"
51#include "dataseg.h"
52#include "error.h"
53#include "textseg.h"
54#include "segments.h"
55
56
57
58/*****************************************************************************/
59/* Data */
60/*****************************************************************************/
61
62
63
64/* Pointer to the current segment list. Output goes here. */
65Segments* CS = 0;
66
67/* Pointer to the global segment list */
68Segments* GS = 0;
69
70/* Actual names for the segments */
71static StrStack SegmentNames[SEG_COUNT];
72
73/* We're using a collection for the stack instead of a linked list. Since
74** functions may not be nested (at least in the current implementation), the
75** maximum stack depth is 2, so there is not really a need for a better
76** implementation.
77*/
78static Collection SegmentStack = STATIC_COLLECTION_INITIALIZER;
79
80
81
82/*****************************************************************************/
83/* Code */
84/*****************************************************************************/
85
86
87
88void InitSegNames (void)
89/* Initialize the segment names */
90{
91 SS_Push (&SegmentNames[SEG_BSS], SEGNAME_BSS);
92 SS_Push (&SegmentNames[SEG_CODE], SEGNAME_CODE);
93 SS_Push (&SegmentNames[SEG_DATA], SEGNAME_DATA);
94 SS_Push (&SegmentNames[SEG_RODATA], SEGNAME_RODATA);
95}
96
97
98
99void SetSegName (segment_t Seg, const char* Name)
100/* Set a new name for a segment */
101{
102 SS_Set (&SegmentNames[Seg], Name);
103}
104
105
106
107void PushSegName (segment_t Seg, const char* Name)
108/* Push the current segment name and set a new name for a segment */
109{
110 if (SS_IsFull (&SegmentNames[Seg])) {
111 Error ("Segment name stack overflow");
112 } else {
113 SS_Push (&SegmentNames[Seg], Name);
114 }
115}
116
117
118
119void PopSegName (segment_t Seg)
120/* Restore a segment name from the segment name stack */
121{
122 if (SS_GetCount (&SegmentNames[Seg]) < 2) {
123 Error ("Segment name stack is empty");
124 } else {
125 SS_Drop (&SegmentNames[Seg]);
126 }
127}
128
129
130
131const char* GetSegName (segment_t Seg)
132/* Get the name of the given segment */
133{
134 return SS_Get (&SegmentNames[Seg]);
135}
136
137
138
139static Segments* NewSegments (SymEntry* Func)
140/* Initialize a Segments structure (set all fields to NULL) */
141{
142 /* Allocate memory */
143 Segments* S = xmalloc (sizeof (Segments));
144
145 /* Initialize the fields */
146 S->Text = NewTextSeg (Func);
147 S->Code = NewCodeSeg (GetSegName (SEG_CODE), Func);
148 S->Data = NewDataSeg (GetSegName (SEG_DATA), Func);
149 S->ROData = NewDataSeg (GetSegName (SEG_RODATA), Func);
150 S->BSS = NewDataSeg (GetSegName (SEG_BSS), Func);
151 S->CurDSeg = SEG_DATA;
152
153 /* Return the new struct */
154 return S;
155}
156
157
158
159Segments* PushSegments (SymEntry* Func)
160/* Make the new segment list current but remember the old one */
161{
162 /* Push the current pointer onto the stack */
163 CollAppend (&SegmentStack, CS);
164
165 /* Create a new Segments structure */
166 CS = NewSegments (Func);
167
168 /* Return the new struct */
169 return CS;
170}
171
172
173
174void PopSegments (void)
175/* Pop the old segment list (make it current) */
176{
177 /* Must have something on the stack */
178 PRECONDITION (CollCount (&SegmentStack) > 0);
179
180 /* Pop the last segment and set it as current */
181 CS = CollPop (&SegmentStack);
182}
183
184
185
186void CreateGlobalSegments (void)
187/* Create the global segments and remember them in GS */
188{
189 GS = PushSegments (0);
190}
191
192
193
194void UseDataSeg (segment_t DSeg)
195/* For the current segment list, use the data segment DSeg */
196{
197 /* Check the input */
198 PRECONDITION (CS && DSeg != SEG_CODE);
199
200 /* Set the new segment to use */
201 CS->CurDSeg = DSeg;
202}
203
204
205
206struct DataSeg* GetDataSeg (void)
207/* Return the current data segment */
208{
209 PRECONDITION (CS != 0);
210 switch (CS->CurDSeg) {
211 case SEG_BSS: return CS->BSS;
212 case SEG_DATA: return CS->Data;
213 case SEG_RODATA: return CS->ROData;
214 default:
215 FAIL ("Invalid data segment");
216 return 0;
217 }
218}
219
220
221
222void AddTextLine (const char* Format, ...)
223/* Add a line of code to the current text segment */
224{
225 va_list ap;
226 va_start (ap, Format);
227 CHECK (CS != 0);
228 TS_AddVLine (CS->Text, Format, ap);
229 va_end (ap);
230}
231
232
233
234void AddCodeLine (const char* Format, ...)
235/* Add a line of code to the current code segment */
236{
237 va_list ap;
238 va_start (ap, Format);
239 CHECK (CS != 0);
240 CS_AddVLine (CS->Code, CurTok.LI, Format, ap);
241 va_end (ap);
242}
243
244
245
246void AddCode (opc_t OPC, am_t AM, const char* Arg, struct CodeLabel* JumpTo)
247/* Add a code entry to the current code segment */
248{
249 CHECK (CS != 0);
250 CS_AddEntry (CS->Code, NewCodeEntry (OPC, AM, Arg, JumpTo, CurTok.LI));
251}
252
253
254
255void AddDataLine (const char* Format, ...)
256/* Add a line of data to the current data segment */
257{
258 va_list ap;
259 va_start (ap, Format);
260 CHECK (CS != 0);
261 DS_AddVLine (GetDataSeg(), Format, ap);
262 va_end (ap);
263}
264
265
266
267int HaveGlobalCode (void)
268/* Return true if the global code segment contains entries (which is an error) */
269{
270 return (CS_GetEntryCount (GS->Code) > 0);
271}
272
273
274
275void RemoveGlobalCode (void)
276/* Remove all code from the global code segment. Used for error recovery. */
277{
278 CS_DelEntries (GS->Code, 0, CS_GetEntryCount (GS->Code));
279}
280
281
282
283void OutputSegments (const Segments* S)
284/* Output the given segments to the output file */
285{
286 /* Output the function prologue if the segments came from a function */
287 CS_OutputPrologue (S->Code);
288
289 /* Output the text segment */
290 TS_Output (S->Text);
291
292 /* Output the three data segments */
293 DS_Output (S->Data);
294 DS_Output (S->ROData);
295 DS_Output (S->BSS);
296
297 /* Output the code segment */
298 CS_Output (S->Code);
299
300 /* Output the code segment epiloque */
301 CS_OutputEpilogue (S->Code);
302}
303