1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* condes.c */ |
4 | /* */ |
5 | /* Module constructor/destructor support */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2000-2012, 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 | |
38 | /* common */ |
39 | #include "addrsize.h" |
40 | #include "check.h" |
41 | #include "coll.h" |
42 | #include "filepos.h" |
43 | #include "fragdefs.h" |
44 | #include "xmalloc.h" |
45 | |
46 | /* ld65 */ |
47 | #include "condes.h" |
48 | #include "exports.h" |
49 | #include "fragment.h" |
50 | #include "segments.h" |
51 | #include "spool.h" |
52 | |
53 | |
54 | |
55 | /*****************************************************************************/ |
56 | /* Data */ |
57 | /*****************************************************************************/ |
58 | |
59 | |
60 | |
61 | /* Struct describing one condes type */ |
62 | typedef struct ConDesDesc ConDesDesc; |
63 | struct ConDesDesc { |
64 | Collection ExpList; /* List of exported symbols */ |
65 | unsigned SegName; /* Name of segment the table is in */ |
66 | unsigned Label; /* Name of table label */ |
67 | unsigned CountSym; /* Name of symbol for entry count */ |
68 | unsigned char Order; /* Table order (increasing/decreasing) */ |
69 | ConDesImport Import; /* Forced import if any */ |
70 | }; |
71 | |
72 | /* Array for all types */ |
73 | static ConDesDesc ConDes[CD_TYPE_COUNT] = { |
74 | { |
75 | STATIC_COLLECTION_INITIALIZER, |
76 | INVALID_STRING_ID, |
77 | INVALID_STRING_ID, |
78 | INVALID_STRING_ID, |
79 | cdIncreasing, |
80 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
81 | },{ |
82 | STATIC_COLLECTION_INITIALIZER, |
83 | INVALID_STRING_ID, |
84 | INVALID_STRING_ID, |
85 | INVALID_STRING_ID, |
86 | cdIncreasing, |
87 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
88 | },{ |
89 | STATIC_COLLECTION_INITIALIZER, |
90 | INVALID_STRING_ID, |
91 | INVALID_STRING_ID, |
92 | INVALID_STRING_ID, |
93 | cdIncreasing, |
94 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
95 | },{ |
96 | STATIC_COLLECTION_INITIALIZER, |
97 | INVALID_STRING_ID, |
98 | INVALID_STRING_ID, |
99 | INVALID_STRING_ID, |
100 | cdIncreasing, |
101 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
102 | },{ |
103 | STATIC_COLLECTION_INITIALIZER, |
104 | INVALID_STRING_ID, |
105 | INVALID_STRING_ID, |
106 | INVALID_STRING_ID, |
107 | cdIncreasing, |
108 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
109 | },{ |
110 | STATIC_COLLECTION_INITIALIZER, |
111 | INVALID_STRING_ID, |
112 | INVALID_STRING_ID, |
113 | INVALID_STRING_ID, |
114 | cdIncreasing, |
115 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
116 | },{ |
117 | STATIC_COLLECTION_INITIALIZER, |
118 | INVALID_STRING_ID, |
119 | INVALID_STRING_ID, |
120 | INVALID_STRING_ID, |
121 | cdIncreasing, |
122 | { INVALID_STRING_ID, STATIC_FILEPOS_INITIALIZER, ADDR_SIZE_DEFAULT }, |
123 | }, |
124 | }; |
125 | |
126 | |
127 | |
128 | /*****************************************************************************/ |
129 | /* Internally used function to create the condes tables */ |
130 | /*****************************************************************************/ |
131 | |
132 | |
133 | |
134 | static int ConDesCompare (void* Data, const void* E1, const void* E2) |
135 | /* Compare function to sort the exports */ |
136 | { |
137 | int Cmp; |
138 | |
139 | /* Data is actually a pointer to a ConDesDesc from the table, E1 and |
140 | ** E2 are exports from the collection. Get the condes type and cast |
141 | ** the void pointers to object pointers. |
142 | */ |
143 | ConDesDesc* CD = ((ConDesDesc*) Data); |
144 | int Type = CD - ConDes; |
145 | const Export* Exp1 = (const Export*) E1; |
146 | const Export* Exp2 = (const Export*) E2; |
147 | |
148 | /* Get the priorities of the two exports */ |
149 | unsigned Prio1 = Exp1->ConDes[Type]; |
150 | unsigned Prio2 = Exp2->ConDes[Type]; |
151 | |
152 | /* Compare the priorities for this condes type */ |
153 | if (Prio1 < Prio2) { |
154 | Cmp = -1; |
155 | } else if (Prio1 > Prio2) { |
156 | Cmp = 1; |
157 | } else { |
158 | /* Use the name in this case */ |
159 | Cmp = SB_Compare (GetStrBuf (Exp1->Name), GetStrBuf (Exp2->Name)); |
160 | } |
161 | |
162 | /* Reverse the result for decreasing order */ |
163 | if (CD->Order == cdIncreasing) { |
164 | return Cmp; |
165 | } else { |
166 | return -Cmp; |
167 | } |
168 | } |
169 | |
170 | |
171 | |
172 | static void ConDesCreateOne (ConDesDesc* CD) |
173 | /* Create one table if requested */ |
174 | { |
175 | Segment* Seg; /* Segment for table */ |
176 | Section* Sec; /* Section for table */ |
177 | unsigned Count; /* Number of exports */ |
178 | unsigned I; |
179 | |
180 | /* Check if this table has a segment and table label defined. If not, |
181 | ** creation was not requested in the config file - ignore it. |
182 | */ |
183 | if (CD->SegName == INVALID_STRING_ID || CD->Label == INVALID_STRING_ID) { |
184 | return; |
185 | } |
186 | |
187 | /* Check if there is an import for the table label. If not, there is no |
188 | ** reference to the table and we would just waste memory creating the |
189 | ** table. |
190 | */ |
191 | if (!IsUnresolved (CD->Label)) { |
192 | return; |
193 | } |
194 | |
195 | /* Sort the collection of exports according to priority */ |
196 | CollSort (&CD->ExpList, ConDesCompare, CD); |
197 | |
198 | /* Get the segment for the table, create it if needed */ |
199 | Seg = GetSegment (CD->SegName, ADDR_SIZE_ABS, 0); |
200 | |
201 | /* Create a new section for the table */ |
202 | Sec = NewSection (Seg, 1, ADDR_SIZE_ABS); |
203 | |
204 | /* Walk over the exports and create a fragment for each one. We will use |
205 | ** the exported expression without copying it, since it's cheap and there |
206 | ** is currently no place where it gets changed (hope this will not hunt |
207 | ** me later...). |
208 | */ |
209 | Count = CollCount (&CD->ExpList); |
210 | for (I = 0; I < Count; ++I) { |
211 | |
212 | /* Get the export */ |
213 | Export* E = CollAt (&CD->ExpList, I); |
214 | |
215 | /* Create the fragment */ |
216 | Fragment* F = NewFragment (FRAG_EXPR, 2, Sec); |
217 | |
218 | /* Set the expression pointer */ |
219 | F->Expr = E->Expr; |
220 | } |
221 | |
222 | /* Define the table start as an export, offset into section is zero |
223 | ** (the section only contains the table). |
224 | */ |
225 | CreateSectionExport (CD->Label, Sec, 0); |
226 | |
227 | /* If we have a CountSym name given AND if it is referenced, define it |
228 | ** with the number of elements in the table. |
229 | */ |
230 | if (CD->CountSym) { |
231 | CreateConstExport (CD->CountSym, Count); |
232 | } |
233 | } |
234 | |
235 | |
236 | |
237 | /*****************************************************************************/ |
238 | /* Code */ |
239 | /*****************************************************************************/ |
240 | |
241 | |
242 | |
243 | void ConDesAddExport (struct Export* E) |
244 | /* Add the given export to the list of constructors/destructor */ |
245 | { |
246 | unsigned Type; |
247 | |
248 | /* Insert the export into all tables for which declarations exist */ |
249 | for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { |
250 | unsigned Prio = E->ConDes[Type]; |
251 | if (Prio != CD_PRIO_NONE) { |
252 | CollAppend (&ConDes[Type].ExpList, E); |
253 | } |
254 | } |
255 | } |
256 | |
257 | |
258 | |
259 | void ConDesSetSegName (unsigned Type, unsigned SegName) |
260 | /* Set the segment name where the table should go */ |
261 | { |
262 | /* Check the parameters */ |
263 | PRECONDITION (Type <= CD_TYPE_MAX && SegName != 0); |
264 | |
265 | /* Setting the segment name twice is bad */ |
266 | CHECK (ConDes[Type].SegName == INVALID_STRING_ID); |
267 | |
268 | /* Set the name */ |
269 | ConDes[Type].SegName = SegName; |
270 | } |
271 | |
272 | |
273 | |
274 | const ConDesImport* ConDesGetImport (unsigned Type) |
275 | /* Get the forced import for the given ConDes type. Returns NULL if there is |
276 | ** no forced import for this type. |
277 | */ |
278 | { |
279 | const ConDesImport* Import; |
280 | |
281 | /* Check the parameters */ |
282 | PRECONDITION (Type <= CD_TYPE_MAX); |
283 | |
284 | /* Return the import */ |
285 | Import = &ConDes[Type].Import; |
286 | return (Import->Name != INVALID_STRING_ID)? Import : 0; |
287 | } |
288 | |
289 | |
290 | |
291 | void ConDesSetImport (unsigned Type, const ConDesImport* Import) |
292 | /* Set the forced import for the given ConDes type */ |
293 | { |
294 | /* Check the parameters */ |
295 | PRECONDITION (Type <= CD_TYPE_MAX && Import != 0); |
296 | |
297 | /* Setting the import twice is bad */ |
298 | CHECK (ConDes[Type].Import.Name == INVALID_STRING_ID); |
299 | |
300 | /* Set the import and its position */ |
301 | ConDes[Type].Import = *Import; |
302 | } |
303 | |
304 | |
305 | |
306 | void ConDesSetLabel (unsigned Type, unsigned Name) |
307 | /* Set the label for the given ConDes type */ |
308 | { |
309 | /* Check the parameters */ |
310 | PRECONDITION (Type <= CD_TYPE_MAX && Name != 0); |
311 | |
312 | /* Setting the label twice is bad */ |
313 | CHECK (ConDes[Type].Label == INVALID_STRING_ID); |
314 | |
315 | /* Set the name */ |
316 | ConDes[Type].Label = Name; |
317 | } |
318 | |
319 | |
320 | |
321 | void ConDesSetCountSym (unsigned Type, unsigned Name) |
322 | /* Set the name for the given ConDes count symbol */ |
323 | { |
324 | /* Check the parameters */ |
325 | PRECONDITION (Type <= CD_TYPE_MAX && Name != 0); |
326 | |
327 | /* Setting the symbol twice is bad */ |
328 | CHECK (ConDes[Type].CountSym == INVALID_STRING_ID); |
329 | |
330 | /* Set the name */ |
331 | ConDes[Type].CountSym = Name; |
332 | } |
333 | |
334 | |
335 | |
336 | void ConDesSetOrder (unsigned Type, ConDesOrder Order) |
337 | /* Set the sorting oder for the given ConDes table */ |
338 | { |
339 | /* Check the parameters */ |
340 | PRECONDITION (Type <= CD_TYPE_MAX); |
341 | |
342 | /* Set the order */ |
343 | ConDes[Type].Order = Order; |
344 | } |
345 | |
346 | |
347 | |
348 | int ConDesHasSegName (unsigned Type) |
349 | /* Return true if a segment name is already defined for this ConDes type */ |
350 | { |
351 | /* Check the parameters */ |
352 | PRECONDITION (Type <= CD_TYPE_MAX); |
353 | |
354 | return (ConDes[Type].SegName != INVALID_STRING_ID); |
355 | } |
356 | |
357 | |
358 | |
359 | int ConDesHasLabel (unsigned Type) |
360 | /* Return true if a label is already defined for this ConDes type */ |
361 | { |
362 | /* Check the parameters */ |
363 | PRECONDITION (Type <= CD_TYPE_MAX); |
364 | |
365 | return (ConDes[Type].Label != INVALID_STRING_ID); |
366 | } |
367 | |
368 | |
369 | |
370 | void ConDesCreate (void) |
371 | /* Create the condes tables if requested */ |
372 | { |
373 | unsigned Type; |
374 | |
375 | /* Walk over the descriptor array and create a table for each entry */ |
376 | for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { |
377 | ConDesCreateOne (ConDes + Type); |
378 | } |
379 | } |
380 | |
381 | |
382 | |
383 | void ConDesDump (void) |
384 | /* Dump ConDes data to stdout for debugging */ |
385 | { |
386 | unsigned Type; |
387 | for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { |
388 | Collection* ExpList = &ConDes[Type].ExpList; |
389 | printf ("CONDES(%u): %u symbols\n" , Type, CollCount (ExpList)); |
390 | } |
391 | } |
392 | |