Mercurial > hg > index.cgi
comparison lwlink/link.c @ 0:2c24602be78f
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author | lost@l-w.ca |
---|---|
date | Wed, 19 Jan 2011 22:27:17 -0700 |
parents | |
children | 7317fbe024af |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2c24602be78f |
---|---|
1 /* | |
2 link.c | |
3 Copyright © 2009 William Astle | |
4 | |
5 This file is part of LWLINK. | |
6 | |
7 LWLINK is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
21 Resolve section and symbol addresses; handle incomplete references | |
22 */ | |
23 | |
24 #include <stdio.h> | |
25 #include <stdlib.h> | |
26 | |
27 #include "expr.h" | |
28 #include "lwlink.h" | |
29 #include "util.h" | |
30 | |
31 struct section_list *sectlist = NULL; | |
32 int nsects = 0; | |
33 static int nforced = 0; | |
34 | |
35 void check_section_name(char *name, int *base, fileinfo_t *fn) | |
36 { | |
37 int sn; | |
38 | |
39 if (fn -> forced == 0) | |
40 return; | |
41 | |
42 for (sn = 0; sn < fn -> nsections; sn++) | |
43 { | |
44 if (!strcmp(name, fn -> sections[sn].name)) | |
45 { | |
46 // we have a match | |
47 sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); | |
48 sectlist[nsects].ptr = &(fn -> sections[sn]); | |
49 | |
50 fn -> sections[sn].processed = 1; | |
51 fn -> sections[sn].loadaddress = *base; | |
52 *base += fn -> sections[sn].codesize; | |
53 nsects++; | |
54 } | |
55 } | |
56 for (sn = 0; sn < fn -> nsubs; sn++) | |
57 { | |
58 check_section_name(name, base, fn -> subs[sn]); | |
59 } | |
60 } | |
61 | |
62 void add_matching_sections(char *name, int yesflags, int noflags, int *base); | |
63 void check_section_flags(int yesflags, int noflags, int *base, fileinfo_t *fn) | |
64 { | |
65 int sn; | |
66 | |
67 if (fn -> forced == 0) | |
68 return; | |
69 | |
70 for (sn = 0; sn < fn -> nsections; sn++) | |
71 { | |
72 // ignore if the noflags tell us to | |
73 if (noflags && (fn -> sections[sn].flags & noflags)) | |
74 continue; | |
75 // ignore unless the yesflags tell us not to | |
76 if (yesflags && (fn -> sections[sn].flags & yesflags == 0)) | |
77 continue; | |
78 // ignore it if already processed | |
79 if (fn -> sections[sn].processed) | |
80 continue; | |
81 | |
82 // we have a match - now collect *all* sections of the same name! | |
83 add_matching_sections(fn -> sections[sn].name, 0, 0, base); | |
84 | |
85 // and then continue looking for sections | |
86 } | |
87 for (sn = 0; sn < fn -> nsubs; sn++) | |
88 { | |
89 check_section_flags(yesflags, noflags, base, fn -> subs[sn]); | |
90 } | |
91 } | |
92 | |
93 | |
94 | |
95 void add_matching_sections(char *name, int yesflags, int noflags, int *base) | |
96 { | |
97 int fn; | |
98 if (name) | |
99 { | |
100 // named section | |
101 // look for all instances of a section by the specified name | |
102 // and resolve base addresses and add to the list | |
103 for (fn = 0; fn < ninputfiles; fn++) | |
104 { | |
105 check_section_name(name, base, inputfiles[fn]); | |
106 } | |
107 } | |
108 else | |
109 { | |
110 // wildcard section | |
111 // named section | |
112 // look for all instances of a section by the specified name | |
113 // and resolve base addresses and add to the list | |
114 for (fn = 0; fn < ninputfiles; fn++) | |
115 { | |
116 check_section_flags(yesflags, noflags, base, inputfiles[fn]); | |
117 } | |
118 } | |
119 } | |
120 | |
121 // work out section load order and resolve base addresses for each section | |
122 // make a list of sections to load in order | |
123 void resolve_sections(void) | |
124 { | |
125 int laddr = 0; | |
126 int ln, sn, fn; | |
127 | |
128 for (ln = 0; ln < linkscript.nlines; ln++) | |
129 { | |
130 if (linkscript.lines[ln].loadat >= 0) | |
131 laddr = linkscript.lines[ln].loadat; | |
132 add_matching_sections(linkscript.lines[ln].sectname, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags, &laddr); | |
133 | |
134 if (linkscript.lines[ln].sectname) | |
135 { | |
136 } | |
137 else | |
138 { | |
139 // wildcard section | |
140 // look for all sections not yet processed that match flags | |
141 | |
142 int f = 0; | |
143 int fn0, sn0; | |
144 char *sname; | |
145 | |
146 // named section | |
147 // look for all instances of a section by the specified name | |
148 // and resolve base addresses and add to the list | |
149 for (fn0 = 0; fn0 < ninputfiles; fn0++) | |
150 { | |
151 for (sn0 = 0; sn0 < inputfiles[fn0] -> nsections; sn0++) | |
152 { | |
153 // ignore if the "no flags" bit says to | |
154 if (linkscript.lines[ln].noflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].noflags)) | |
155 continue; | |
156 // ignore unless the yes flags tell us not to | |
157 if (linkscript.lines[ln].yesflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].yesflags == 0)) | |
158 continue; | |
159 if (inputfiles[fn0] -> sections[sn0].processed == 0) | |
160 { | |
161 sname = inputfiles[fn0] -> sections[sn0].name; | |
162 for (fn = 0; fn < ninputfiles; fn++) | |
163 { | |
164 for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) | |
165 { | |
166 if (!strcmp(sname, inputfiles[fn] -> sections[sn].name)) | |
167 { | |
168 // we have a match | |
169 sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); | |
170 sectlist[nsects].ptr = &(inputfiles[fn] -> sections[sn]); | |
171 | |
172 inputfiles[fn] -> sections[sn].processed = 1; | |
173 if (!f && linkscript.lines[ln].loadat >= 0) | |
174 { | |
175 f = 1; | |
176 sectlist[nsects].forceaddr = 1; | |
177 laddr = linkscript.lines[ln].loadat; | |
178 } | |
179 else | |
180 { | |
181 sectlist[nsects].forceaddr = 0; | |
182 } | |
183 inputfiles[fn] -> sections[sn].loadaddress = laddr; | |
184 laddr += inputfiles[fn] -> sections[sn].codesize; | |
185 nsects++; | |
186 } | |
187 } | |
188 } | |
189 } | |
190 } | |
191 } | |
192 } | |
193 } | |
194 | |
195 // theoretically, all the base addresses are set now | |
196 } | |
197 | |
198 lw_expr_stack_t *find_external_sym_recurse(char *sym, fileinfo_t *fn) | |
199 { | |
200 int sn; | |
201 lw_expr_stack_t *r; | |
202 lw_expr_term_t *term; | |
203 symtab_t *se; | |
204 int val; | |
205 | |
206 for (sn = 0; sn < fn -> nsections; sn++) | |
207 { | |
208 for (se = fn -> sections[sn].exportedsyms; se; se = se -> next) | |
209 { | |
210 if (!strcmp(sym, se -> sym)) | |
211 { | |
212 if (!(fn -> forced)) | |
213 { | |
214 fn -> forced = 1; | |
215 nforced = 1; | |
216 } | |
217 val = se -> offset + fn -> sections[sn].loadaddress; | |
218 r = lw_expr_stack_create(); | |
219 term = lw_expr_term_create_int(val & 0xffff); | |
220 lw_expr_stack_push(r, term); | |
221 lw_expr_term_free(term); | |
222 return r; | |
223 } | |
224 } | |
225 } | |
226 | |
227 for (sn = 0; sn < fn -> nsubs; sn++) | |
228 { | |
229 r = find_external_sym_recurse(sym, fn -> subs[sn]); | |
230 if (r) | |
231 { | |
232 if (!(fn -> forced)) | |
233 { | |
234 nforced = 1; | |
235 fn -> forced = 1; | |
236 } | |
237 return r; | |
238 } | |
239 } | |
240 return NULL; | |
241 } | |
242 | |
243 // resolve all incomplete references now | |
244 // anything that is unresolvable at this stage will throw an error | |
245 // because we know the load address of every section now | |
246 lw_expr_stack_t *resolve_sym(char *sym, int symtype, void *state) | |
247 { | |
248 section_t *sect = state; | |
249 lw_expr_term_t *term; | |
250 int val = 0, i, fn; | |
251 lw_expr_stack_t *s; | |
252 symtab_t *se; | |
253 fileinfo_t *fp; | |
254 | |
255 if (symtype == 1) | |
256 { | |
257 // local symbol | |
258 if (!sym) | |
259 { | |
260 val = sect -> loadaddress; | |
261 goto out; | |
262 } | |
263 | |
264 // start with this section | |
265 for (se = sect -> localsyms; se; se = se -> next) | |
266 { | |
267 if (!strcmp(se -> sym, sym)) | |
268 { | |
269 val = se -> offset + sect -> loadaddress; | |
270 goto out; | |
271 } | |
272 } | |
273 // not in this section - check all sections in this file | |
274 for (i = 0; i < sect -> file -> nsections; i++) | |
275 { | |
276 for (se = sect -> file -> sections[i].localsyms; se; se = se -> next) | |
277 { | |
278 if (!strcmp(se -> sym, sym)) | |
279 { | |
280 val = se -> offset + sect -> file -> sections[i].loadaddress; | |
281 goto out; | |
282 } | |
283 } | |
284 } | |
285 // not found | |
286 symerr = 1; | |
287 fprintf(stderr, "Local symbol %s not found in %s:%s\n", sanitize_symbol(sym), sect -> file -> filename, sect -> name); | |
288 goto outerr; | |
289 } | |
290 else | |
291 { | |
292 // external symbol | |
293 // read all files in order until found (or not found) | |
294 if (sect) | |
295 { | |
296 for (fp = sect -> file; fp; fp = fp -> parent) | |
297 { | |
298 s = find_external_sym_recurse(sym, fp); | |
299 if (s) | |
300 return s; | |
301 } | |
302 } | |
303 | |
304 for (fn = 0; fn < ninputfiles; fn++) | |
305 { | |
306 s = find_external_sym_recurse(sym, inputfiles[fn]); | |
307 if (s) | |
308 return s; | |
309 } | |
310 if (sect) | |
311 { | |
312 fprintf(stderr, "External symbol %s not found in %s:%s\n", sanitize_symbol(sym), sect -> file -> filename, sect -> name); | |
313 } | |
314 else | |
315 { | |
316 fprintf(stderr, "External symbol %s not found\n", sym); | |
317 } | |
318 symerr = 1; | |
319 goto outerr; | |
320 } | |
321 fprintf(stderr, "Shouldn't ever get here!!!\n"); | |
322 exit(88); | |
323 out: | |
324 s = lw_expr_stack_create(); | |
325 term = lw_expr_term_create_int(val & 0xffff); | |
326 lw_expr_stack_push(s, term); | |
327 lw_expr_term_free(term); | |
328 return s; | |
329 outerr: | |
330 return NULL; | |
331 } | |
332 | |
333 void resolve_references(void) | |
334 { | |
335 int sn; | |
336 reloc_t *rl; | |
337 int rval; | |
338 | |
339 // resolve entry point if required | |
340 // this must resolve to an *exported* symbol and will resolve to the | |
341 // first instance of that symbol | |
342 if (linkscript.execsym) | |
343 { | |
344 lw_expr_stack_t *s; | |
345 | |
346 s = resolve_sym(linkscript.execsym, 0, NULL); | |
347 if (!s) | |
348 { | |
349 fprintf(stderr, "Cannot resolve exec address '%s'\n", linkscript.execsym); | |
350 symerr = 1; | |
351 } | |
352 else | |
353 { | |
354 linkscript.execaddr = lw_expr_get_value(s); | |
355 lw_expr_stack_free(s); | |
356 } | |
357 } | |
358 | |
359 for (sn = 0; sn < nsects; sn++) | |
360 { | |
361 for (rl = sectlist[sn].ptr -> incompletes; rl; rl = rl -> next) | |
362 { | |
363 // do a "simplify" on the expression | |
364 rval = lw_expr_reval(rl -> expr, resolve_sym, sectlist[sn].ptr); | |
365 | |
366 // is it constant? error out if not | |
367 if (rval != 0 || !lw_expr_is_constant(rl -> expr)) | |
368 { | |
369 fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", sectlist[sn].ptr -> file -> filename, sectlist[sn].ptr -> name, rl -> offset); | |
370 symerr = 1; | |
371 } | |
372 else | |
373 { | |
374 // put the value into the relocation address | |
375 rval = lw_expr_get_value(rl -> expr); | |
376 if (rl -> flags & RELOC_8BIT) | |
377 { | |
378 sectlist[sn].ptr -> code[rl -> offset] = rval & 0xff; | |
379 } | |
380 else | |
381 { | |
382 sectlist[sn].ptr -> code[rl -> offset] = (rval >> 8) & 0xff; | |
383 sectlist[sn].ptr -> code[rl -> offset + 1] = rval & 0xff; | |
384 } | |
385 } | |
386 } | |
387 } | |
388 | |
389 if (symerr) | |
390 exit(1); | |
391 } | |
392 | |
393 /* | |
394 This is just a pared down version of the algo for resolving references. | |
395 */ | |
396 void resolve_files(void) | |
397 { | |
398 int sn; | |
399 int fn; | |
400 reloc_t *rl; | |
401 lw_expr_stack_t *te; | |
402 | |
403 int rval; | |
404 | |
405 // resolve entry point if required | |
406 // this must resolve to an *exported* symbol and will resolve to the | |
407 // first instance of that symbol | |
408 if (linkscript.execsym) | |
409 { | |
410 lw_expr_stack_t *s; | |
411 | |
412 s = resolve_sym(linkscript.execsym, 0, NULL); | |
413 if (!s) | |
414 { | |
415 fprintf(stderr, "Cannot resolve exec address '%s'\n", sanitize_symbol(linkscript.execsym)); | |
416 symerr = 1; | |
417 } | |
418 } | |
419 | |
420 do | |
421 { | |
422 nforced = 0; | |
423 for (fn = 0; fn < ninputfiles; fn++) | |
424 { | |
425 if (inputfiles[fn] -> forced == 0) | |
426 continue; | |
427 | |
428 for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) | |
429 { | |
430 for (rl = inputfiles[fn] -> sections[sn].incompletes; rl; rl = rl -> next) | |
431 { | |
432 // do a "simplify" on the expression | |
433 te = lw_expr_stack_dup(rl -> expr); | |
434 rval = lw_expr_reval(te, resolve_sym, &(inputfiles[fn] -> sections[sn])); | |
435 | |
436 // is it constant? error out if not | |
437 if (rval != 0 || !lw_expr_is_constant(te)) | |
438 { | |
439 fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", inputfiles[fn] -> filename, inputfiles[fn] -> sections[sn].name, rl -> offset); | |
440 symerr = 1; | |
441 } | |
442 lw_expr_stack_free(te); | |
443 } | |
444 } | |
445 } | |
446 } | |
447 while (nforced == 1); | |
448 | |
449 if (symerr) | |
450 exit(1); | |
451 | |
452 // theoretically, all files referenced by other files now have "forced" set to 1 | |
453 for (fn = 0; fn < ninputfiles; fn++) | |
454 { | |
455 if (inputfiles[fn] -> forced == 1) | |
456 continue; | |
457 | |
458 fprintf(stderr, "Warning: %s (%d) does not resolve any symbols\n", inputfiles[fn] -> filename, fn); | |
459 } | |
460 } |