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. */ |
65 | Segments* CS = 0; |
66 | |
67 | /* Pointer to the global segment list */ |
68 | Segments* GS = 0; |
69 | |
70 | /* Actual names for the segments */ |
71 | static 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 | */ |
78 | static Collection SegmentStack = STATIC_COLLECTION_INITIALIZER; |
79 | |
80 | |
81 | |
82 | /*****************************************************************************/ |
83 | /* Code */ |
84 | /*****************************************************************************/ |
85 | |
86 | |
87 | |
88 | void 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 | |
99 | void 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 | |
107 | void 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 | |
119 | void 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 | |
131 | const char* GetSegName (segment_t Seg) |
132 | /* Get the name of the given segment */ |
133 | { |
134 | return SS_Get (&SegmentNames[Seg]); |
135 | } |
136 | |
137 | |
138 | |
139 | static 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 | |
159 | Segments* 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 | |
174 | void 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 | |
186 | void CreateGlobalSegments (void) |
187 | /* Create the global segments and remember them in GS */ |
188 | { |
189 | GS = PushSegments (0); |
190 | } |
191 | |
192 | |
193 | |
194 | void 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 | |
206 | struct 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 | |
222 | void 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 | |
234 | void 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 | |
246 | void 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 | |
255 | void 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 | |
267 | int 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 | |
275 | void 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 | |
283 | void 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 | |