1 /*
2     $Id: section.c 2596 2021-04-18 18:52:11Z soci $
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18 */
19 #include "section.h"
20 #include "unicode.h"
21 #include "error.h"
22 #include "64tass.h"
23 #include "values.h"
24 #include "intobj.h"
25 #include "longjump.h"
26 #include "optimizer.h"
27 #include "eval.h"
28 #include "mem.h"
29 
30 #include "memblocksobj.h"
31 
32 struct section_s root_section;
33 struct section_s *current_section = &root_section;
34 struct section_address_s *current_address = &root_section.address;
35 static struct section_s *prev_section = &root_section;
36 
section_compare(const struct avltree_node * aa,const struct avltree_node * bb)37 static FAST_CALL int section_compare(const struct avltree_node *aa, const struct avltree_node *bb)
38 {
39     const struct section_s *a = cavltree_container_of(aa, struct section_s, node);
40     const struct section_s *b = cavltree_container_of(bb, struct section_s, node);
41     int h = a->name_hash - b->name_hash;
42     if (h != 0) return h;
43     return str_cmp(&a->cfname, &b->cfname);
44 }
45 
section_free(struct avltree_node * aa)46 static void section_free(struct avltree_node *aa)
47 {
48     struct section_s *a = avltree_container_of(aa, struct section_s, node);
49     free((uint8_t *)a->name.data);
50     if (a->name.data != a->cfname.data) free((uint8_t *)a->cfname.data);
51     avltree_destroy(&a->members, section_free);
52     longjump_destroy(&a->longjump);
53     val_destroy(Obj(a->address.mem));
54     val_destroy(a->address.l_address_val);
55     cpu_opt_destroy(a->optimizer);
56     free(a);
57 }
58 
find_section(const str_t * name,struct section_s * context)59 static struct section_s *find_section(const str_t *name, struct section_s *context) {
60     struct avltree_node *b;
61     struct section_s tmp, *tmp2 = NULL;
62 
63     if (name->len > 1 && name->data[1] == 0) tmp.cfname = *name;
64     else str_cfcpy(&tmp.cfname, name);
65     tmp.name_hash = str_hash(&tmp.cfname);
66 
67     while (context != NULL) {
68         b = avltree_lookup(&tmp.node, &context->members, section_compare);
69         if (b != NULL) {
70             tmp2 = avltree_container_of(b, struct section_s, node);
71             if (tmp2->defpass >= pass - 1) {
72                 return tmp2;
73             }
74         }
75         context = context->parent;
76     }
77     return tmp2;
78 }
79 
find_new_section(const str_t * name)80 struct section_s *find_new_section(const str_t *name) {
81     struct section_s *tmp2 = find_section(name, current_section);
82     return (tmp2 != NULL) ? tmp2 : new_section(name);
83 }
84 
85 static struct section_s *lastsc = NULL;
new_section(const str_t * name)86 struct section_s *new_section(const str_t *name) {
87     struct avltree_node *b;
88     struct section_s *tmp;
89 
90     if (lastsc == NULL) {
91         lastsc = (struct section_s *)mallocx(sizeof *lastsc);
92     }
93     str_cfcpy(&lastsc->cfname, name);
94     lastsc->name_hash = str_hash(&lastsc->cfname);
95     b = avltree_insert(&lastsc->node, &current_section->members, section_compare);
96     if (b == NULL) { /* new section */
97         str_cpy(&lastsc->name, name);
98         if (lastsc->cfname.data == name->data) lastsc->cfname = lastsc->name;
99         else str_cfcpy(&lastsc->cfname, NULL);
100         lastsc->parent = current_section;
101         lastsc->provides = ~(uval_t)0;lastsc->requires = lastsc->conflicts = 0;
102         lastsc->address.end = lastsc->address.address = lastsc->address.l_address = lastsc->address.l_start = lastsc->address.l_union = lastsc->size = 0;
103         lastsc->address.l_address_val = val_reference(int_value[0]);
104         lastsc->defpass = 0;
105         lastsc->usepass = 0;
106         lastsc->address.unionmode = false;
107         lastsc->logicalrecursion = 0;
108         lastsc->address.moved = false;
109         lastsc->address.wrapwarn = false;
110         lastsc->address.bankwarn = false;
111         lastsc->next = NULL;
112         lastsc->optimizer = NULL;
113         prev_section->next = lastsc;
114         prev_section = lastsc;
115         lastsc->address.mem = new_memblocks(0, 0);
116         avltree_init(&lastsc->members);
117         avltree_init(&lastsc->longjump);
118         tmp = lastsc;
119         lastsc = NULL;
120         return tmp;
121     }
122     return avltree_container_of(b, struct section_s, node);            /* already exists */
123 }
124 
find_this_section(const char * here)125 struct section_s *find_this_section(const char *here) {
126     struct section_s *space;
127     str_t labelname;
128 
129     space = &root_section;
130     if (here == NULL) return space;
131 
132     pline = (const uint8_t *)here;
133     lpoint.pos = 0;
134     do {
135         labelname.data = pline + lpoint.pos; labelname.len = get_label(labelname.data);
136         if (labelname.len == 0) return NULL;
137         lpoint.pos += (linecpos_t)labelname.len;
138         space = find_section(&labelname, space);
139         if (space == NULL) return NULL;
140         lpoint.pos++;
141     } while (labelname.data[labelname.len] == '.');
142 
143     return labelname.data[labelname.len] != 0 ? NULL : space;
144 }
145 
reset_section(struct section_s * section)146 void reset_section(struct section_s *section) {
147     section->provides = ~(uval_t)0; section->requires = section->conflicts = 0;
148     section->address.end = section->address.start = section->restart = section->l_restart = section->address.address = section->address.l_address = section->address.l_start = section->address.l_union = 0;
149     val_destroy(section->address.l_address_val);
150     section->address.l_address_val = val_reference(int_value[0]);
151     section->logicalrecursion = 0;
152     section->address.moved = false;
153     section->address.wrapwarn = false;
154     section->address.bankwarn = false;
155     section->address.unionmode = false;
156 }
157 
init_section(void)158 void init_section(void) {
159     root_section.parent = NULL;
160     root_section.name.data = NULL;
161     root_section.name.len = 0;
162     root_section.cfname.data = NULL;
163     root_section.cfname.len = 0;
164     root_section.next = NULL;
165     root_section.optimizer = NULL;
166     root_section.address.mem = new_memblocks(0, 0);
167     root_section.address.l_address_val = val_reference(int_value[0]);
168     avltree_init(&root_section.members);
169     avltree_init(&root_section.longjump);
170     prev_section = &root_section;
171 }
172 
destroy_section(void)173 void destroy_section(void) {
174     free(lastsc);
175     avltree_destroy(&root_section.members, section_free);
176     longjump_destroy(&root_section.longjump);
177     val_destroy(Obj(root_section.address.mem));
178     val_destroy(root_section.address.l_address_val);
179     root_section.address.l_address_val = NULL;
180     cpu_opt_destroy(root_section.optimizer);
181     root_section.optimizer = NULL;
182 }
183 
sectionprint2(const struct section_s * l,FILE * f)184 static void sectionprint2(const struct section_s *l, FILE *f) {
185     if (l->name.data != NULL) {
186         sectionprint2(l->parent, f);
187         printable_print2(l->name.data, f, l->name.len);
188         putc('.', f);
189     }
190 }
191 
printrange(const struct section_s * l,FILE * f)192 static void printrange(const struct section_s *l, FILE *f) {
193     char temp[10], temp2[10], temp3[10];
194     sprintf(temp, "$%04" PRIaddress, l->address.start);
195     temp2[0] = 0;
196     if (l->size != 0) {
197         sprintf(temp2, "-$%04" PRIaddress, l->address.start + l->size - 1U);
198     }
199     sprintf(temp3, "$%04" PRIaddress, l->size);
200     fprintf(f, "Section: %15s%-8s %-7s", temp, temp2, temp3);
201 }
202 
sectionprint(FILE * f)203 void sectionprint(FILE *f) {
204     struct section_s *l = &root_section;
205 
206     if (l->size != 0) {
207         printrange(l, f);
208         putc('\n', f);
209     }
210     memprint(l->address.mem, f);
211     l = root_section.next;
212     while (l != NULL) {
213         if (l->defpass == pass) {
214             printrange(l, f);
215             putc(' ', f);
216             sectionprint2(l->parent, f);
217             printable_print2(l->name.data, f, l->name.len);
218             putc('\n', f);
219             memprint(l->address.mem, f);
220         }
221         l = l->next;
222     }
223 }
224 
section_sizecheck(void)225 void section_sizecheck(void) {
226     struct section_s *l = root_section.next;
227     while (l != NULL) {
228         if (l->defpass == pass) {
229             if (l->size != ((!l->address.moved && l->address.end < l->address.address) ? l->address.address : l->address.end) - l->address.start) {
230                 if (pass > max_pass) err_msg_cant_calculate2(&l->name, l->file_list, &l->epoint);
231                 fixeddig = false;
232                 return;
233             }
234         }
235         l = l->next;
236     }
237 }
238