Mercurial > hg-old > index.cgi
annotate lwlink/link.c @ 205:42df94f30d82
checkpoint
author | lost |
---|---|
date | Sun, 19 Apr 2009 17:44:46 +0000 |
parents | 048ebb85f6ef |
children | 299c5d793aca |
rev | line source |
---|---|
119 | 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 #ifdef HAVE_CONFIG_H | |
25 #include "config.h" | |
26 #endif | |
27 | |
120 | 28 #include <stdio.h> |
119 | 29 #include <stdlib.h> |
30 | |
120 | 31 #include "expr.h" |
119 | 32 #include "lwlink.h" |
33 #include "util.h" | |
34 | |
121 | 35 struct section_list *sectlist = NULL; |
36 int nsects = 0; | |
205 | 37 static int nforced = 0; |
119 | 38 |
171 | 39 void check_section_name(char *name, int *base, fileinfo_t *fn) |
40 { | |
41 int sn; | |
205 | 42 |
43 if (fn -> forced == 0) | |
44 return; | |
45 | |
171 | 46 for (sn = 0; sn < fn -> nsections; sn++) |
47 { | |
48 if (!strcmp(name, fn -> sections[sn].name)) | |
49 { | |
50 // we have a match | |
51 sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); | |
52 sectlist[nsects].ptr = &(fn -> sections[sn]); | |
53 | |
54 fn -> sections[sn].processed = 1; | |
55 fn -> sections[sn].loadaddress = *base; | |
56 *base += fn -> sections[sn].codesize; | |
57 nsects++; | |
58 } | |
59 } | |
173 | 60 for (sn = 0; sn < fn -> nsubs; sn++) |
171 | 61 { |
62 check_section_name(name, base, fn -> subs[sn]); | |
63 } | |
64 } | |
65 | |
66 void add_matching_sections(char *name, int yesflags, int noflags, int *base); | |
67 void check_section_flags(int yesflags, int noflags, int *base, fileinfo_t *fn) | |
68 { | |
69 int sn; | |
205 | 70 |
71 if (fn -> forced == 0) | |
72 return; | |
73 | |
171 | 74 for (sn = 0; sn < fn -> nsections; sn++) |
75 { | |
76 // ignore if the noflags tell us to | |
77 if (noflags && (fn -> sections[sn].flags & noflags)) | |
78 continue; | |
79 // ignore unless the yesflags tell us not to | |
80 if (yesflags && (fn -> sections[sn].flags & yesflags == 0)) | |
81 continue; | |
82 // ignore it if already processed | |
83 if (fn -> sections[sn].processed) | |
84 continue; | |
85 | |
86 // we have a match - now collect *all* sections of the same name! | |
87 add_matching_sections(fn -> sections[sn].name, 0, 0, base); | |
88 | |
89 // and then continue looking for sections | |
90 } | |
173 | 91 for (sn = 0; sn < fn -> nsubs; sn++) |
171 | 92 { |
93 check_section_flags(yesflags, noflags, base, fn -> subs[sn]); | |
94 } | |
95 } | |
96 | |
97 | |
98 | |
99 void add_matching_sections(char *name, int yesflags, int noflags, int *base) | |
100 { | |
101 int fn; | |
102 if (name) | |
103 { | |
104 // named section | |
105 // look for all instances of a section by the specified name | |
106 // and resolve base addresses and add to the list | |
107 for (fn = 0; fn < ninputfiles; fn++) | |
108 { | |
109 check_section_name(name, base, inputfiles[fn]); | |
110 } | |
111 } | |
112 else | |
113 { | |
114 // wildcard section | |
115 // named section | |
116 // look for all instances of a section by the specified name | |
117 // and resolve base addresses and add to the list | |
118 for (fn = 0; fn < ninputfiles; fn++) | |
119 { | |
120 check_section_flags(yesflags, noflags, base, inputfiles[fn]); | |
121 } | |
122 } | |
123 } | |
124 | |
119 | 125 // work out section load order and resolve base addresses for each section |
126 // make a list of sections to load in order | |
127 void resolve_sections(void) | |
128 { | |
129 int laddr = 0; | |
130 int ln, sn, fn; | |
131 | |
132 for (ln = 0; ln < linkscript.nlines; ln++) | |
133 { | |
171 | 134 if (linkscript.lines[ln].loadat >= 0) |
135 laddr = linkscript.lines[ln].loadat; | |
136 add_matching_sections(linkscript.lines[ln].sectname, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags, &laddr); | |
137 | |
119 | 138 if (linkscript.lines[ln].sectname) |
139 { | |
140 } | |
141 else | |
142 { | |
143 // wildcard section | |
144 // look for all sections not yet processed that match flags | |
145 | |
146 int f = 0; | |
147 int fn0, sn0; | |
148 char *sname; | |
149 | |
150 // named section | |
151 // look for all instances of a section by the specified name | |
152 // and resolve base addresses and add to the list | |
153 for (fn0 = 0; fn0 < ninputfiles; fn0++) | |
154 { | |
155 for (sn0 = 0; sn0 < inputfiles[fn0] -> nsections; sn0++) | |
156 { | |
157 // ignore if the "no flags" bit says to | |
158 if (linkscript.lines[ln].noflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].noflags)) | |
159 continue; | |
160 // ignore unless the yes flags tell us not to | |
161 if (linkscript.lines[ln].yesflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].yesflags == 0)) | |
162 continue; | |
163 if (inputfiles[fn0] -> sections[sn0].processed == 0) | |
164 { | |
165 sname = inputfiles[fn0] -> sections[sn0].name; | |
166 for (fn = 0; fn < ninputfiles; fn++) | |
167 { | |
168 for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) | |
169 { | |
170 if (!strcmp(sname, inputfiles[fn] -> sections[sn].name)) | |
171 { | |
172 // we have a match | |
173 sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); | |
174 sectlist[nsects].ptr = &(inputfiles[fn] -> sections[sn]); | |
175 | |
176 inputfiles[fn] -> sections[sn].processed = 1; | |
177 if (!f && linkscript.lines[ln].loadat >= 0) | |
178 { | |
179 f = 1; | |
180 sectlist[nsects].forceaddr = 1; | |
181 laddr = linkscript.lines[ln].loadat; | |
182 } | |
183 else | |
184 { | |
185 sectlist[nsects].forceaddr = 0; | |
186 } | |
187 inputfiles[fn] -> sections[sn].loadaddress = laddr; | |
131
5276565799bd
Fixed load addresses of chained sections and subsections to actually increment
lost
parents:
130
diff
changeset
|
188 laddr += inputfiles[fn] -> sections[sn].codesize; |
119 | 189 nsects++; |
190 } | |
191 } | |
192 } | |
193 } | |
194 } | |
195 } | |
196 } | |
197 } | |
198 | |
199 // theoretically, all the base addresses are set now | |
200 } | |
120 | 201 |
171 | 202 lw_expr_stack_t *find_external_sym_recurse(char *sym, fileinfo_t *fn) |
203 { | |
204 int sn; | |
205 lw_expr_stack_t *r; | |
206 lw_expr_term_t *term; | |
207 symtab_t *se; | |
208 int val; | |
209 | |
210 for (sn = 0; sn < fn -> nsections; sn++) | |
211 { | |
212 for (se = fn -> sections[sn].exportedsyms; se; se = se -> next) | |
213 { | |
214 if (!strcmp(sym, se -> sym)) | |
215 { | |
205 | 216 if (!(fn -> forced)) |
217 { | |
218 fn -> forced = 1; | |
219 nforced = 1; | |
220 } | |
171 | 221 val = se -> offset + fn -> sections[sn].loadaddress; |
222 r = lw_expr_stack_create(); | |
223 term = lw_expr_term_create_int(val & 0xffff); | |
224 lw_expr_stack_push(r, term); | |
225 lw_expr_term_free(term); | |
226 return r; | |
227 } | |
228 } | |
229 } | |
230 | |
231 for (sn = 0; sn < fn -> nsubs; sn++) | |
232 { | |
233 r = find_external_sym_recurse(sym, fn -> subs[sn]); | |
234 if (r) | |
205 | 235 { |
236 if (!(fn -> forced)) | |
237 { | |
238 nforced = 1; | |
239 fn -> forced = 1; | |
240 } | |
171 | 241 return r; |
205 | 242 } |
171 | 243 } |
244 return NULL; | |
245 } | |
246 | |
120 | 247 // resolve all incomplete references now |
248 // anything that is unresolvable at this stage will throw an error | |
249 // because we know the load address of every section now | |
250 lw_expr_stack_t *resolve_sym(char *sym, int symtype, void *state) | |
251 { | |
252 section_t *sect = state; | |
253 lw_expr_term_t *term; | |
254 int val = 0, i, fn; | |
255 lw_expr_stack_t *s; | |
256 symtab_t *se; | |
171 | 257 fileinfo_t *fp; |
258 | |
120 | 259 if (symtype == 1) |
260 { | |
261 // local symbol | |
262 if (!sym) | |
263 { | |
264 val = sect -> loadaddress; | |
265 goto out; | |
266 } | |
267 | |
268 // start with this section | |
269 for (se = sect -> localsyms; se; se = se -> next) | |
270 { | |
271 if (!strcmp(se -> sym, sym)) | |
272 { | |
273 val = se -> offset + sect -> loadaddress; | |
274 goto out; | |
275 } | |
276 } | |
277 // not in this section - check all sections in this file | |
278 for (i = 0; i < sect -> file -> nsections; i++) | |
279 { | |
280 for (se = sect -> file -> sections[i].localsyms; se; se = se -> next) | |
281 { | |
282 if (!strcmp(se -> sym, sym)) | |
283 { | |
284 val = se -> offset + sect -> file -> sections[i].loadaddress; | |
285 goto out; | |
286 } | |
287 } | |
288 } | |
289 // not found | |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
290 symerr = 1; |
120 | 291 fprintf(stderr, "Local symbol %s not found in %s:%s\n", sym, sect -> file -> filename, sect -> name); |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
292 goto outerr; |
120 | 293 } |
294 else | |
295 { | |
296 // external symbol | |
297 // read all files in order until found (or not found) | |
173 | 298 if (sect) |
171 | 299 { |
173 | 300 for (fp = sect -> file; fp; fp = fp -> parent) |
301 { | |
302 s = find_external_sym_recurse(sym, fp); | |
303 if (s) | |
304 return s; | |
305 } | |
171 | 306 } |
307 | |
120 | 308 for (fn = 0; fn < ninputfiles; fn++) |
309 { | |
171 | 310 s = find_external_sym_recurse(sym, inputfiles[fn]); |
311 if (s) | |
312 return s; | |
120 | 313 } |
130 | 314 if (sect) |
315 { | |
316 fprintf(stderr, "External symbol %s not found in %s:%s\n", sym, sect -> file -> filename, sect -> name); | |
317 } | |
318 else | |
319 { | |
320 fprintf(stderr, "External symbol %s not found\n", sym); | |
321 } | |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
322 symerr = 1; |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
323 goto outerr; |
120 | 324 } |
325 fprintf(stderr, "Shouldn't ever get here!!!\n"); | |
326 exit(88); | |
327 out: | |
328 s = lw_expr_stack_create(); | |
329 term = lw_expr_term_create_int(val & 0xffff); | |
330 lw_expr_stack_push(s, term); | |
331 lw_expr_term_free(term); | |
332 return s; | |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
333 outerr: |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
334 return NULL; |
120 | 335 } |
336 | |
337 void resolve_references(void) | |
338 { | |
339 int sn; | |
340 reloc_t *rl; | |
341 int rval; | |
121 | 342 |
343 // resolve entry point if required | |
344 // this must resolve to an *exported* symbol and will resolve to the | |
345 // first instance of that symbol | |
346 if (linkscript.execsym) | |
347 { | |
348 lw_expr_stack_t *s; | |
349 | |
350 s = resolve_sym(linkscript.execsym, 0, NULL); | |
187 | 351 if (!s) |
352 { | |
353 fprintf(stderr, "Cannot resolve exec address '%s'\n", linkscript.execsym); | |
354 symerr = 1; | |
355 } | |
356 else | |
357 { | |
358 linkscript.execaddr = lw_expr_get_value(s); | |
359 lw_expr_stack_free(s); | |
360 } | |
121 | 361 } |
120 | 362 |
124 | 363 for (sn = 0; sn < nsects; sn++) |
120 | 364 { |
365 for (rl = sectlist[sn].ptr -> incompletes; rl; rl = rl -> next) | |
366 { | |
367 // do a "simplify" on the expression | |
368 rval = lw_expr_reval(rl -> expr, resolve_sym, sectlist[sn].ptr); | |
369 | |
370 // is it constant? error out if not | |
371 if (rval != 0 || !lw_expr_is_constant(rl -> expr)) | |
372 { | |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
373 fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", sectlist[sn].ptr -> file -> filename, sectlist[sn].ptr -> name, rl -> offset); |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
374 symerr = 1; |
120 | 375 } |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
376 else |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
377 { |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
378 // put the value into the relocation address |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
379 rval = lw_expr_get_value(rl -> expr); |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
380 if (rl -> flags & RELOC_8BIT) |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
381 { |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
382 sectlist[sn].ptr -> code[rl -> offset] = rval & 0xff; |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
383 } |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
384 else |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
385 { |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
386 sectlist[sn].ptr -> code[rl -> offset] = (rval >> 8) & 0xff; |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
387 sectlist[sn].ptr -> code[rl -> offset + 1] = rval & 0xff; |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
187
diff
changeset
|
388 } |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
389 } |
120 | 390 } |
391 } | |
184
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
392 |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
393 if (symerr) |
220a760ec654
Make lwlink display all undefined references instead of bailing after the first one
lost
parents:
173
diff
changeset
|
394 exit(1); |
120 | 395 } |
205 | 396 |
397 /* | |
398 This is just a pared down version of the algo for resolving references. | |
399 */ | |
400 void resolve_files(void) | |
401 { | |
402 int sn; | |
403 int fn; | |
404 reloc_t *rl; | |
405 int rval; | |
406 | |
407 // resolve entry point if required | |
408 // this must resolve to an *exported* symbol and will resolve to the | |
409 // first instance of that symbol | |
410 if (linkscript.execsym) | |
411 { | |
412 lw_expr_stack_t *s; | |
413 | |
414 s = resolve_sym(linkscript.execsym, 0, NULL); | |
415 if (!s) | |
416 { | |
417 fprintf(stderr, "Cannot resolve exec address '%s'\n", linkscript.execsym); | |
418 symerr = 1; | |
419 } | |
420 } | |
421 | |
422 do | |
423 { | |
424 nforced = 0; | |
425 for (fn = 0; fn < ninputfiles; fn++) | |
426 { | |
427 if (inputfiles[fn] -> forced == 0) | |
428 continue; | |
429 | |
430 for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) | |
431 { | |
432 for (rl = inputfiles[fn] -> sections[sn].incompletes; rl; rl = rl -> next) | |
433 { | |
434 // do a "simplify" on the expression | |
435 rval = lw_expr_reval(rl -> expr, resolve_sym, &(inputfiles[fn] -> sections[sn])); | |
436 | |
437 // is it constant? error out if not | |
438 if (rval != 0 || !lw_expr_is_constant(rl -> expr)) | |
439 { | |
440 fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", inputfiles[fn] -> filename, inputfiles[fn] -> sections[sn].name, rl -> offset); | |
441 symerr = 1; | |
442 } | |
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 } |