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, ¤t_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