]> git.sur5r.net Git - cc65/blob - src/ld65/condes.c
1e0406a648f8c2385f10baff32503f562052546a
[cc65] / src / ld65 / condes.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 condes.h                                  */
4 /*                                                                           */
5 /*                   Module constructor/destructor support                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2008 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 "fragdefs.h"
43 #include "segdefs.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 };
70
71 /* Array for all types */
72 static ConDesDesc ConDes[CD_TYPE_COUNT] = {
73     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
74     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
75     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
76     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
77     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
78     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
79     { STATIC_COLLECTION_INITIALIZER, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, cdIncreasing },
80 };
81
82
83
84 /*****************************************************************************/
85 /*           Internally used function to create the condes tables            */
86 /*****************************************************************************/
87
88
89
90 static int ConDesCompare (void* Data, const void* E1, const void* E2)
91 /* Compare function to sort the exports */
92 {
93     int Cmp;
94
95     /* Data is actually a pointer to a ConDesDesc from the table, E1 and
96      * E2 are exports from the collection. Get the condes type and cast
97      * the void pointers to object pointers.
98      */
99     ConDesDesc* CD = ((ConDesDesc*) Data);
100     int Type = CD - ConDes;
101     const Export* Exp1 = (const Export*) E1;
102     const Export* Exp2 = (const Export*) E2;
103
104     /* Get the priorities of the two exports */
105     unsigned Prio1 = Exp1->ConDes[Type];
106     unsigned Prio2 = Exp2->ConDes[Type];
107
108     /* Compare the priorities for this condes type */
109     if (Prio1 < Prio2) {
110         Cmp = -1;
111     } else if (Prio1 > Prio2) {
112         Cmp = 1;
113     } else {
114         /* Use the name in this case */
115         Cmp = SB_Compare (GetStrBuf (Exp1->Name), GetStrBuf (Exp2->Name));
116     }
117
118     /* Reverse the result for decreasing order */
119     if (CD->Order == cdIncreasing) {
120         return Cmp;
121     } else {
122         return -Cmp;
123     }
124 }
125
126
127
128 static void ConDesCreateOne (ConDesDesc* CD)
129 /* Create one table if requested */
130 {
131     Segment*    Seg;            /* Segment for table */
132     Section*    Sec;            /* Section for table */
133     unsigned    Count;          /* Number of exports */
134     unsigned    I;
135
136     /* Check if this table has a segment and table label defined. If not,
137      * creation was not requested in the config file - ignore it.
138      */
139     if (CD->SegName == INVALID_STRING_ID || CD->Label == INVALID_STRING_ID) {
140         return;
141     }
142
143     /* Check if there is an import for the table label. If not, there is no
144      * reference to the table and we would just waste memory creating the
145      * table.
146      */
147     if (!IsUnresolved (CD->Label)) {
148         return;
149     }
150
151     /* Sort the collection of exports according to priority */
152     CollSort (&CD->ExpList, ConDesCompare, CD);
153
154     /* Get the segment for the table, create it if needed */
155     Seg = GetSegment (CD->SegName, ADDR_SIZE_ABS, 0);
156
157     /* Create a new section for the table */
158     Sec = NewSection (Seg, 1, ADDR_SIZE_ABS);
159
160     /* Walk over the exports and create a fragment for each one. We will use
161      * the exported expression without copying it, since it's cheap and there
162      * is currently no place where it gets changed (hope this will not hunt
163      * me later...).
164      */
165     Count = CollCount (&CD->ExpList);
166     for (I = 0; I < Count; ++I) {
167
168         /* Get the export */
169         Export* E = CollAt (&CD->ExpList, I);
170
171         /* Create the fragment */
172         Fragment* F = NewFragment (FRAG_EXPR, 2, Sec);
173
174         /* Set the expression pointer */
175         F->Expr = E->Expr;
176     }
177
178     /* Define the table start as an export, offset into section is zero
179      * (the section only contains the table).
180      */
181     CreateSectionExport (CD->Label, Sec, 0);
182
183     /* If we have a CountSym name given AND if it is referenced, define it
184      * with the number of elements in the table.
185      */
186     if (CD->CountSym) {
187         CreateConstExport (CD->CountSym, Count);
188     }
189 }
190
191
192
193 /*****************************************************************************/
194 /*                                   Code                                    */
195 /*****************************************************************************/
196
197
198
199 void ConDesAddExport (struct Export* E)
200 /* Add the given export to the list of constructors/destructor */
201 {
202     unsigned Type;
203
204     /* Insert the export into all tables for which declarations exist */
205     for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
206         unsigned Prio = E->ConDes[Type];
207         if (Prio != CD_PRIO_NONE) {
208             CollAppend (&ConDes[Type].ExpList, E);
209         }
210     }
211 }
212
213
214
215 void ConDesSetSegName (unsigned Type, unsigned SegName)
216 /* Set the segment name where the table should go */
217 {
218     /* Check the parameters */
219     PRECONDITION (Type <= CD_TYPE_MAX && SegName != 0);
220
221     /* Setting the segment name twice is bad */
222     CHECK (ConDes[Type].SegName == INVALID_STRING_ID);
223
224     /* Set the name */
225     ConDes[Type].SegName = SegName;
226 }
227
228
229
230 void ConDesSetLabel (unsigned Type, unsigned Name)
231 /* Set the label for the given ConDes type */
232 {
233     /* Check the parameters */
234     PRECONDITION (Type <= CD_TYPE_MAX && Name != 0);
235
236     /* Setting the label twice is bad */
237     CHECK (ConDes[Type].Label == INVALID_STRING_ID);
238
239     /* Set the name */
240     ConDes[Type].Label = Name;
241 }
242
243
244
245 void ConDesSetCountSym (unsigned Type, unsigned Name)
246 /* Set the name for the given ConDes count symbol */
247 {
248     /* Check the parameters */
249     PRECONDITION (Type <= CD_TYPE_MAX && Name != 0);
250
251     /* Setting the symbol twice is bad */
252     CHECK (ConDes[Type].CountSym == INVALID_STRING_ID);
253
254     /* Set the name */
255     ConDes[Type].CountSym = Name;
256 }
257
258
259
260 void ConDesSetOrder (unsigned Type, ConDesOrder Order)
261 /* Set the sorting oder for the given ConDes table */
262 {
263     /* Check the parameters */
264     PRECONDITION (Type <= CD_TYPE_MAX);
265
266     /* Set the order */
267     ConDes[Type].Order = Order;
268 }
269
270
271
272 int ConDesHasSegName (unsigned Type)
273 /* Return true if a segment name is already defined for this ConDes type */
274 {
275     /* Check the parameters */
276     PRECONDITION (Type <= CD_TYPE_MAX);
277
278     return (ConDes[Type].SegName != INVALID_STRING_ID);
279 }
280
281
282
283 int ConDesHasLabel (unsigned Type)
284 /* Return true if a label is already defined for this ConDes type */
285 {
286     /* Check the parameters */
287     PRECONDITION (Type <= CD_TYPE_MAX);
288
289     return (ConDes[Type].Label != INVALID_STRING_ID);
290 }
291
292
293
294 void ConDesCreate (void)
295 /* Create the condes tables if requested */
296 {
297     unsigned Type;
298
299     /* Walk over the descriptor array and create a table for each entry */
300     for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
301         ConDesCreateOne (ConDes + Type);
302     }
303 }
304
305
306
307 void ConDesDump (void)
308 /* Dump ConDes data to stdout for debugging */
309 {
310     unsigned Type;
311     for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
312         Collection* ExpList = &ConDes[Type].ExpList;
313         printf ("CONDES(%u): %u symbols\n", Type, CollCount (ExpList));
314     }
315 }
316
317
318