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 }