GNU Binutils with patches for OS216
Revision | 2fa0b342a5cd580781d2b9348a87f33a92d363fa (tree) |
---|---|
Zeit | 1991-03-22 06:29:06 |
Autor | David Henkel-Wallace <gumby@cygn...> |
Commiter | David Henkel-Wallace |
Initial revision
@@ -0,0 +1,850 @@ | ||
1 | + | |
2 | + | |
3 | + | |
4 | +/* ar.c - Archive modify and extract. */ | |
5 | +/* | |
6 | + Bugs: should use getopt the way tar does (complete w/optional -) and | |
7 | + should have long options too. GNU ar used to check file against filesystem | |
8 | + in quick_update and replace operations (would check mtime). Doesn't warn | |
9 | + when name truncated. No way to specify pos_end. Error messages should be | |
10 | + more consistant. | |
11 | +*/ | |
12 | +#include "sysdep.h" | |
13 | +#include "bfd.h" | |
14 | +#include "ar.h" | |
15 | +#include <stdio.h> | |
16 | +#include <sys/time.h> | |
17 | +#include <errno.h> | |
18 | +#define BUFSIZE 8192 | |
19 | +/* Not great to have these here. Should they be exported or not? */ | |
20 | +PROTO(size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd * abfd)); | |
21 | +PROTO(size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd * abfd)); | |
22 | +/* PROTO (void, open_inarch, (char *archive_filename)); */ | |
23 | +#ifdef __STDC__ | |
24 | +static void open_inarch(char *archive_filename); | |
25 | +#else | |
26 | +static void open_inarch(); | |
27 | +#endif /* __STDC__ */ | |
28 | + | |
29 | +PROTO(void, map_over_members, (void (*function) (), char **files, int count)); | |
30 | +PROTO(void, print_contents, (bfd * member)); | |
31 | +PROTO(void, extract_file, (bfd * abfd)); | |
32 | +PROTO(void, delete_members, (char **files_to_delete)); | |
33 | +PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append)); | |
34 | +PROTO(void, move_members, (char **files_to_move)); | |
35 | +PROTO(void, replace_members, (char **files_to_replace)); | |
36 | +PROTO(void, print_descr, (bfd * abfd)); | |
37 | +PROTO(void, ranlib_only, (char *archname)); | |
38 | + | |
39 | +/** Globals and flags */ | |
40 | + | |
41 | +char *program_name = NULL; | |
42 | +bfd bogus_archive; | |
43 | +bfd *inarch; /* The input arch we're manipulating */ | |
44 | + | |
45 | +/* Nonzero means don't warn about creating the archive file if necessary. */ | |
46 | +int silent_create = 0; | |
47 | +/* Nonzero means describe each action performed. */ | |
48 | +int verbose = 0; | |
49 | +/* Nonzero means preserve dates of members when extracting them. */ | |
50 | +int preserve_dates = 0; | |
51 | +/* | |
52 | + Nonzero means don't replace existing members whose dates are more recent | |
53 | + than the corresponding files. | |
54 | +*/ | |
55 | +int newer_only = 0; | |
56 | +/* write a __.SYMDEF member into the modified archive. */ | |
57 | +boolean write_armap = false; | |
58 | +/* | |
59 | + Nonzero means don't update __.SYMDEF unless command line explicitly | |
60 | + requested it | |
61 | +*/ | |
62 | +int ignore_symdef = 0; | |
63 | +/* | |
64 | + Nonzero means it's the name of an existing member; position new or moved | |
65 | + files with respect to this one. | |
66 | +*/ | |
67 | +char *posname = NULL; | |
68 | +/* | |
69 | + Sez how to use `posname': pos_before means position before that member. | |
70 | + pos_after means position after that member. pos_end means always at end. | |
71 | + pos_default means default appropriately. For the latter two, `posname' | |
72 | + should also be zero. | |
73 | +*/ | |
74 | +enum pos { | |
75 | + pos_default, pos_before, pos_after, pos_end | |
76 | +} postype = pos_default; | |
77 | + | |
78 | +/* | |
79 | + The option parsing should be in its own function. It will be when I have | |
80 | + getopt working. | |
81 | +*/ | |
82 | +int | |
83 | +main(argc, argv) | |
84 | + int argc; | |
85 | + char **argv; | |
86 | +{ | |
87 | + char *arg_ptr; | |
88 | + char c; | |
89 | + enum { | |
90 | + none = 0, delete, replace, print_table, | |
91 | + print_files, extract, move, quick_append | |
92 | + } operation = none; | |
93 | + int arg_index; | |
94 | + char **files; | |
95 | + char *inarch_filename; | |
96 | + char *temp; | |
97 | + program_name = argv[0]; | |
98 | + | |
99 | + | |
100 | + temp = strrchr(program_name, '/'); | |
101 | + if (temp == (char *) NULL) | |
102 | + temp = program_name; /* shouldn't happen, but... */ | |
103 | + else | |
104 | + ++temp; | |
105 | + if (!strcmp(temp, "ranlib")) { | |
106 | + if (argc < 2) | |
107 | + fatal("Too few command arguments."); | |
108 | + ranlib_only(argv[1]); | |
109 | + } | |
110 | + | |
111 | + | |
112 | + if (argc < 3) | |
113 | + fatal("Too few command arguments."); | |
114 | + | |
115 | + arg_ptr = argv[1]; | |
116 | + | |
117 | + if (*arg_ptr == '-') | |
118 | + ++arg_ptr; /* compatibility */ | |
119 | + | |
120 | + while (c = *arg_ptr++) { | |
121 | + switch (c) { | |
122 | + case 'd': | |
123 | + case 'm': | |
124 | + case 'p': | |
125 | + case 'q': | |
126 | + case 'r': | |
127 | + case 't': | |
128 | + case 'x': | |
129 | + if (operation != none) | |
130 | + fatal("two different operation switches specified"); | |
131 | + switch (c) { | |
132 | + case 'd': | |
133 | + operation = delete; | |
134 | + break; | |
135 | + case 'm': | |
136 | + operation = move; | |
137 | + break; | |
138 | + case 'p': | |
139 | + operation = print_files; | |
140 | + break; | |
141 | + case 'q': | |
142 | + operation = quick_append; | |
143 | + break; | |
144 | + case 'r': | |
145 | + operation = replace; | |
146 | + break; | |
147 | + case 't': | |
148 | + operation = print_table; | |
149 | + break; | |
150 | + case 'x': | |
151 | + operation = extract; | |
152 | + break; | |
153 | + } | |
154 | + case 'l': | |
155 | + break; | |
156 | + case 'c': | |
157 | + silent_create = 1; | |
158 | + break; | |
159 | + case 'o': | |
160 | + preserve_dates = 1; | |
161 | + break; | |
162 | + case 's': | |
163 | + write_armap = true; | |
164 | + break; | |
165 | + case 'u': | |
166 | + newer_only = 1; | |
167 | + break; | |
168 | + case 'v': | |
169 | + verbose = 1; | |
170 | + break; | |
171 | + case 'a': | |
172 | + postype = pos_after; | |
173 | + break; | |
174 | + case 'b': | |
175 | + postype = pos_before; | |
176 | + break; | |
177 | + case 'i': | |
178 | + postype = pos_before; | |
179 | + break; | |
180 | + default: | |
181 | + fatal("invalid option %c", c); | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + if (operation == none && write_armap) | |
186 | + ranlib_only(argv[2]); | |
187 | + | |
188 | + if (operation == none) | |
189 | + fatal("no operation specified"); | |
190 | + | |
191 | + if (newer_only && operation != replace) | |
192 | + fatal("'u' only meaningful with 'r' option."); | |
193 | + | |
194 | + arg_index = 2; | |
195 | + | |
196 | + if (postype != pos_default) | |
197 | + posname = argv[arg_index++]; | |
198 | + | |
199 | + inarch_filename = argv[arg_index++]; | |
200 | + | |
201 | + if (arg_index < argc) { | |
202 | + files = argv + arg_index; | |
203 | + while (arg_index < argc) | |
204 | + if (!strcmp(argv[arg_index++], "__.SYMDEF")) { | |
205 | + ignore_symdef = 1; | |
206 | + break; | |
207 | + } | |
208 | + } | |
209 | + else | |
210 | + files = NULL; | |
211 | + | |
212 | + if (operation == quick_append) { | |
213 | + if (files != NULL) | |
214 | + do_quick_append(inarch_filename, files); | |
215 | + exit(0); | |
216 | + } | |
217 | + | |
218 | + | |
219 | + open_inarch(inarch_filename); | |
220 | + /* | |
221 | + If we have no archive, and we've been asked to replace then create one | |
222 | + */ | |
223 | + | |
224 | + if (operation == replace && | |
225 | + inarch == &bogus_archive) { | |
226 | + silent_create = 1; | |
227 | + do_quick_append(inarch_filename, 0); | |
228 | + open_inarch(inarch_filename); | |
229 | + } | |
230 | + | |
231 | + switch (operation) { | |
232 | + | |
233 | + case print_table: | |
234 | + map_over_members(print_descr, files, argc - 3); | |
235 | + break; | |
236 | + | |
237 | + case print_files: | |
238 | + map_over_members(print_contents, files, argc - 3); | |
239 | + break; | |
240 | + | |
241 | + case extract: | |
242 | + map_over_members(extract_file, files, argc - 3); | |
243 | + break; | |
244 | + | |
245 | + case delete: | |
246 | + if (files != NULL) | |
247 | + delete_members(files); | |
248 | + break; | |
249 | + | |
250 | + case move: | |
251 | + if (files != NULL) | |
252 | + move_members(files); | |
253 | + break; | |
254 | + | |
255 | + case replace: | |
256 | + if (files != NULL || write_armap) | |
257 | + replace_members(files); | |
258 | + break; | |
259 | + | |
260 | + /* Shouldn't happen! */ | |
261 | + default: | |
262 | + fprintf(stderr, "Sorry; this option not implemented.\n"); | |
263 | + } | |
264 | + | |
265 | + return (0); | |
266 | +} /* main() */ | |
267 | + | |
268 | +static | |
269 | +char *normalize(file) | |
270 | +char *file; | |
271 | +{ | |
272 | + char * filename = strrchr(file, '/'); | |
273 | + if (filename != (char *)NULL) { | |
274 | + filename ++; | |
275 | + } | |
276 | + else { | |
277 | + filename = file; | |
278 | + } | |
279 | + return filename; | |
280 | +} | |
281 | + | |
282 | +static void | |
283 | +open_inarch(archive_filename) | |
284 | + char *archive_filename; | |
285 | +{ | |
286 | + bfd **last_one; | |
287 | + bfd *next_one; | |
288 | + struct stat sbuf; | |
289 | + bfd_error = no_error; | |
290 | + if (stat(archive_filename, &sbuf) != 0) { | |
291 | + if (errno != ENOENT) | |
292 | + bfd_fatal(archive_filename); | |
293 | + if (!silent_create) | |
294 | + fprintf(stderr, | |
295 | + "%s: creating %s\n", program_name, archive_filename); | |
296 | + | |
297 | + inarch = &bogus_archive; | |
298 | + inarch->filename = archive_filename; | |
299 | + inarch->has_armap = true; | |
300 | + | |
301 | + } | |
302 | + else { | |
303 | + inarch = bfd_openr(archive_filename, NULL); | |
304 | + if (inarch == NULL) { | |
305 | + bloser: | |
306 | + bfd_perror(archive_filename); | |
307 | + exit(1); | |
308 | + } | |
309 | + | |
310 | + if (bfd_check_format(inarch, bfd_archive) != true) | |
311 | + fatal("File %s is not an archive.", archive_filename); | |
312 | + last_one = &(inarch->next); | |
313 | + /* Read all the contents right away, regardless. */ | |
314 | + for (next_one = bfd_openr_next_archived_file(inarch, NULL); | |
315 | + next_one; | |
316 | + next_one = bfd_openr_next_archived_file(inarch, next_one)) { | |
317 | + *last_one = next_one; | |
318 | + last_one = &next_one->next; | |
319 | + } | |
320 | + *last_one = (bfd *) NULL; | |
321 | + if (bfd_error != no_more_archived_files) | |
322 | + goto bloser; | |
323 | + } | |
324 | +} | |
325 | + | |
326 | + | |
327 | + | |
328 | +/* | |
329 | + If count is 0, then function is called once on each entry. if nonzero, | |
330 | + count is the length of the files chain; function is called on each entry | |
331 | + whose name matches one in files | |
332 | +*/ | |
333 | +void | |
334 | +map_over_members(function, files, count) | |
335 | + void (*function) (); | |
336 | + char **files; | |
337 | + int count; | |
338 | +{ | |
339 | + bfd *head; | |
340 | + | |
341 | + | |
342 | + | |
343 | + | |
344 | + if (count == 0) { | |
345 | + for (head = inarch->next; head; head = head->next) | |
346 | + function(head); | |
347 | + return; | |
348 | + } | |
349 | + /* | |
350 | + This may appear to be a baroque way of accomplishing what we want. | |
351 | + however we have to iterate over the filenames in order to notice where | |
352 | + a filename is requested but does not exist in the archive. Ditto | |
353 | + mapping over each file each time -- we want to hack multiple | |
354 | + references. | |
355 | + */ | |
356 | + | |
357 | + for (; count > 0; files++, count--) { | |
358 | + boolean found = false; | |
359 | + for (head = inarch->next; head; head = head->next) | |
360 | + if ((head->filename != NULL) && | |
361 | + (!strcmp(*files, head->filename))) { | |
362 | + found = true; | |
363 | + function(head); | |
364 | + } | |
365 | + if (!found) | |
366 | + fprintf(stderr, "No entry %s in archive.\n", *files); | |
367 | + } | |
368 | +} | |
369 | + | |
370 | + | |
371 | +/* Things which are interesting to map over all or some of the files: */ | |
372 | + | |
373 | +void | |
374 | +print_descr(abfd) | |
375 | + bfd *abfd; | |
376 | +{ | |
377 | + print_arelt_descr(abfd, verbose); | |
378 | +} | |
379 | + | |
380 | +void | |
381 | +print_contents(abfd) | |
382 | + bfd *abfd; | |
383 | +{ | |
384 | + int ncopied = 0; | |
385 | + struct stat buf; | |
386 | + long size; | |
387 | + if (bfd_stat_arch_elt(abfd, &buf) != 0) | |
388 | + fatal("Internal stat error on %s", abfd->filename); | |
389 | + | |
390 | + if (verbose) | |
391 | + printf("\n<member %s>\n\n", abfd->filename); | |
392 | + | |
393 | + bfd_seek(abfd, 0, SEEK_SET); | |
394 | + | |
395 | + size = buf.st_size; | |
396 | + while (ncopied < size) { | |
397 | + char cbuf[BUFSIZE]; | |
398 | + int nread; | |
399 | + int tocopy = size - ncopied; | |
400 | + if (tocopy > BUFSIZE) | |
401 | + tocopy = BUFSIZE; | |
402 | + | |
403 | + nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke | |
404 | + abstraction! */ | |
405 | + | |
406 | + if (nread != tocopy) | |
407 | + fatal("file %s not a valid archive", abfd->my_archive->filename); | |
408 | + fwrite(cbuf, 1, nread, stdout); | |
409 | + ncopied += tocopy; | |
410 | + } | |
411 | +} | |
412 | + | |
413 | + | |
414 | +/* | |
415 | + Extract a member of the archive into its own file. | |
416 | + | |
417 | +We defer opening the new file until after we have read a BUFSIZ chunk of the | |
418 | + old one, since we know we have just read the archive header for the old | |
419 | + one. Since most members are shorter than BUFSIZ, this means we will read | |
420 | + the old header, read the old data, write a new inode for the new file, and | |
421 | + write the new data, and be done. This 'optimization' is what comes from | |
422 | + sitting next to a bare disk and hearing it every time it seeks. -- Gnu | |
423 | + Gilmore | |
424 | +*/ | |
425 | + | |
426 | +void | |
427 | +extract_file(abfd) | |
428 | + bfd *abfd; | |
429 | +{ | |
430 | + FILE *ostream; | |
431 | + char cbuf[BUFSIZE]; | |
432 | + int nread, | |
433 | + tocopy; | |
434 | + int ncopied = 0; | |
435 | + long size; | |
436 | + struct stat buf; | |
437 | + if (bfd_stat_arch_elt(abfd, &buf) != 0) | |
438 | + fatal("Internal stat error on %s", abfd->filename); | |
439 | + size = buf.st_size; | |
440 | + | |
441 | + if (verbose) | |
442 | + printf("x - %s\n", abfd->filename); | |
443 | + | |
444 | + bfd_seek(abfd, 0, SEEK_SET); | |
445 | + | |
446 | + ostream = 0; | |
447 | + while (ncopied < size) { | |
448 | + tocopy = size - ncopied; | |
449 | + if (tocopy > BUFSIZE) | |
450 | + tocopy = BUFSIZE; | |
451 | + | |
452 | + nread = bfd_read(cbuf, 1, tocopy, abfd); | |
453 | + if (nread != tocopy) | |
454 | + fatal("file %s not a valid archive", abfd->my_archive->filename); | |
455 | + | |
456 | + /* See comment above; this saves disk arm motion */ | |
457 | + if (!ostream) { | |
458 | + /* Seems like an abstraction violation, eh? Well it's OK! */ | |
459 | + ostream = fopen(abfd->filename, "w"); | |
460 | + if (!ostream) { | |
461 | + perror(abfd->filename); | |
462 | + exit(1); | |
463 | + } | |
464 | + } | |
465 | + /* no need to byte-swap; the two formats are presumably compatible(!) */ | |
466 | + fwrite(cbuf, 1, nread, ostream); | |
467 | + ncopied += tocopy; | |
468 | + } | |
469 | + | |
470 | + fclose(ostream); | |
471 | + chmod(abfd->filename, buf.st_mode); | |
472 | + | |
473 | + if (preserve_dates) { | |
474 | +#ifdef USG | |
475 | + long tb[2]; | |
476 | + tb[0] = buf.st_mtime; | |
477 | + tb[1] = buf.st_mtime; | |
478 | + utime(abfd->filename, tb); /* FIXME check result */ | |
479 | +#else | |
480 | + struct timeval tv[2]; | |
481 | + tv[0].tv_sec = buf.st_mtime; | |
482 | + tv[0].tv_usec = 0; | |
483 | + tv[1].tv_sec = buf.st_mtime; | |
484 | + tv[1].tv_usec = 0; | |
485 | + utimes(abfd->filename, tv); /* FIXME check result */ | |
486 | +#endif | |
487 | + } | |
488 | +} | |
489 | + | |
490 | + | |
491 | +/* Just do it quickly; don't worry about dups, armap, or anything like that */ | |
492 | + | |
493 | +/* This is ugly! XXX */ | |
494 | + | |
495 | +PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (char *filename)); | |
496 | + | |
497 | +void | |
498 | +do_quick_append(archive_filename, files_to_append) | |
499 | + char *archive_filename; | |
500 | + char **files_to_append; | |
501 | + | |
502 | +{ | |
503 | + FILE *ofile, | |
504 | + *ifile; | |
505 | + char buf[BUFSIZE]; | |
506 | + long tocopy, | |
507 | + thistime; | |
508 | + bfd *temp; | |
509 | + struct stat sbuf; | |
510 | + boolean newfile = false; | |
511 | + bfd_error = no_error; | |
512 | + | |
513 | + if (stat(archive_filename, &sbuf) != 0) { | |
514 | + if (errno != ENOENT) | |
515 | + bfd_fatal(archive_filename); | |
516 | + newfile = true; | |
517 | + } | |
518 | + | |
519 | + | |
520 | + ofile = fopen(archive_filename, "a+"); | |
521 | + if (ofile == NULL) { | |
522 | + perror(program_name); | |
523 | + exit(1); | |
524 | + } | |
525 | + | |
526 | + /* bletch */ | |
527 | + temp = bfd_openr(archive_filename, NULL); | |
528 | + if (temp == NULL) { | |
529 | + bfd_perror(archive_filename); | |
530 | + exit(1); | |
531 | + } | |
532 | + if (newfile == false) { | |
533 | + if (bfd_check_format(temp, bfd_archive) != true) | |
534 | + fatal("File %s is not an archive.", archive_filename); | |
535 | + } | |
536 | + else { | |
537 | + fwrite(ARMAG, 1, SARMAG, ofile); | |
538 | + if (!silent_create) | |
539 | + fprintf(stderr, "%s: creating %s\n", program_name, archive_filename); | |
540 | + } | |
541 | + | |
542 | + /* assume it's an achive, go straight to the end, sans $200 */ | |
543 | + fseek(ofile, 0, 2); | |
544 | + | |
545 | + for (; files_to_append && *files_to_append; ++files_to_append) { | |
546 | + struct ar_hdr *hdr = bfd_special_undocumented_glue(*files_to_append); | |
547 | + if (hdr == NULL) { | |
548 | + bfd_perror(*files_to_append); | |
549 | + exit(1); | |
550 | + } | |
551 | + | |
552 | + BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr)); | |
553 | + | |
554 | + ifile = fopen(*files_to_append, "r"); | |
555 | + if (ifile == NULL) | |
556 | + bfd_perror(program_name); | |
557 | + | |
558 | + if (stat(*files_to_append, &sbuf) != 0) | |
559 | + bfd_perror(*files_to_append); | |
560 | + | |
561 | + tocopy = sbuf.st_size; | |
562 | + | |
563 | + /* XXX should do error-checking! */ | |
564 | + fwrite(hdr, 1, sizeof(struct ar_hdr), ofile); | |
565 | + | |
566 | + | |
567 | + while (tocopy > 0) { | |
568 | + thistime = tocopy; | |
569 | + if (thistime > BUFSIZE) | |
570 | + thistime = BUFSIZE; | |
571 | + fread(buf, 1, thistime, ifile); | |
572 | + fwrite(buf, 1, thistime, ofile); | |
573 | + tocopy -= thistime; | |
574 | + } | |
575 | + fclose(ifile); | |
576 | + if ((sbuf.st_size % 2) == 1) | |
577 | + putc('\n', ofile); | |
578 | + } | |
579 | + fclose(ofile); | |
580 | + bfd_close(temp); | |
581 | +} | |
582 | + | |
583 | + | |
584 | +void | |
585 | +write_archive() | |
586 | +{ | |
587 | + bfd *obfd; | |
588 | + char *xmalloc(); | |
589 | + int namelen = strlen(inarch->filename); | |
590 | + char *new_name = xmalloc(namelen + 6); | |
591 | + bfd *contents_head = inarch->next; | |
592 | + if (inarch == &bogus_archive) { | |
593 | + /* How can this be ? */ | |
594 | + return; | |
595 | + } | |
596 | + else { | |
597 | + | |
598 | + strcpy(new_name, inarch->filename); | |
599 | + strcpy(new_name + namelen, ".art"); | |
600 | + obfd = bfd_openw(new_name, bfd_get_target(inarch)); | |
601 | + | |
602 | + if (obfd == NULL) | |
603 | + bfd_fatal(inarch->filename); | |
604 | + | |
605 | + bfd_set_format(obfd, bfd_archive); | |
606 | + obfd->has_armap = write_armap; | |
607 | + | |
608 | + if (bfd_set_archive_head(obfd, contents_head) != true) | |
609 | + bfd_fatal(inarch->filename); | |
610 | + | |
611 | + if (!bfd_close(obfd)) | |
612 | + bfd_fatal(inarch->filename); | |
613 | + if (rename(new_name, inarch->filename) != 0) | |
614 | + bfd_fatal(inarch->filename); | |
615 | + } | |
616 | +} | |
617 | + | |
618 | + | |
619 | + | |
620 | +/* | |
621 | + returns a pointer to the pointer to the entry which should be rplacd'd | |
622 | + into when altering. default_pos should be how to interpret pos_default, | |
623 | + and should be a pos value. | |
624 | +*/ | |
625 | + | |
626 | +bfd ** | |
627 | +get_pos_bfd(contents, default_pos) | |
628 | + bfd **contents; | |
629 | + enum pos default_pos; | |
630 | +{ | |
631 | + bfd **after_bfd; | |
632 | + | |
633 | + enum pos realpos = (postype == pos_default ? default_pos : postype); | |
634 | + switch (realpos) { | |
635 | + | |
636 | + case pos_end: | |
637 | + after_bfd = contents; | |
638 | + while (*after_bfd) { | |
639 | + after_bfd = &((*after_bfd)->next); | |
640 | + } | |
641 | + | |
642 | + break; | |
643 | +#if 0 | |
644 | + case pos_after: | |
645 | + for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next) | |
646 | + if (!strcpy(after_bfd->filename, posname)) | |
647 | + break; | |
648 | + break; | |
649 | + case pos_before: | |
650 | + for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next) | |
651 | + if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname))) | |
652 | + break; | |
653 | +#endif | |
654 | + } | |
655 | + | |
656 | + return after_bfd; | |
657 | +} | |
658 | + | |
659 | + | |
660 | +void | |
661 | +delete_members(files_to_delete) | |
662 | + char **files_to_delete; | |
663 | +{ | |
664 | + bfd **current_ptr_ptr; | |
665 | + boolean found; | |
666 | + boolean something_changed = false; | |
667 | + for (; *files_to_delete != NULL; ++files_to_delete) { | |
668 | + /* | |
669 | + In a.out systems, the armap is optional. It's also called | |
670 | + __.SYMDEF. So if the user asked to delete it, we should remember | |
671 | + that fact. The name is NULL in COFF archives, so using this as a | |
672 | + key is as good as anything I suppose | |
673 | + */ | |
674 | + if (!strcmp(*files_to_delete, "__.SYMDEF")) { | |
675 | + inarch->has_armap = false; | |
676 | + write_armap = false; | |
677 | + continue; | |
678 | + } | |
679 | + | |
680 | + found = false; | |
681 | + current_ptr_ptr = &(inarch->next); | |
682 | + while (*current_ptr_ptr) { | |
683 | + if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) { | |
684 | + found = true; | |
685 | + something_changed = true; | |
686 | + if (verbose) | |
687 | + printf("d - %s\n", | |
688 | + *files_to_delete); | |
689 | + *current_ptr_ptr = ((*current_ptr_ptr)->next); | |
690 | + goto next_file; | |
691 | + | |
692 | + } | |
693 | + else { | |
694 | + current_ptr_ptr = &((*current_ptr_ptr)->next); | |
695 | + } | |
696 | + } | |
697 | + | |
698 | + if (verbose && found == false) { | |
699 | + printf("No member named `%s'\n", *files_to_delete); | |
700 | + } | |
701 | +next_file:; | |
702 | + | |
703 | + } | |
704 | + | |
705 | + if (something_changed == true) { | |
706 | + write_archive(); | |
707 | + } | |
708 | +} | |
709 | + | |
710 | + | |
711 | +/* Reposition existing members within an archive */ | |
712 | + | |
713 | +void | |
714 | +move_members(files_to_move) | |
715 | + char **files_to_move; | |
716 | +{ | |
717 | + bfd **after_bfd; /* New entries go after this one */ | |
718 | + bfd **current_ptr_ptr; /* cdr pointer into contents */ | |
719 | + | |
720 | + | |
721 | + | |
722 | + | |
723 | + for (; *files_to_move; ++files_to_move) { | |
724 | + current_ptr_ptr = &(inarch->next); | |
725 | + while (*current_ptr_ptr) { | |
726 | + bfd *current_ptr = *current_ptr_ptr; | |
727 | + if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) { | |
728 | + /* | |
729 | + Move this file to the end of the list - first cut from | |
730 | + where it is. | |
731 | + */ | |
732 | + *current_ptr_ptr = current_ptr->next; | |
733 | + | |
734 | + /* Now glue to end */ | |
735 | + after_bfd = get_pos_bfd(&inarch->next, pos_end); | |
736 | + *after_bfd = current_ptr; | |
737 | + current_ptr->next = (bfd *) NULL; | |
738 | + | |
739 | + if (verbose) | |
740 | + printf("m - %s\n", *files_to_move); | |
741 | + | |
742 | + goto next_file; | |
743 | + } | |
744 | + current_ptr_ptr = &((*current_ptr_ptr)->next); | |
745 | + } | |
746 | + fprintf(stderr, "No entry %s in archive %s!\n", | |
747 | + *files_to_move, inarch->filename); | |
748 | + exit(1); | |
749 | +next_file:; | |
750 | + } | |
751 | + | |
752 | + write_archive(); | |
753 | +} | |
754 | + | |
755 | + | |
756 | +/* Ought to default to replacing in place, but this is existing practice! */ | |
757 | + | |
758 | +void | |
759 | +replace_members(files_to_move) | |
760 | + char **files_to_move; | |
761 | +{ | |
762 | + bfd **after_bfd; /* New entries go after this one */ | |
763 | + bfd *current; | |
764 | + bfd **current_ptr; | |
765 | + bfd *temp; | |
766 | + /* | |
767 | + If the first item in the archive is an __.SYMDEF then remove it | |
768 | + */ | |
769 | + if (inarch->next && | |
770 | + strcmp(inarch->next->filename, "__.SYMDEF") == 0) { | |
771 | + inarch->next = inarch->next->next; | |
772 | + } | |
773 | + | |
774 | + | |
775 | + | |
776 | + while (files_to_move && *files_to_move) { | |
777 | + current_ptr = &inarch->next; | |
778 | + while (*current_ptr) { | |
779 | + current = *current_ptr; | |
780 | + | |
781 | + if (!strcmp(normalize(*files_to_move), current->filename)) { | |
782 | + /* snip out this entry from the chain */ | |
783 | + *current_ptr = current->next; | |
784 | + if (newer_only) { | |
785 | + struct stat fsbuf, | |
786 | + asbuf; | |
787 | + if (stat(*files_to_move, &fsbuf) != 0) { | |
788 | + if (errno != ENOENT) | |
789 | + bfd_fatal(*files_to_move); | |
790 | + goto next_file; | |
791 | + } | |
792 | + if (bfd_stat_arch_elt(current, &asbuf) != 0) | |
793 | + fatal("Internal stat error on %s", current->filename); | |
794 | + | |
795 | + if (fsbuf.st_mtime <= asbuf.st_mtime) | |
796 | + goto next_file; | |
797 | + } | |
798 | + | |
799 | + | |
800 | + after_bfd = get_pos_bfd(&inarch->next, pos_end); | |
801 | + temp = *after_bfd; | |
802 | + *after_bfd = bfd_openr(*files_to_move, NULL); | |
803 | + if (*after_bfd == (bfd *) NULL) { | |
804 | + fprintf(stderr, "Can't open file %s\n", *files_to_move); | |
805 | + exit(1); | |
806 | + } | |
807 | + (*after_bfd)->next = temp; | |
808 | + | |
809 | + if (verbose) { | |
810 | + printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'), | |
811 | + *files_to_move); | |
812 | + } | |
813 | + goto next_file; | |
814 | + } | |
815 | + current_ptr = &(current->next); | |
816 | + } | |
817 | + | |
818 | + /* It isn't in there, so add to end */ | |
819 | + | |
820 | + after_bfd = get_pos_bfd(&inarch->next, pos_end); | |
821 | + temp = *after_bfd; | |
822 | + *after_bfd = bfd_openr(*files_to_move, NULL); | |
823 | + if (*after_bfd == (bfd *) NULL) { | |
824 | + fprintf(stderr, "Can't open file %s\n", *files_to_move); | |
825 | + exit(1); | |
826 | + } | |
827 | + if (verbose) { | |
828 | + printf("c - %s\n", *files_to_move); | |
829 | + } | |
830 | + | |
831 | + (*after_bfd)->next = temp; | |
832 | + | |
833 | +next_file:; | |
834 | + | |
835 | + files_to_move++; | |
836 | + } | |
837 | + | |
838 | + | |
839 | + write_archive(); | |
840 | +} | |
841 | + | |
842 | +void | |
843 | +ranlib_only(archname) | |
844 | + char *archname; | |
845 | +{ | |
846 | + write_armap = true; | |
847 | + open_inarch(archname); | |
848 | + write_archive(); | |
849 | + exit(0); | |
850 | +} |
@@ -0,0 +1,151 @@ | ||
1 | +/*** bucomm.c -- Bin Utils COMmon code. | |
2 | + | |
3 | + We might put this in a library someday so it could be dynamically | |
4 | + loaded, but for now it's not necessary */ | |
5 | + | |
6 | +#include "sysdep.h" | |
7 | +#include "bfd.h" | |
8 | +#include <varargs.h> | |
9 | + | |
10 | +char *target = NULL; /* default as late as possible */ | |
11 | + | |
12 | +/* Yes, this is what atexit is for, but that isn't guaranteed yet. | |
13 | + And yes, I know this isn't as good, but it does what is needed just fine */ | |
14 | +void (*exit_handler) (); | |
15 | + | |
16 | +/** Memory hackery */ | |
17 | + | |
18 | +PROTO (char *, malloc, (unsigned size)); | |
19 | +PROTO (char *, realloc, (char *ptr, unsigned size)); | |
20 | + | |
21 | + | |
22 | +/* Error reporting */ | |
23 | + | |
24 | +char *program_name; | |
25 | + | |
26 | +void | |
27 | +bfd_fatal (string) | |
28 | + char *string; | |
29 | +{ | |
30 | + char *errmsg = bfd_errmsg (bfd_error); | |
31 | + | |
32 | + if (string) | |
33 | + fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); | |
34 | + else | |
35 | + fprintf (stderr, "%s: %s\n", program_name, errmsg); | |
36 | + | |
37 | + if (NULL != exit_handler) (*exit_handler) (); | |
38 | + exit (1); | |
39 | +} | |
40 | + | |
41 | +#ifndef NO_STDARG | |
42 | +void | |
43 | +fatal (Format) | |
44 | + const char *Format; | |
45 | +{ | |
46 | + va_list args; | |
47 | + | |
48 | + va_start (args, Format); | |
49 | + vfprintf (stderr, Format, args); | |
50 | + va_end (args); | |
51 | + (void) putc ('\n', stderr); | |
52 | + if (NULL != exit_handler) (*exit_handler) (); | |
53 | + exit (1); | |
54 | +} | |
55 | +#else | |
56 | +#ifndef NO_VARARGS | |
57 | +void fatal (va_alist) | |
58 | + va_dcl | |
59 | +{ | |
60 | + char *Format; | |
61 | + va_list args; | |
62 | + | |
63 | + va_start (args); | |
64 | + Format = va_arg(args, char *); | |
65 | + vfprintf (stderr, Format, args); | |
66 | + va_end (args); | |
67 | + (void) putc ('\n', stderr); | |
68 | + if (NULL != exit_handler) (*exit_handler) (); | |
69 | + exit (1); | |
70 | +} /* fatal() */ | |
71 | +#else | |
72 | +/*VARARGS1 */ | |
73 | +fatal (Format, args) | |
74 | + char *Format; | |
75 | +{ | |
76 | + as_where (); | |
77 | + _doprnt (Format, &args, stderr); /* not terribly portable, but... */ | |
78 | + (void) putc ('\n', stderr); | |
79 | + if (NULL != exit_handler) (*exit_handler) (); | |
80 | + exit (1); | |
81 | +} | |
82 | +#endif /* not NO_VARARGS */ | |
83 | +#endif /* not NO_STDARG */ | |
84 | + | |
85 | + | |
86 | +/** Display the archive header for an element as if it were an ls -l listing */ | |
87 | + | |
88 | +/* Mode User\tGroup\tSize\tDate Name */ | |
89 | + | |
90 | +void | |
91 | +print_arelt_descr (abfd, verbose) | |
92 | + bfd *abfd; | |
93 | + boolean verbose; | |
94 | +{ | |
95 | + struct stat buf; | |
96 | + char modebuf[11]; | |
97 | + char timebuf[40]; | |
98 | + long when; | |
99 | + long current_time = time ((long *) 0); | |
100 | + | |
101 | + if (verbose) { | |
102 | + | |
103 | + if (bfd_stat_arch_elt (abfd, &buf) == 0) { /* if not, huh? */ | |
104 | + | |
105 | + mode_string (buf.st_mode, modebuf); | |
106 | + modebuf[10] = '\0'; | |
107 | + fputs (modebuf, stdout); | |
108 | + | |
109 | + when = buf.st_mtime; | |
110 | + strcpy (timebuf, ctime (&when)); | |
111 | + | |
112 | + /* This code comes from gnu ls. */ | |
113 | + if ((current_time - when > 6 * 30 * 24 * 60 * 60) | |
114 | + || (current_time - when < 0)) { | |
115 | + /* The file is fairly old or in the future. | |
116 | + POSIX says the cutoff is 6 months old; | |
117 | + approximate this by 6*30 days. | |
118 | + Show the year instead of the time of day. */ | |
119 | + strcpy (timebuf + 11, timebuf + 19); | |
120 | + } | |
121 | + timebuf[16] = 0; | |
122 | + | |
123 | + printf (" %d\t%d\t%ld\t%s ", buf.st_uid, buf.st_gid, buf.st_size, timebuf); | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + puts (abfd->filename); | |
128 | +} | |
129 | + | |
130 | +/* Like malloc but get fatal error if memory is exhausted. */ | |
131 | +char * | |
132 | +xmalloc (size) | |
133 | + unsigned size; | |
134 | +{ | |
135 | + register char *result = malloc (size); | |
136 | + if (result == NULL && size != NULL) fatal ("virtual memory exhausted"); | |
137 | + | |
138 | + return result; | |
139 | +} | |
140 | + | |
141 | +/* Like realloc but get fatal error if memory is exhausted. */ | |
142 | +char * | |
143 | +xrealloc (ptr, size) | |
144 | + char *ptr; | |
145 | + unsigned size; | |
146 | +{ | |
147 | + register char *result = realloc (ptr, size); | |
148 | + if (result == 0 && size != 0) fatal ("virtual memory exhausted"); | |
149 | + | |
150 | + return result; | |
151 | +} |
@@ -0,0 +1,193 @@ | ||
1 | +/* filemode.c -- make a string describing file modes | |
2 | + Copyright (C) 1985, 1990 Free Software Foundation, Inc. | |
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 1, or (at your option) | |
7 | + 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 | |
15 | + along with this program; if not, write to the Free Software | |
16 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
17 | + | |
18 | +#include <sys/types.h> | |
19 | +#include <sys/stat.h> | |
20 | + | |
21 | +void mode_string (); | |
22 | +static char ftypelet (); | |
23 | +static void rwx (); | |
24 | +static void setst (); | |
25 | + | |
26 | +/* filemodestring - fill in string STR with an ls-style ASCII | |
27 | + representation of the st_mode field of file stats block STATP. | |
28 | + 10 characters are stored in STR; no terminating null is added. | |
29 | + The characters stored in STR are: | |
30 | + | |
31 | + 0 File type. 'd' for directory, 'c' for character | |
32 | + special, 'b' for block special, 'm' for multiplex, | |
33 | + 'l' for symbolic link, 's' for socket, 'p' for fifo, | |
34 | + '-' for any other file type | |
35 | + | |
36 | + 1 'r' if the owner may read, '-' otherwise. | |
37 | + | |
38 | + 2 'w' if the owner may write, '-' otherwise. | |
39 | + | |
40 | + 3 'x' if the owner may execute, 's' if the file is | |
41 | + set-user-id, '-' otherwise. | |
42 | + 'S' if the file is set-user-id, but the execute | |
43 | + bit isn't set. | |
44 | + | |
45 | + 4 'r' if group members may read, '-' otherwise. | |
46 | + | |
47 | + 5 'w' if group members may write, '-' otherwise. | |
48 | + | |
49 | + 6 'x' if group members may execute, 's' if the file is | |
50 | + set-group-id, '-' otherwise. | |
51 | + 'S' if it is set-group-id but not executable. | |
52 | + | |
53 | + 7 'r' if any user may read, '-' otherwise. | |
54 | + | |
55 | + 8 'w' if any user may write, '-' otherwise. | |
56 | + | |
57 | + 9 'x' if any user may execute, 't' if the file is "sticky" | |
58 | + (will be retained in swap space after execution), '-' | |
59 | + otherwise. | |
60 | + 'T' if the file is sticky but not executable. */ | |
61 | + | |
62 | +void | |
63 | +filemodestring (statp, str) | |
64 | + struct stat *statp; | |
65 | + char *str; | |
66 | +{ | |
67 | + mode_string (statp->st_mode, str); | |
68 | +} | |
69 | + | |
70 | +/* Like filemodestring, but only the relevant part of the `struct stat' | |
71 | + is given as an argument. */ | |
72 | + | |
73 | +void | |
74 | +mode_string (mode, str) | |
75 | + unsigned short mode; | |
76 | + char *str; | |
77 | +{ | |
78 | + str[0] = ftypelet (mode); | |
79 | + rwx ((mode & 0700) << 0, &str[1]); | |
80 | + rwx ((mode & 0070) << 3, &str[4]); | |
81 | + rwx ((mode & 0007) << 6, &str[7]); | |
82 | + setst (mode, str); | |
83 | +} | |
84 | + | |
85 | +/* Return a character indicating the type of file described by | |
86 | + file mode BITS: | |
87 | + 'd' for directories | |
88 | + 'b' for block special files | |
89 | + 'c' for character special files | |
90 | + 'm' for multiplexor files | |
91 | + 'l' for symbolic links | |
92 | + 's' for sockets | |
93 | + 'p' for fifos | |
94 | + '-' for any other file type. */ | |
95 | + | |
96 | +static char | |
97 | +ftypelet (bits) | |
98 | + unsigned short bits; | |
99 | +{ | |
100 | + switch (bits & S_IFMT) | |
101 | + { | |
102 | + default: | |
103 | + return '-'; | |
104 | + case S_IFDIR: | |
105 | + return 'd'; | |
106 | +#ifdef S_IFLNK | |
107 | + case S_IFLNK: | |
108 | + return 'l'; | |
109 | +#endif | |
110 | +#ifdef S_IFCHR | |
111 | + case S_IFCHR: | |
112 | + return 'c'; | |
113 | +#endif | |
114 | +#ifdef S_IFBLK | |
115 | + case S_IFBLK: | |
116 | + return 'b'; | |
117 | +#endif | |
118 | +#ifdef S_IFMPC | |
119 | + case S_IFMPC: | |
120 | + case S_IFMPB: | |
121 | + return 'm'; | |
122 | +#endif | |
123 | +#ifdef S_IFSOCK | |
124 | + case S_IFSOCK: | |
125 | + return 's'; | |
126 | +#endif | |
127 | +#ifdef S_IFIFO | |
128 | +#if S_IFIFO != S_IFSOCK | |
129 | + case S_IFIFO: | |
130 | + return 'p'; | |
131 | +#endif | |
132 | +#endif | |
133 | +#ifdef S_IFNWK /* HP-UX */ | |
134 | + case S_IFNWK: | |
135 | + return 'n'; | |
136 | +#endif | |
137 | + } | |
138 | +} | |
139 | + | |
140 | +/* Look at read, write, and execute bits in BITS and set | |
141 | + flags in CHARS accordingly. */ | |
142 | + | |
143 | +static void | |
144 | +rwx (bits, chars) | |
145 | + unsigned short bits; | |
146 | + char *chars; | |
147 | +{ | |
148 | + chars[0] = (bits & S_IREAD) ? 'r' : '-'; | |
149 | + chars[1] = (bits & S_IWRITE) ? 'w' : '-'; | |
150 | + chars[2] = (bits & S_IEXEC) ? 'x' : '-'; | |
151 | +} | |
152 | + | |
153 | +/* Set the 's' and 't' flags in file attributes string CHARS, | |
154 | + according to the file mode BITS. */ | |
155 | + | |
156 | +static void | |
157 | +setst (bits, chars) | |
158 | + unsigned short bits; | |
159 | + char *chars; | |
160 | +{ | |
161 | +#ifdef S_ISUID | |
162 | + if (bits & S_ISUID) | |
163 | + { | |
164 | + if (chars[3] != 'x') | |
165 | + /* Set-uid, but not executable by owner. */ | |
166 | + chars[3] = 'S'; | |
167 | + else | |
168 | + chars[3] = 's'; | |
169 | + } | |
170 | +#endif | |
171 | +#ifdef S_ISGID | |
172 | + if (bits & S_ISGID) | |
173 | + { | |
174 | + if (chars[6] != 'x') | |
175 | + /* Set-gid, but not executable by group. */ | |
176 | + chars[6] = 'S'; | |
177 | + else | |
178 | + chars[6] = 's'; | |
179 | + } | |
180 | +#endif | |
181 | +#ifdef S_ISVTX | |
182 | + if (bits & S_ISVTX) | |
183 | + { | |
184 | + if (chars[9] != 'x') | |
185 | + /* Sticky, but not executable by others. */ | |
186 | + chars[9] = 'T'; | |
187 | + else | |
188 | + chars[9] = 't'; | |
189 | + } | |
190 | +#endif | |
191 | +} | |
192 | + | |
193 | + |
@@ -0,0 +1,820 @@ | ||
1 | +/* Disassemble i80960 instructions. | |
2 | + */ | |
3 | + | |
4 | +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. | |
5 | + | |
6 | +This file is part of BFD, the Binary File Diddler. | |
7 | + | |
8 | +BFD is free software; you can redistribute it and/or modify | |
9 | +it under the terms of the GNU General Public License as published by | |
10 | +the Free Software Foundation; either version 1, or (at your option) | |
11 | +any later version. | |
12 | + | |
13 | +BFD is distributed in the hope that it will be useful, | |
14 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | +GNU General Public License for more details. | |
17 | + | |
18 | +You should have received a copy of the GNU General Public License | |
19 | +along with BFD; see the file COPYING. If not, write to | |
20 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
21 | + | |
22 | +/* $Id$ | |
23 | + $Log | |
24 | +*/ | |
25 | +#include <stdio.h> | |
26 | +#include "sysdep.h" | |
27 | +#include "bfd.h" | |
28 | + | |
29 | +extern char *xmalloc(); | |
30 | +extern int fputs(); | |
31 | + | |
32 | +static char *reg_names[] = { | |
33 | +/* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7", | |
34 | +/* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
35 | +/* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", | |
36 | +/* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp", | |
37 | +/* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3" | |
38 | +}; | |
39 | + | |
40 | + | |
41 | +static FILE *stream; /* Output goes here */ | |
42 | +static void print_addr(); | |
43 | +static void ctrl(); | |
44 | +static void cobr(); | |
45 | +static void reg(); | |
46 | +static int mem(); | |
47 | +static void ea(); | |
48 | +static void dstop(); | |
49 | +static void regop(); | |
50 | +static void invalid(); | |
51 | +static int pinsn(); | |
52 | +static void put_abs(); | |
53 | + | |
54 | + | |
55 | +/* Print the i960 instruction at address 'memaddr' in debugged memory, | |
56 | + * on stream 's'. Returns length of the instruction, in bytes. | |
57 | + */ | |
58 | +int | |
59 | +print_insn_i960( memaddr, buffer, s ) | |
60 | + bfd_vma memaddr; | |
61 | +uint8e_type *buffer; | |
62 | + FILE *s; | |
63 | +{ | |
64 | + unsigned int word1, word2; | |
65 | + | |
66 | + stream = s; | |
67 | + word1 =buffer [0] |( buffer[1]<< 8) | (buffer[2] << 16) | ( buffer[3] <<24); | |
68 | + word2 =buffer [4] |( buffer[5]<< 8) | (buffer[6] << 16) | ( buffer[7] <<24); | |
69 | + return pinsn( memaddr, word1, word2 ); | |
70 | +} | |
71 | + | |
72 | +#define IN_GDB | |
73 | + | |
74 | +/***************************************************************************** | |
75 | + * All code below this point should be identical with that of | |
76 | + * the disassembler in gdmp960. | |
77 | + *****************************************************************************/ | |
78 | + | |
79 | +struct tabent { | |
80 | + char *name; | |
81 | + char numops; | |
82 | +}; | |
83 | + | |
84 | +static int | |
85 | +pinsn( memaddr, word1, word2 ) | |
86 | + unsigned long memaddr; | |
87 | + unsigned long word1, word2; | |
88 | +{ | |
89 | + int instr_len; | |
90 | + | |
91 | + instr_len = 4; | |
92 | + put_abs( word1, word2 ); | |
93 | + | |
94 | + /* Divide instruction set into classes based on high 4 bits of opcode*/ | |
95 | + switch ( (word1 >> 28) & 0xf ){ | |
96 | + case 0x0: | |
97 | + case 0x1: | |
98 | + ctrl( memaddr, word1, word2 ); | |
99 | + break; | |
100 | + case 0x2: | |
101 | + case 0x3: | |
102 | + cobr( memaddr, word1, word2 ); | |
103 | + break; | |
104 | + case 0x5: | |
105 | + case 0x6: | |
106 | + case 0x7: | |
107 | + reg( word1 ); | |
108 | + break; | |
109 | + case 0x8: | |
110 | + case 0x9: | |
111 | + case 0xa: | |
112 | + case 0xb: | |
113 | + case 0xc: | |
114 | + instr_len = mem( memaddr, word1, word2, 0 ); | |
115 | + break; | |
116 | + default: | |
117 | + /* invalid instruction, print as data word */ | |
118 | + invalid( word1 ); | |
119 | + break; | |
120 | + } | |
121 | + return instr_len; | |
122 | +} | |
123 | + | |
124 | +/****************************************/ | |
125 | +/* CTRL format */ | |
126 | +/****************************************/ | |
127 | +static void | |
128 | +ctrl( memaddr, word1, word2 ) | |
129 | + unsigned long memaddr; | |
130 | + unsigned long word1, word2; | |
131 | +{ | |
132 | + int i; | |
133 | + static struct tabent ctrl_tab[] = { | |
134 | + NULL, 0, /* 0x00 */ | |
135 | + NULL, 0, /* 0x01 */ | |
136 | + NULL, 0, /* 0x02 */ | |
137 | + NULL, 0, /* 0x03 */ | |
138 | + NULL, 0, /* 0x04 */ | |
139 | + NULL, 0, /* 0x05 */ | |
140 | + NULL, 0, /* 0x06 */ | |
141 | + NULL, 0, /* 0x07 */ | |
142 | + "b", 1, /* 0x08 */ | |
143 | + "call", 1, /* 0x09 */ | |
144 | + "ret", 0, /* 0x0a */ | |
145 | + "bal", 1, /* 0x0b */ | |
146 | + NULL, 0, /* 0x0c */ | |
147 | + NULL, 0, /* 0x0d */ | |
148 | + NULL, 0, /* 0x0e */ | |
149 | + NULL, 0, /* 0x0f */ | |
150 | + "bno", 1, /* 0x10 */ | |
151 | + "bg", 1, /* 0x11 */ | |
152 | + "be", 1, /* 0x12 */ | |
153 | + "bge", 1, /* 0x13 */ | |
154 | + "bl", 1, /* 0x14 */ | |
155 | + "bne", 1, /* 0x15 */ | |
156 | + "ble", 1, /* 0x16 */ | |
157 | + "bo", 1, /* 0x17 */ | |
158 | + "faultno", 0, /* 0x18 */ | |
159 | + "faultg", 0, /* 0x19 */ | |
160 | + "faulte", 0, /* 0x1a */ | |
161 | + "faultge", 0, /* 0x1b */ | |
162 | + "faultl", 0, /* 0x1c */ | |
163 | + "faultne", 0, /* 0x1d */ | |
164 | + "faultle", 0, /* 0x1e */ | |
165 | + "faulto", 0, /* 0x1f */ | |
166 | + }; | |
167 | + | |
168 | + i = (word1 >> 24) & 0xff; | |
169 | + if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){ | |
170 | + invalid( word1 ); | |
171 | + return; | |
172 | + } | |
173 | + | |
174 | + fputs( ctrl_tab[i].name, stream ); | |
175 | + if ( word1 & 2 ){ /* Predicts branch not taken */ | |
176 | + fputs( ".f", stream ); | |
177 | + } | |
178 | + | |
179 | + if ( ctrl_tab[i].numops == 1 ){ | |
180 | + /* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */ | |
181 | + word1 &= 0x00ffffff; | |
182 | + if ( word1 & 0x00800000 ){ /* Sign bit is set */ | |
183 | + word1 |= (-1 & ~0xffffff); /* Sign extend */ | |
184 | + } | |
185 | + putc( '\t', stream ); | |
186 | + print_addr( word1 + memaddr ); | |
187 | + } | |
188 | +} | |
189 | + | |
190 | +/****************************************/ | |
191 | +/* COBR format */ | |
192 | +/****************************************/ | |
193 | +static void | |
194 | +cobr( memaddr, word1, word2 ) | |
195 | + unsigned long memaddr; | |
196 | + unsigned long word1, word2; | |
197 | +{ | |
198 | + int src1; | |
199 | + int src2; | |
200 | + int i; | |
201 | + | |
202 | + static struct tabent cobr_tab[] = { | |
203 | + "testno", 1, /* 0x20 */ | |
204 | + "testg", 1, /* 0x21 */ | |
205 | + "teste", 1, /* 0x22 */ | |
206 | + "testge", 1, /* 0x23 */ | |
207 | + "testl", 1, /* 0x24 */ | |
208 | + "testne", 1, /* 0x25 */ | |
209 | + "testle", 1, /* 0x26 */ | |
210 | + "testo", 1, /* 0x27 */ | |
211 | + NULL, 0, /* 0x28 */ | |
212 | + NULL, 0, /* 0x29 */ | |
213 | + NULL, 0, /* 0x2a */ | |
214 | + NULL, 0, /* 0x2b */ | |
215 | + NULL, 0, /* 0x2c */ | |
216 | + NULL, 0, /* 0x2d */ | |
217 | + NULL, 0, /* 0x2e */ | |
218 | + NULL, 0, /* 0x2f */ | |
219 | + "bbc", 3, /* 0x30 */ | |
220 | + "cmpobg", 3, /* 0x31 */ | |
221 | + "cmpobe", 3, /* 0x32 */ | |
222 | + "cmpobge", 3, /* 0x33 */ | |
223 | + "cmpobl", 3, /* 0x34 */ | |
224 | + "cmpobne", 3, /* 0x35 */ | |
225 | + "cmpoble", 3, /* 0x36 */ | |
226 | + "bbs", 3, /* 0x37 */ | |
227 | + "cmpibno", 3, /* 0x38 */ | |
228 | + "cmpibg", 3, /* 0x39 */ | |
229 | + "cmpibe", 3, /* 0x3a */ | |
230 | + "cmpibge", 3, /* 0x3b */ | |
231 | + "cmpibl", 3, /* 0x3c */ | |
232 | + "cmpibne", 3, /* 0x3d */ | |
233 | + "cmpible", 3, /* 0x3e */ | |
234 | + "cmpibo", 3, /* 0x3f */ | |
235 | + }; | |
236 | + | |
237 | + i = ((word1 >> 24) & 0xff) - 0x20; | |
238 | + if ( cobr_tab[i].name == NULL ){ | |
239 | + invalid( word1 ); | |
240 | + return; | |
241 | + } | |
242 | + | |
243 | + fputs( cobr_tab[i].name, stream ); | |
244 | + if ( word1 & 2 ){ /* Predicts branch not taken */ | |
245 | + fputs( ".f", stream ); | |
246 | + } | |
247 | + putc( '\t', stream ); | |
248 | + | |
249 | + src1 = (word1 >> 19) & 0x1f; | |
250 | + src2 = (word1 >> 14) & 0x1f; | |
251 | + | |
252 | + if ( word1 & 0x02000 ){ /* M1 is 1 */ | |
253 | + fprintf( stream, "%d", src1 ); | |
254 | + } else { /* M1 is 0 */ | |
255 | + fputs( reg_names[src1], stream ); | |
256 | + } | |
257 | + | |
258 | + if ( cobr_tab[i].numops > 1 ){ | |
259 | + if ( word1 & 1 ){ /* S2 is 1 */ | |
260 | + fprintf( stream, ",sf%d,", src2 ); | |
261 | + } else { /* S1 is 0 */ | |
262 | + fprintf( stream, ",%s,", reg_names[src2] ); | |
263 | + } | |
264 | + | |
265 | + /* Extract displacement and convert to address | |
266 | + */ | |
267 | + word1 &= 0x00001ffc; | |
268 | + if ( word1 & 0x00001000 ){ /* Negative displacement */ | |
269 | + word1 |= (-1 & ~0x1fff); /* Sign extend */ | |
270 | + } | |
271 | + print_addr( memaddr + word1 ); | |
272 | + } | |
273 | +} | |
274 | + | |
275 | +/****************************************/ | |
276 | +/* MEM format */ | |
277 | +/****************************************/ | |
278 | +static int /* returns instruction length: 4 or 8 */ | |
279 | +mem( memaddr, word1, word2, noprint ) | |
280 | + unsigned long memaddr; | |
281 | + unsigned long word1, word2; | |
282 | + int noprint; /* If TRUE, return instruction length, but | |
283 | + * don't output any text. | |
284 | + */ | |
285 | +{ | |
286 | + int i, j; | |
287 | + int len; | |
288 | + int mode; | |
289 | + int offset; | |
290 | + char *reg1, *reg2, *reg3; | |
291 | + | |
292 | + /* This lookup table is too sparse to make it worth typing in, but not | |
293 | + * so large as to make a sparse array necessary. We allocate the | |
294 | + * table at runtime, initialize all entries to empty, and copy the | |
295 | + * real ones in from an initialization table. | |
296 | + * | |
297 | + * NOTE: In this table, the meaning of 'numops' is: | |
298 | + * 1: single operand | |
299 | + * 2: 2 operands, load instruction | |
300 | + * -2: 2 operands, store instruction | |
301 | + */ | |
302 | + static struct tabent *mem_tab = NULL; | |
303 | + static struct { int opcode; char *name; char numops; } mem_init[] = { | |
304 | +#define MEM_MIN 0x80 | |
305 | + 0x80, "ldob", 2, | |
306 | + 0x82, "stob", -2, | |
307 | + 0x84, "bx", 1, | |
308 | + 0x85, "balx", 2, | |
309 | + 0x86, "callx", 1, | |
310 | + 0x88, "ldos", 2, | |
311 | + 0x8a, "stos", -2, | |
312 | + 0x8c, "lda", 2, | |
313 | + 0x90, "ld", 2, | |
314 | + 0x92, "st", -2, | |
315 | + 0x98, "ldl", 2, | |
316 | + 0x9a, "stl", -2, | |
317 | + 0xa0, "ldt", 2, | |
318 | + 0xa2, "stt", -2, | |
319 | + 0xb0, "ldq", 2, | |
320 | + 0xb2, "stq", -2, | |
321 | + 0xc0, "ldib", 2, | |
322 | + 0xc2, "stib", -2, | |
323 | + 0xc8, "ldis", 2, | |
324 | + 0xca, "stis", -2, | |
325 | +#define MEM_MAX 0xca | |
326 | +#define MEM_SIZ ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent)) | |
327 | + 0, NULL, 0 | |
328 | + }; | |
329 | + | |
330 | + if ( mem_tab == NULL ){ | |
331 | + mem_tab = (struct tabent *) xmalloc( MEM_SIZ ); | |
332 | + bzero( (void *) mem_tab, MEM_SIZ ); | |
333 | + for ( i = 0; mem_init[i].opcode != 0; i++ ){ | |
334 | + j = mem_init[i].opcode - MEM_MIN; | |
335 | + mem_tab[j].name = mem_init[i].name; | |
336 | + mem_tab[j].numops = mem_init[i].numops; | |
337 | + } | |
338 | + } | |
339 | + | |
340 | + i = ((word1 >> 24) & 0xff) - MEM_MIN; | |
341 | + mode = (word1 >> 10) & 0xf; | |
342 | + | |
343 | + if ( (mem_tab[i].name != NULL) /* Valid instruction */ | |
344 | + && ((mode == 5) || (mode >=12)) ){ /* With 32-bit displacement */ | |
345 | + len = 8; | |
346 | + } else { | |
347 | + len = 4; | |
348 | + } | |
349 | + | |
350 | + if ( noprint ){ | |
351 | + return len; | |
352 | + } | |
353 | + | |
354 | + if ( (mem_tab[i].name == NULL) || (mode == 6) ){ | |
355 | + invalid( word1 ); | |
356 | + return len; | |
357 | + } | |
358 | + | |
359 | + fprintf( stream, "%s\t", mem_tab[i].name ); | |
360 | + | |
361 | + reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */ | |
362 | + reg2 = reg_names[ (word1 >> 14) & 0x1f ]; | |
363 | + reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */ | |
364 | + offset = word1 & 0xfff; /* MEMA only */ | |
365 | + | |
366 | + switch ( mem_tab[i].numops ){ | |
367 | + | |
368 | + case 2: /* LOAD INSTRUCTION */ | |
369 | + if ( mode & 4 ){ /* MEMB FORMAT */ | |
370 | + ea( memaddr, mode, reg2, reg3, word1, word2 ); | |
371 | + fprintf( stream, ",%s", reg1 ); | |
372 | + } else { /* MEMA FORMAT */ | |
373 | + fprintf( stream, "0x%x", (unsigned) offset ); | |
374 | + if (mode & 8) { | |
375 | + fprintf( stream, "(%s)", reg2 ); | |
376 | + } | |
377 | + fprintf( stream, ",%s", reg1 ); | |
378 | + } | |
379 | + break; | |
380 | + | |
381 | + case -2: /* STORE INSTRUCTION */ | |
382 | + if ( mode & 4 ){ /* MEMB FORMAT */ | |
383 | + fprintf( stream, "%s,", reg1 ); | |
384 | + ea( memaddr, mode, reg2, reg3, word1, word2 ); | |
385 | + } else { /* MEMA FORMAT */ | |
386 | + fprintf( stream, "%s,0x%x", reg1, (unsigned) offset ); | |
387 | + if (mode & 8) { | |
388 | + fprintf( stream, "(%s)", reg2 ); | |
389 | + } | |
390 | + } | |
391 | + break; | |
392 | + | |
393 | + case 1: /* BX/CALLX INSTRUCTION */ | |
394 | + if ( mode & 4 ){ /* MEMB FORMAT */ | |
395 | + ea( memaddr, mode, reg2, reg3, word1, word2 ); | |
396 | + } else { /* MEMA FORMAT */ | |
397 | + fprintf( stream, "0x%x", (unsigned) offset ); | |
398 | + if (mode & 8) { | |
399 | + fprintf( stream, "(%s)", reg2 ); | |
400 | + } | |
401 | + } | |
402 | + break; | |
403 | + } | |
404 | + | |
405 | + return len; | |
406 | +} | |
407 | + | |
408 | +/****************************************/ | |
409 | +/* REG format */ | |
410 | +/****************************************/ | |
411 | +static void | |
412 | +reg( word1 ) | |
413 | + unsigned long word1; | |
414 | +{ | |
415 | + int i, j; | |
416 | + int opcode; | |
417 | + int fp; | |
418 | + int m1, m2, m3; | |
419 | + int s1, s2; | |
420 | + int src, src2, dst; | |
421 | + char *mnemp; | |
422 | + | |
423 | + /* This lookup table is too sparse to make it worth typing in, but not | |
424 | + * so large as to make a sparse array necessary. We allocate the | |
425 | + * table at runtime, initialize all entries to empty, and copy the | |
426 | + * real ones in from an initialization table. | |
427 | + * | |
428 | + * NOTE: In this table, the meaning of 'numops' is: | |
429 | + * 1: single operand, which is NOT a destination. | |
430 | + * -1: single operand, which IS a destination. | |
431 | + * 2: 2 operands, the 2nd of which is NOT a destination. | |
432 | + * -2: 2 operands, the 2nd of which IS a destination. | |
433 | + * 3: 3 operands | |
434 | + * | |
435 | + * If an opcode mnemonic begins with "F", it is a floating-point | |
436 | + * opcode (the "F" is not printed). | |
437 | + */ | |
438 | + | |
439 | + static struct tabent *reg_tab = NULL; | |
440 | + static struct { int opcode; char *name; char numops; } reg_init[] = { | |
441 | +#define REG_MIN 0x580 | |
442 | + 0x580, "notbit", 3, | |
443 | + 0x581, "and", 3, | |
444 | + 0x582, "andnot", 3, | |
445 | + 0x583, "setbit", 3, | |
446 | + 0x584, "notand", 3, | |
447 | + 0x586, "xor", 3, | |
448 | + 0x587, "or", 3, | |
449 | + 0x588, "nor", 3, | |
450 | + 0x589, "xnor", 3, | |
451 | + 0x58a, "not", -2, | |
452 | + 0x58b, "ornot", 3, | |
453 | + 0x58c, "clrbit", 3, | |
454 | + 0x58d, "notor", 3, | |
455 | + 0x58e, "nand", 3, | |
456 | + 0x58f, "alterbit", 3, | |
457 | + 0x590, "addo", 3, | |
458 | + 0x591, "addi", 3, | |
459 | + 0x592, "subo", 3, | |
460 | + 0x593, "subi", 3, | |
461 | + 0x598, "shro", 3, | |
462 | + 0x59a, "shrdi", 3, | |
463 | + 0x59b, "shri", 3, | |
464 | + 0x59c, "shlo", 3, | |
465 | + 0x59d, "rotate", 3, | |
466 | + 0x59e, "shli", 3, | |
467 | + 0x5a0, "cmpo", 2, | |
468 | + 0x5a1, "cmpi", 2, | |
469 | + 0x5a2, "concmpo", 2, | |
470 | + 0x5a3, "concmpi", 2, | |
471 | + 0x5a4, "cmpinco", 3, | |
472 | + 0x5a5, "cmpinci", 3, | |
473 | + 0x5a6, "cmpdeco", 3, | |
474 | + 0x5a7, "cmpdeci", 3, | |
475 | + 0x5ac, "scanbyte", 2, | |
476 | + 0x5ae, "chkbit", 2, | |
477 | + 0x5b0, "addc", 3, | |
478 | + 0x5b2, "subc", 3, | |
479 | + 0x5cc, "mov", -2, | |
480 | + 0x5d8, "eshro", 3, | |
481 | + 0x5dc, "movl", -2, | |
482 | + 0x5ec, "movt", -2, | |
483 | + 0x5fc, "movq", -2, | |
484 | + 0x600, "synmov", 2, | |
485 | + 0x601, "synmovl", 2, | |
486 | + 0x602, "synmovq", 2, | |
487 | + 0x603, "cmpstr", 3, | |
488 | + 0x604, "movqstr", 3, | |
489 | + 0x605, "movstr", 3, | |
490 | + 0x610, "atmod", 3, | |
491 | + 0x612, "atadd", 3, | |
492 | + 0x613, "inspacc", -2, | |
493 | + 0x614, "ldphy", -2, | |
494 | + 0x615, "synld", -2, | |
495 | + 0x617, "fill", 3, | |
496 | + 0x630, "sdma", 3, | |
497 | + 0x631, "udma", 0, | |
498 | + 0x640, "spanbit", -2, | |
499 | + 0x641, "scanbit", -2, | |
500 | + 0x642, "daddc", 3, | |
501 | + 0x643, "dsubc", 3, | |
502 | + 0x644, "dmovt", -2, | |
503 | + 0x645, "modac", 3, | |
504 | + 0x646, "condrec", -2, | |
505 | + 0x650, "modify", 3, | |
506 | + 0x651, "extract", 3, | |
507 | + 0x654, "modtc", 3, | |
508 | + 0x655, "modpc", 3, | |
509 | + 0x656, "receive", -2, | |
510 | + 0x659, "sysctl", 3, | |
511 | + 0x660, "calls", 1, | |
512 | + 0x662, "send", 3, | |
513 | + 0x663, "sendserv", 1, | |
514 | + 0x664, "resumprcs", 1, | |
515 | + 0x665, "schedprcs", 1, | |
516 | + 0x666, "saveprcs", 0, | |
517 | + 0x668, "condwait", 1, | |
518 | + 0x669, "wait", 1, | |
519 | + 0x66a, "signal", 1, | |
520 | + 0x66b, "mark", 0, | |
521 | + 0x66c, "fmark", 0, | |
522 | + 0x66d, "flushreg", 0, | |
523 | + 0x66f, "syncf", 0, | |
524 | + 0x670, "emul", 3, | |
525 | + 0x671, "ediv", 3, | |
526 | + 0x673, "ldtime", -1, | |
527 | + 0x674, "Fcvtir", -2, | |
528 | + 0x675, "Fcvtilr", -2, | |
529 | + 0x676, "Fscalerl", 3, | |
530 | + 0x677, "Fscaler", 3, | |
531 | + 0x680, "Fatanr", 3, | |
532 | + 0x681, "Flogepr", 3, | |
533 | + 0x682, "Flogr", 3, | |
534 | + 0x683, "Fremr", 3, | |
535 | + 0x684, "Fcmpor", 2, | |
536 | + 0x685, "Fcmpr", 2, | |
537 | + 0x688, "Fsqrtr", -2, | |
538 | + 0x689, "Fexpr", -2, | |
539 | + 0x68a, "Flogbnr", -2, | |
540 | + 0x68b, "Froundr", -2, | |
541 | + 0x68c, "Fsinr", -2, | |
542 | + 0x68d, "Fcosr", -2, | |
543 | + 0x68e, "Ftanr", -2, | |
544 | + 0x68f, "Fclassr", 1, | |
545 | + 0x690, "Fatanrl", 3, | |
546 | + 0x691, "Flogeprl", 3, | |
547 | + 0x692, "Flogrl", 3, | |
548 | + 0x693, "Fremrl", 3, | |
549 | + 0x694, "Fcmporl", 2, | |
550 | + 0x695, "Fcmprl", 2, | |
551 | + 0x698, "Fsqrtrl", -2, | |
552 | + 0x699, "Fexprl", -2, | |
553 | + 0x69a, "Flogbnrl", -2, | |
554 | + 0x69b, "Froundrl", -2, | |
555 | + 0x69c, "Fsinrl", -2, | |
556 | + 0x69d, "Fcosrl", -2, | |
557 | + 0x69e, "Ftanrl", -2, | |
558 | + 0x69f, "Fclassrl", 1, | |
559 | + 0x6c0, "Fcvtri", -2, | |
560 | + 0x6c1, "Fcvtril", -2, | |
561 | + 0x6c2, "Fcvtzri", -2, | |
562 | + 0x6c3, "Fcvtzril", -2, | |
563 | + 0x6c9, "Fmovr", -2, | |
564 | + 0x6d9, "Fmovrl", -2, | |
565 | + 0x6e1, "Fmovre", -2, | |
566 | + 0x6e2, "Fcpysre", 3, | |
567 | + 0x6e3, "Fcpyrsre", 3, | |
568 | + 0x701, "mulo", 3, | |
569 | + 0x708, "remo", 3, | |
570 | + 0x70b, "divo", 3, | |
571 | + 0x741, "muli", 3, | |
572 | + 0x748, "remi", 3, | |
573 | + 0x749, "modi", 3, | |
574 | + 0x74b, "divi", 3, | |
575 | + 0x78b, "Fdivr", 3, | |
576 | + 0x78c, "Fmulr", 3, | |
577 | + 0x78d, "Fsubr", 3, | |
578 | + 0x78f, "Faddr", 3, | |
579 | + 0x79b, "Fdivrl", 3, | |
580 | + 0x79c, "Fmulrl", 3, | |
581 | + 0x79d, "Fsubrl", 3, | |
582 | + 0x79f, "Faddrl", 3, | |
583 | +#define REG_MAX 0x79f | |
584 | +#define REG_SIZ ((REG_MAX-REG_MIN+1) * sizeof(struct tabent)) | |
585 | + 0, NULL, 0 | |
586 | + }; | |
587 | + | |
588 | + if ( reg_tab == NULL ){ | |
589 | + reg_tab = (struct tabent *) xmalloc( REG_SIZ ); | |
590 | + bzero( (void *) reg_tab, REG_SIZ ); | |
591 | + for ( i = 0; reg_init[i].opcode != 0; i++ ){ | |
592 | + j = reg_init[i].opcode - REG_MIN; | |
593 | + reg_tab[j].name = reg_init[i].name; | |
594 | + reg_tab[j].numops = reg_init[i].numops; | |
595 | + } | |
596 | + } | |
597 | + | |
598 | + opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf); | |
599 | + i = opcode - REG_MIN; | |
600 | + | |
601 | + if ( (opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL) ){ | |
602 | + invalid( word1 ); | |
603 | + return; | |
604 | + } | |
605 | + | |
606 | + mnemp = reg_tab[i].name; | |
607 | + if ( *mnemp == 'F' ){ | |
608 | + fp = 1; | |
609 | + mnemp++; | |
610 | + } else { | |
611 | + fp = 0; | |
612 | + } | |
613 | + | |
614 | + fputs( mnemp, stream ); | |
615 | + | |
616 | + s1 = (word1 >> 5) & 1; | |
617 | + s2 = (word1 >> 6) & 1; | |
618 | + m1 = (word1 >> 11) & 1; | |
619 | + m2 = (word1 >> 12) & 1; | |
620 | + m3 = (word1 >> 13) & 1; | |
621 | + src = word1 & 0x1f; | |
622 | + src2 = (word1 >> 14) & 0x1f; | |
623 | + dst = (word1 >> 19) & 0x1f; | |
624 | + | |
625 | + if ( reg_tab[i].numops != 0 ){ | |
626 | + putc( '\t', stream ); | |
627 | + | |
628 | + switch ( reg_tab[i].numops ){ | |
629 | + case 1: | |
630 | + regop( m1, s1, src, fp ); | |
631 | + break; | |
632 | + case -1: | |
633 | + dstop( m3, dst, fp ); | |
634 | + break; | |
635 | + case 2: | |
636 | + regop( m1, s1, src, fp ); | |
637 | + putc( ',', stream ); | |
638 | + regop( m2, s2, src2, fp ); | |
639 | + break; | |
640 | + case -2: | |
641 | + regop( m1, s1, src, fp ); | |
642 | + putc( ',', stream ); | |
643 | + dstop( m3, dst, fp ); | |
644 | + break; | |
645 | + case 3: | |
646 | + regop( m1, s1, src, fp ); | |
647 | + putc( ',', stream ); | |
648 | + regop( m2, s2, src2, fp ); | |
649 | + putc( ',', stream ); | |
650 | + dstop( m3, dst, fp ); | |
651 | + break; | |
652 | + } | |
653 | + } | |
654 | +} | |
655 | + | |
656 | + | |
657 | +/* | |
658 | + * Print out effective address for memb instructions. | |
659 | + */ | |
660 | +static void | |
661 | +ea( memaddr, mode, reg2, reg3, word1, word2 ) | |
662 | + unsigned long memaddr; | |
663 | + int mode; | |
664 | + char *reg2, *reg3; | |
665 | +int word1; | |
666 | + unsigned int word2; | |
667 | +{ | |
668 | + int scale; | |
669 | + static int scale_tab[] = { 1, 2, 4, 8, 16 }; | |
670 | + | |
671 | + scale = (word1 >> 7) & 0x07; | |
672 | + if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){ | |
673 | + invalid( word1 ); | |
674 | + return; | |
675 | + } | |
676 | + scale = scale_tab[scale]; | |
677 | + | |
678 | + switch (mode) { | |
679 | + case 4: /* (reg) */ | |
680 | + fprintf( stream, "(%s)", reg2 ); | |
681 | + break; | |
682 | + case 5: /* displ+8(ip) */ | |
683 | + print_addr( word2+8+memaddr ); | |
684 | + break; | |
685 | + case 7: /* (reg)[index*scale] */ | |
686 | + if (scale == 1) { | |
687 | + fprintf( stream, "(%s)[%s]", reg2, reg3 ); | |
688 | + } else { | |
689 | + fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale); | |
690 | + } | |
691 | + break; | |
692 | + case 12: /* displacement */ | |
693 | + print_addr( word2 ); | |
694 | + break; | |
695 | + case 13: /* displ(reg) */ | |
696 | + print_addr( word2 ); | |
697 | + fprintf( stream, "(%s)", reg2 ); | |
698 | + break; | |
699 | + case 14: /* displ[index*scale] */ | |
700 | + print_addr( word2 ); | |
701 | + if (scale == 1) { | |
702 | + fprintf( stream, "[%s]", reg3 ); | |
703 | + } else { | |
704 | + fprintf( stream, "[%s*%d]", reg3, scale ); | |
705 | + } | |
706 | + break; | |
707 | + case 15: /* displ(reg)[index*scale] */ | |
708 | + print_addr( word2 ); | |
709 | + if (scale == 1) { | |
710 | + fprintf( stream, "(%s)[%s]", reg2, reg3 ); | |
711 | + } else { | |
712 | + fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale ); | |
713 | + } | |
714 | + break; | |
715 | + default: | |
716 | + invalid( word1 ); | |
717 | + return; | |
718 | + } | |
719 | +} | |
720 | + | |
721 | + | |
722 | +/************************************************/ | |
723 | +/* Register Instruction Operand */ | |
724 | +/************************************************/ | |
725 | +static void | |
726 | +regop( mode, spec, reg, fp ) | |
727 | + int mode, spec, reg, fp; | |
728 | +{ | |
729 | + if ( fp ){ /* FLOATING POINT INSTRUCTION */ | |
730 | + if ( mode == 1 ){ /* FP operand */ | |
731 | + switch ( reg ){ | |
732 | + case 0: fputs( "fp0", stream ); break; | |
733 | + case 1: fputs( "fp1", stream ); break; | |
734 | + case 2: fputs( "fp2", stream ); break; | |
735 | + case 3: fputs( "fp3", stream ); break; | |
736 | + case 16: fputs( "0f0.0", stream ); break; | |
737 | + case 22: fputs( "0f1.0", stream ); break; | |
738 | + default: putc( '?', stream ); break; | |
739 | + } | |
740 | + } else { /* Non-FP register */ | |
741 | + fputs( reg_names[reg], stream ); | |
742 | + } | |
743 | + } else { /* NOT FLOATING POINT */ | |
744 | + if ( mode == 1 ){ /* Literal */ | |
745 | + fprintf( stream, "%d", reg ); | |
746 | + } else { /* Register */ | |
747 | + if ( spec == 0 ){ | |
748 | + fputs( reg_names[reg], stream ); | |
749 | + } else { | |
750 | + fprintf( stream, "sf%d", reg ); | |
751 | + } | |
752 | + } | |
753 | + } | |
754 | +} | |
755 | + | |
756 | +/************************************************/ | |
757 | +/* Register Instruction Destination Operand */ | |
758 | +/************************************************/ | |
759 | +static void | |
760 | +dstop( mode, reg, fp ) | |
761 | + int mode, reg, fp; | |
762 | +{ | |
763 | + /* 'dst' operand can't be a literal. On non-FP instructions, register | |
764 | + * mode is assumed and "m3" acts as if were "s3"; on FP-instructions, | |
765 | + * sf registers are not allowed so m3 acts normally. | |
766 | + */ | |
767 | + if ( fp ){ | |
768 | + regop( mode, 0, reg, fp ); | |
769 | + } else { | |
770 | + regop( 0, mode, reg, fp ); | |
771 | + } | |
772 | +} | |
773 | + | |
774 | + | |
775 | +static void | |
776 | +invalid( word1 ) | |
777 | + int word1; | |
778 | +{ | |
779 | + fprintf( stream, ".word\t0x%08x", (unsigned) word1 ); | |
780 | +} | |
781 | + | |
782 | +static void | |
783 | +print_addr(a) | |
784 | +int a; | |
785 | +{ | |
786 | + fprintf( stream, "0x%x", (unsigned) a ); | |
787 | +} | |
788 | + | |
789 | +static void | |
790 | +put_abs( word1, word2 ) | |
791 | + unsigned long word1, word2; | |
792 | +{ | |
793 | +#ifdef IN_GDB | |
794 | + return; | |
795 | +#else | |
796 | + int len; | |
797 | + | |
798 | + switch ( (word1 >> 28) & 0xf ){ | |
799 | + case 0x8: | |
800 | + case 0x9: | |
801 | + case 0xa: | |
802 | + case 0xb: | |
803 | + case 0xc: | |
804 | + /* MEM format instruction */ | |
805 | + len = mem( 0, word1, word2, 1 ); | |
806 | + break; | |
807 | + default: | |
808 | + len = 4; | |
809 | + break; | |
810 | + } | |
811 | + | |
812 | + if ( len == 8 ){ | |
813 | + fprintf( stream, "%08x %08x\t", word1, word2 ); | |
814 | + } else { | |
815 | + fprintf( stream, "%08x \t", word1 ); | |
816 | + } | |
817 | +; | |
818 | + | |
819 | +#endif | |
820 | +} |
@@ -0,0 +1,806 @@ | ||
1 | +/* Print m68k instructions for objdump | |
2 | + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. | |
3 | + | |
4 | + | |
5 | +This file is part of the binutils. | |
6 | + | |
7 | +The binutils are free software; you can redistribute it and/or modify | |
8 | +it under the terms of the GNU General Public License as published by | |
9 | +the Free Software Foundation; either version 1, or (at your option) | |
10 | +any later version. | |
11 | + | |
12 | +The binutils are distributed in the hope that they will be useful, | |
13 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | +GNU General Public License for more details. | |
16 | + | |
17 | +You should have received a copy of the GNU General Public License | |
18 | +along with the binutils; see the file COPYING. If not, write to | |
19 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +/* $Id$ | |
22 | + $Log$ | |
23 | + Revision 1.1 1991/03/21 21:26:45 gumby | |
24 | + Initial revision | |
25 | + | |
26 | + * Revision 1.1 1991/03/13 00:34:06 chrisb | |
27 | + * Initial revision | |
28 | + * | |
29 | + * Revision 1.4 1991/03/09 04:36:34 rich | |
30 | + * Modified Files: | |
31 | + * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c | |
32 | + * binutils.h | |
33 | + * | |
34 | + * Pulled sysdep.h out of bfd.h. | |
35 | + * | |
36 | + * Revision 1.3 1991/03/08 21:54:45 rich | |
37 | + * Modified Files: | |
38 | + * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c | |
39 | + * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h | |
40 | + * sparc-pinsn.c strip.c | |
41 | + * | |
42 | + * Verifying Portland tree with steve's last changes. Also, some partial | |
43 | + * porting. | |
44 | + * | |
45 | + * Revision 1.2 1991/03/08 07:46:24 sac | |
46 | + * Added -l option to disassembly - prints line numbers too. | |
47 | + * | |
48 | + * Revision 1.1 1991/02/22 16:48:02 sac | |
49 | + * Initial revision | |
50 | + * | |
51 | +*/ | |
52 | + | |
53 | +#include <stdio.h> | |
54 | +#include "sysdep.h" | |
55 | +#include "bfd.h" | |
56 | +#include "m68k-opcode.h" | |
57 | + | |
58 | +extern int fputs(); | |
59 | +extern void print_address(); | |
60 | + | |
61 | +/* 68k instructions are never longer than this many bytes. */ | |
62 | +#define MAXLEN 22 | |
63 | + | |
64 | +/* Number of elements in the opcode table. */ | |
65 | +#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) | |
66 | + | |
67 | +extern char *reg_names[]; | |
68 | +char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", | |
69 | + "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"}; | |
70 | + | |
71 | +char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"}; | |
72 | +static unsigned char *print_insn_arg (); | |
73 | +static unsigned char *print_indexed (); | |
74 | +static void print_base (); | |
75 | +static int fetch_arg (); | |
76 | + | |
77 | +#define NEXTBYTE(p) (p += 2, ((char *)p)[-1]) | |
78 | + | |
79 | +#define NEXTWORD(p) \ | |
80 | + (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) | |
81 | + | |
82 | +#define NEXTLONG(p) \ | |
83 | + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) | |
84 | + | |
85 | +#define NEXTSINGLE(p) \ | |
86 | + (p += 4, *((float *)(p - 4))) | |
87 | + | |
88 | +#define NEXTDOUBLE(p) \ | |
89 | + (p += 8, *((double *)(p - 8))) | |
90 | + | |
91 | +#define NEXTEXTEND(p) \ | |
92 | + (p += 12, 0.0) /* Need a function to convert from extended to double | |
93 | + precision... */ | |
94 | + | |
95 | +#define NEXTPACKED(p) \ | |
96 | + (p += 12, 0.0) /* Need a function to convert from packed to double | |
97 | + precision. Actually, it's easier to print a | |
98 | + packed number than a double anyway, so maybe | |
99 | + there should be a special case to handle this... */ | |
100 | + | |
101 | +/* Print the m68k instruction at address MEMADDR in debugged memory, | |
102 | + on STREAM. Returns length of the instruction, in bytes. */ | |
103 | + | |
104 | +int | |
105 | +print_insn_m68k(addr, buffer, stream) | |
106 | + bfd_vma addr; | |
107 | +unsigned char *buffer; | |
108 | + FILE *stream; | |
109 | +{ | |
110 | + register unsigned int i; | |
111 | + register unsigned char *p; | |
112 | + register char *d; | |
113 | + register unsigned int bestmask; | |
114 | + int best; | |
115 | + | |
116 | + | |
117 | + | |
118 | + bestmask = 0; | |
119 | + best = -1; | |
120 | + for (i = 0; i < NOPCODES; i++) | |
121 | + { | |
122 | + register unsigned int opcode = m68k_opcodes[i].opcode; | |
123 | + register unsigned int match = m68k_opcodes[i].match; | |
124 | + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) | |
125 | + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) | |
126 | + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) | |
127 | + && ((0xff & buffer[3] & match) == (0xff & opcode))) | |
128 | + { | |
129 | + /* Don't use for printout the variants of divul and divsl | |
130 | + that have the same register number in two places. | |
131 | + The more general variants will match instead. */ | |
132 | + for (d = m68k_opcodes[i].args; *d; d += 2) | |
133 | + if (d[1] == 'D') | |
134 | + break; | |
135 | + | |
136 | + /* Don't use for printout the variants of most floating | |
137 | + point coprocessor instructions which use the same | |
138 | + register number in two places, as above. */ | |
139 | + if (*d == 0) | |
140 | + for (d = m68k_opcodes[i].args; *d; d += 2) | |
141 | + if (d[1] == 't') | |
142 | + break; | |
143 | + | |
144 | + if (*d == 0 && match > bestmask) | |
145 | + { | |
146 | + best = i; | |
147 | + bestmask = match; | |
148 | + } | |
149 | + } | |
150 | + } | |
151 | + | |
152 | + /* Handle undefined instructions. */ | |
153 | + if (best < 0) | |
154 | + { | |
155 | + fprintf (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]); | |
156 | + return 2; | |
157 | + } | |
158 | + | |
159 | + fprintf (stream, "%s", m68k_opcodes[best].name); | |
160 | + | |
161 | + /* Point at first word of argument data, | |
162 | + and at descriptor for first argument. */ | |
163 | + p = buffer + 2; | |
164 | + | |
165 | + /* Why do this this way? -MelloN */ | |
166 | + for (d = m68k_opcodes[best].args; *d; d += 2) | |
167 | + { | |
168 | + if (d[0] == '#') | |
169 | + { | |
170 | + if (d[1] == 'l' && p - buffer < 6) | |
171 | + p = buffer + 6; | |
172 | + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) | |
173 | + p = buffer + 4; | |
174 | + } | |
175 | + if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) | |
176 | + p = buffer + 4; | |
177 | + if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) | |
178 | + p = buffer + 6; | |
179 | + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) | |
180 | + p = buffer + 4; | |
181 | + } | |
182 | + | |
183 | + d = m68k_opcodes[best].args; | |
184 | + | |
185 | + if (*d) | |
186 | + fputs (" ", stream); | |
187 | + | |
188 | + while (*d) | |
189 | + { | |
190 | + p = print_insn_arg (d, buffer, p, addr + p - buffer, stream); | |
191 | + d += 2; | |
192 | + if (*d && *(d - 2) != 'I' && *d != 'k') | |
193 | + fputs (",", stream); | |
194 | + } | |
195 | + return p - buffer; | |
196 | +} | |
197 | + | |
198 | +static unsigned char * | |
199 | +print_insn_arg (d, buffer, p, addr, stream) | |
200 | + char *d; | |
201 | + unsigned char *buffer; | |
202 | + register unsigned char *p; | |
203 | + bfd_vma addr; /* PC for this arg to be relative to */ | |
204 | + FILE *stream; | |
205 | +{ | |
206 | + register int val; | |
207 | + register int place = d[1]; | |
208 | + int regno; | |
209 | + register char *regname; | |
210 | + register unsigned char *p1; | |
211 | + register double flval; | |
212 | + int flt_p; | |
213 | + | |
214 | + switch (*d) | |
215 | + { | |
216 | + case 'C': | |
217 | + fprintf (stream, "ccr"); | |
218 | + break; | |
219 | + | |
220 | + case 'S': | |
221 | + fprintf (stream, "sr"); | |
222 | + break; | |
223 | + | |
224 | + case 'U': | |
225 | + fprintf (stream, "usp"); | |
226 | + break; | |
227 | + | |
228 | + case 'J': | |
229 | + { | |
230 | + static struct { char *name; int value; } names[] | |
231 | + = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, | |
232 | + {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, | |
233 | + {"msp", 0x803}, {"isp", 0x804}}; | |
234 | + | |
235 | + val = fetch_arg (buffer, place, 12); | |
236 | + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) | |
237 | + if (names[regno].value == val) | |
238 | + { | |
239 | + fprintf (stream, names[regno].name); | |
240 | + break; | |
241 | + } | |
242 | + if (regno < 0) | |
243 | + fprintf (stream, "%d", val); | |
244 | + } | |
245 | + break; | |
246 | + | |
247 | + case 'Q': | |
248 | + val = fetch_arg (buffer, place, 3); | |
249 | + if (val == 0) val = 8; | |
250 | + fprintf (stream, "#%d", val); | |
251 | + break; | |
252 | + | |
253 | + case 'M': | |
254 | + val = fetch_arg (buffer, place, 8); | |
255 | + if (val & 0x80) | |
256 | + val = val - 0x100; | |
257 | + fprintf (stream, "#%d", val); | |
258 | + break; | |
259 | + | |
260 | + case 'T': | |
261 | + val = fetch_arg (buffer, place, 4); | |
262 | + fprintf (stream, "#%d", val); | |
263 | + break; | |
264 | + | |
265 | + case 'D': | |
266 | + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); | |
267 | + break; | |
268 | + | |
269 | + case 'A': | |
270 | + fprintf (stream, "%s", | |
271 | + reg_names[fetch_arg (buffer, place, 3) + 010]); | |
272 | + break; | |
273 | + | |
274 | + case 'R': | |
275 | + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); | |
276 | + break; | |
277 | + | |
278 | + case 'F': | |
279 | + fprintf (stream, "fp%d", fetch_arg (buffer, place, 3)); | |
280 | + break; | |
281 | + | |
282 | + case 'O': | |
283 | + val = fetch_arg (buffer, place, 6); | |
284 | + if (val & 0x20) | |
285 | + fprintf (stream, "%s", reg_names [val & 7]); | |
286 | + else | |
287 | + fprintf (stream, "%d", val); | |
288 | + break; | |
289 | + | |
290 | + case '+': | |
291 | + fprintf (stream, "%s@+", | |
292 | + reg_names[fetch_arg (buffer, place, 3) + 8]); | |
293 | + break; | |
294 | + | |
295 | + case '-': | |
296 | + fprintf (stream, "%s@-", | |
297 | + reg_names[fetch_arg (buffer, place, 3) + 8]); | |
298 | + break; | |
299 | + | |
300 | + case 'k': | |
301 | + if (place == 'k') | |
302 | + fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); | |
303 | + else if (place == 'C') | |
304 | + { | |
305 | + val = fetch_arg (buffer, place, 7); | |
306 | + if ( val > 63 ) /* This is a signed constant. */ | |
307 | + val -= 128; | |
308 | + fprintf (stream, "{#%d}", val); | |
309 | + } | |
310 | + else | |
311 | + fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".", | |
312 | + *d, place); | |
313 | + break; | |
314 | + | |
315 | + case '#': | |
316 | + case '^': | |
317 | + p1 = buffer + (*d == '#' ? 2 : 4); | |
318 | + if (place == 's') | |
319 | + val = fetch_arg (buffer, place, 4); | |
320 | + else if (place == 'C') | |
321 | + val = fetch_arg (buffer, place, 7); | |
322 | + else if (place == '8') | |
323 | + val = fetch_arg (buffer, place, 3); | |
324 | + else if (place == '3') | |
325 | + val = fetch_arg (buffer, place, 8); | |
326 | + else if (place == 'b') | |
327 | + val = NEXTBYTE (p1); | |
328 | + else if (place == 'w') | |
329 | + val = NEXTWORD (p1); | |
330 | + else if (place == 'l') | |
331 | + val = NEXTLONG (p1); | |
332 | + else | |
333 | + fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".", | |
334 | + *d, place); | |
335 | + fprintf (stream, "#%d", val); | |
336 | + break; | |
337 | + | |
338 | + case 'B': | |
339 | + if (place == 'b') | |
340 | + val = NEXTBYTE (p); | |
341 | + else if (place == 'w') | |
342 | + val = NEXTWORD (p); | |
343 | + else if (place == 'l') | |
344 | + val = NEXTLONG (p); | |
345 | + else if (place == 'g') | |
346 | + { | |
347 | + val = ((char *)buffer)[1]; | |
348 | + if (val == 0) | |
349 | + val = NEXTWORD (p); | |
350 | + else if (val == -1) | |
351 | + val = NEXTLONG (p); | |
352 | + } | |
353 | + else if (place == 'c') | |
354 | + { | |
355 | + if (buffer[1] & 0x40) /* If bit six is one, long offset */ | |
356 | + val = NEXTLONG (p); | |
357 | + else | |
358 | + val = NEXTWORD (p); | |
359 | + } | |
360 | + else | |
361 | + fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".", | |
362 | + *d, place); | |
363 | + print_address (addr + val, stream); | |
364 | + break; | |
365 | + | |
366 | + case 'd': | |
367 | + val = NEXTWORD (p); | |
368 | + fprintf (stream, "%s@(%d)", | |
369 | + reg_names[fetch_arg (buffer, place, 3)], val); | |
370 | + break; | |
371 | + | |
372 | + case 's': | |
373 | + fprintf (stream, "%s", | |
374 | + fpcr_names[fetch_arg (buffer, place, 3)]); | |
375 | + break; | |
376 | + | |
377 | + case 'I': | |
378 | + val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ | |
379 | + if (val != 1) /* Unusual coprocessor ID? */ | |
380 | + fprintf (stream, "(cpid=%d) ", val); | |
381 | + if (place == 'i') | |
382 | + p += 2; /* Skip coprocessor extended operands */ | |
383 | + break; | |
384 | + | |
385 | + case '*': | |
386 | + case '~': | |
387 | + case '%': | |
388 | + case ';': | |
389 | + case '@': | |
390 | + case '!': | |
391 | + case '$': | |
392 | + case '?': | |
393 | + case '/': | |
394 | + case '&': | |
395 | + | |
396 | + if (place == 'd') | |
397 | + { | |
398 | + val = fetch_arg (buffer, 'x', 6); | |
399 | + val = ((val & 7) << 3) + ((val >> 3) & 7); | |
400 | + } | |
401 | + else | |
402 | + val = fetch_arg (buffer, 's', 6); | |
403 | + | |
404 | + /* Get register number assuming address register. */ | |
405 | + regno = (val & 7) + 8; | |
406 | + regname = reg_names[regno]; | |
407 | + switch (val >> 3) | |
408 | + { | |
409 | + case 0: | |
410 | + fprintf (stream, "%s", reg_names[val]); | |
411 | + break; | |
412 | + | |
413 | + case 1: | |
414 | + fprintf (stream, "%s", regname); | |
415 | + break; | |
416 | + | |
417 | + case 2: | |
418 | + fprintf (stream, "%s@", regname); | |
419 | + break; | |
420 | + | |
421 | + case 3: | |
422 | + fprintf (stream, "%s@+", regname); | |
423 | + break; | |
424 | + | |
425 | + case 4: | |
426 | + fprintf (stream, "%s@-", regname); | |
427 | + break; | |
428 | + | |
429 | + case 5: | |
430 | + val = NEXTWORD (p); | |
431 | + fprintf (stream, "%s@(%d)", regname, val); | |
432 | + break; | |
433 | + | |
434 | + case 6: | |
435 | + p = print_indexed (regno, p, addr, stream); | |
436 | + break; | |
437 | + | |
438 | + case 7: | |
439 | + switch (val & 7) | |
440 | + { | |
441 | + case 0: | |
442 | + val = NEXTWORD (p); | |
443 | + fprintf (stream, "@#"); | |
444 | + print_address (val, stream); | |
445 | + break; | |
446 | + | |
447 | + case 1: | |
448 | + val = NEXTLONG (p); | |
449 | + fprintf (stream, "@#"); | |
450 | + print_address (val, stream); | |
451 | + break; | |
452 | + | |
453 | + case 2: | |
454 | + val = NEXTWORD (p); | |
455 | + print_address (addr + val, stream); | |
456 | + break; | |
457 | + | |
458 | + case 3: | |
459 | + p = print_indexed (-1, p, addr, stream); | |
460 | + break; | |
461 | + | |
462 | + case 4: | |
463 | + flt_p = 1; /* Assume it's a float... */ | |
464 | + switch( place ) | |
465 | + { | |
466 | + case 'b': | |
467 | + val = NEXTBYTE (p); | |
468 | + flt_p = 0; | |
469 | + break; | |
470 | + | |
471 | + case 'w': | |
472 | + val = NEXTWORD (p); | |
473 | + flt_p = 0; | |
474 | + break; | |
475 | + | |
476 | + case 'l': | |
477 | + val = NEXTLONG (p); | |
478 | + flt_p = 0; | |
479 | + break; | |
480 | + | |
481 | + case 'f': | |
482 | + flval = NEXTSINGLE(p); | |
483 | + break; | |
484 | + | |
485 | + case 'F': | |
486 | + flval = NEXTDOUBLE(p); | |
487 | + break; | |
488 | + | |
489 | + case 'x': | |
490 | + flval = NEXTEXTEND(p); | |
491 | + break; | |
492 | + | |
493 | + case 'p': | |
494 | + flval = NEXTPACKED(p); | |
495 | + break; | |
496 | + | |
497 | + default: | |
498 | + fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".", | |
499 | + *d, place); | |
500 | + } | |
501 | + if ( flt_p ) /* Print a float? */ | |
502 | + fprintf (stream, "#%g", flval); | |
503 | + else | |
504 | + fprintf (stream, "#%d", val); | |
505 | + break; | |
506 | + | |
507 | + default: | |
508 | + fprintf (stream, "<invalid address mode 0%o>", (unsigned) val); | |
509 | + } | |
510 | + } | |
511 | + break; | |
512 | + | |
513 | + case 'L': | |
514 | + case 'l': | |
515 | + if (place == 'w') | |
516 | + { | |
517 | + char doneany; | |
518 | + p1 = buffer + 2; | |
519 | + val = NEXTWORD (p1); | |
520 | + /* Move the pointer ahead if this point is farther ahead | |
521 | + than the last. */ | |
522 | + p = p1 > p ? p1 : p; | |
523 | + if (val == 0) | |
524 | + { | |
525 | + fputs ("#0", stream); | |
526 | + break; | |
527 | + } | |
528 | + if (*d == 'l') | |
529 | + { | |
530 | + register int newval = 0; | |
531 | + for (regno = 0; regno < 16; ++regno) | |
532 | + if (val & (0x8000 >> regno)) | |
533 | + newval |= 1 << regno; | |
534 | + val = newval; | |
535 | + } | |
536 | + val &= 0xffff; | |
537 | + doneany = 0; | |
538 | + for (regno = 0; regno < 16; ++regno) | |
539 | + if (val & (1 << regno)) | |
540 | + { | |
541 | + int first_regno; | |
542 | + if (doneany) | |
543 | + fputs ("/", stream); | |
544 | + doneany = 1; | |
545 | + fprintf (stream, "%s", reg_names[regno]); | |
546 | + first_regno = regno; | |
547 | + while (val & (1 << (regno + 1))) | |
548 | + ++regno; | |
549 | + if (regno > first_regno) | |
550 | + fprintf (stream, "-%s", reg_names[regno]); | |
551 | + } | |
552 | + } | |
553 | + else if (place == '3') | |
554 | + { | |
555 | + /* `fmovem' insn. */ | |
556 | + char doneany; | |
557 | + val = fetch_arg (buffer, place, 8); | |
558 | + if (val == 0) | |
559 | + { | |
560 | + fputs ("#0", stream); | |
561 | + break; | |
562 | + } | |
563 | + if (*d == 'l') | |
564 | + { | |
565 | + register int newval = 0; | |
566 | + for (regno = 0; regno < 8; ++regno) | |
567 | + if (val & (0x80 >> regno)) | |
568 | + newval |= 1 << regno; | |
569 | + val = newval; | |
570 | + } | |
571 | + val &= 0xff; | |
572 | + doneany = 0; | |
573 | + for (regno = 0; regno < 8; ++regno) | |
574 | + if (val & (1 << regno)) | |
575 | + { | |
576 | + int first_regno; | |
577 | + if (doneany) | |
578 | + fputs ("/", stream); | |
579 | + doneany = 1; | |
580 | + fprintf (stream, "fp%d", regno); | |
581 | + first_regno = regno; | |
582 | + while (val & (1 << (regno + 1))) | |
583 | + ++regno; | |
584 | + if (regno > first_regno) | |
585 | + fprintf (stream, "-fp%d", regno); | |
586 | + } | |
587 | + } | |
588 | + else | |
589 | + abort (); | |
590 | + break; | |
591 | + | |
592 | + default: | |
593 | + fprintf(stderr, "Invalid arg format in opcode table: \"%c\".", *d); | |
594 | + } | |
595 | + | |
596 | + return (unsigned char *) p; | |
597 | +} | |
598 | + | |
599 | +/* Fetch BITS bits from a position in the instruction specified by CODE. | |
600 | + CODE is a "place to put an argument", or 'x' for a destination | |
601 | + that is a general address (mode and register). | |
602 | + BUFFER contains the instruction. */ | |
603 | + | |
604 | +static int | |
605 | +fetch_arg (buffer, code, bits) | |
606 | + unsigned char *buffer; | |
607 | + char code; | |
608 | + int bits; | |
609 | +{ | |
610 | + register int val; | |
611 | + switch (code) | |
612 | + { | |
613 | + case 's': | |
614 | + val = buffer[1]; | |
615 | + break; | |
616 | + | |
617 | + case 'd': /* Destination, for register or quick. */ | |
618 | + val = (buffer[0] << 8) + buffer[1]; | |
619 | + val >>= 9; | |
620 | + break; | |
621 | + | |
622 | + case 'x': /* Destination, for general arg */ | |
623 | + val = (buffer[0] << 8) + buffer[1]; | |
624 | + val >>= 6; | |
625 | + break; | |
626 | + | |
627 | + case 'k': | |
628 | + val = (buffer[3] >> 4); | |
629 | + break; | |
630 | + | |
631 | + case 'C': | |
632 | + val = buffer[3]; | |
633 | + break; | |
634 | + | |
635 | + case '1': | |
636 | + val = (buffer[2] << 8) + buffer[3]; | |
637 | + val >>= 12; | |
638 | + break; | |
639 | + | |
640 | + case '2': | |
641 | + val = (buffer[2] << 8) + buffer[3]; | |
642 | + val >>= 6; | |
643 | + break; | |
644 | + | |
645 | + case '3': | |
646 | + case 'j': | |
647 | + val = (buffer[2] << 8) + buffer[3]; | |
648 | + break; | |
649 | + | |
650 | + case '4': | |
651 | + val = (buffer[4] << 8) + buffer[5]; | |
652 | + val >>= 12; | |
653 | + break; | |
654 | + | |
655 | + case '5': | |
656 | + val = (buffer[4] << 8) + buffer[5]; | |
657 | + val >>= 6; | |
658 | + break; | |
659 | + | |
660 | + case '6': | |
661 | + val = (buffer[4] << 8) + buffer[5]; | |
662 | + break; | |
663 | + | |
664 | + case '7': | |
665 | + val = (buffer[2] << 8) + buffer[3]; | |
666 | + val >>= 7; | |
667 | + break; | |
668 | + | |
669 | + case '8': | |
670 | + val = (buffer[2] << 8) + buffer[3]; | |
671 | + val >>= 10; | |
672 | + break; | |
673 | + | |
674 | + default: | |
675 | + abort (); | |
676 | + } | |
677 | + | |
678 | + switch (bits) | |
679 | + { | |
680 | + case 3: | |
681 | + return val & 7; | |
682 | + case 4: | |
683 | + return val & 017; | |
684 | + case 5: | |
685 | + return val & 037; | |
686 | + case 6: | |
687 | + return val & 077; | |
688 | + case 7: | |
689 | + return val & 0177; | |
690 | + case 8: | |
691 | + return val & 0377; | |
692 | + case 12: | |
693 | + return val & 07777; | |
694 | + default: | |
695 | + abort (); | |
696 | + return(0); | |
697 | + } | |
698 | +} /* fetch_arg() */ | |
699 | + | |
700 | +/* Print an indexed argument. The base register is BASEREG (-1 for pc). | |
701 | + P points to extension word, in buffer. | |
702 | + ADDR is the nominal core address of that extension word. */ | |
703 | + | |
704 | +static unsigned char * | |
705 | +print_indexed (basereg, p, addr, stream) | |
706 | + int basereg; | |
707 | + unsigned char *p; | |
708 | + FILE *stream; | |
709 | +bfd_vma addr; | |
710 | +{ | |
711 | + register int word; | |
712 | + static char *scales[] = {"", "*2", "*4", "*8"}; | |
713 | + register int base_disp; | |
714 | + register int outer_disp; | |
715 | + char buf[40]; | |
716 | + | |
717 | + word = NEXTWORD (p); | |
718 | + | |
719 | + /* Generate the text for the index register. | |
720 | + Where this will be output is not yet determined. */ | |
721 | + sprintf (buf, "[%s.%c%s]", | |
722 | + reg_names[(word >> 12) & 0xf], | |
723 | + (word & 0x800) ? 'l' : 'w', | |
724 | + scales[(word >> 9) & 3]); | |
725 | + | |
726 | + /* Handle the 68000 style of indexing. */ | |
727 | + | |
728 | + if ((word & 0x100) == 0) | |
729 | + { | |
730 | + print_base (basereg, | |
731 | + ((word & 0x80) ? word | 0xff00 : word & 0xff) | |
732 | + + ((basereg == -1) ? addr : 0), | |
733 | + stream); | |
734 | + fputs (buf, stream); | |
735 | + return p; | |
736 | + } | |
737 | + | |
738 | + /* Handle the generalized kind. */ | |
739 | + /* First, compute the displacement to add to the base register. */ | |
740 | + | |
741 | + if (word & 0200) | |
742 | + basereg = -2; | |
743 | + if (word & 0100) | |
744 | + buf[0] = 0; | |
745 | + base_disp = 0; | |
746 | + switch ((word >> 4) & 3) | |
747 | + { | |
748 | + case 2: | |
749 | + base_disp = NEXTWORD (p); | |
750 | + break; | |
751 | + case 3: | |
752 | + base_disp = NEXTLONG (p); | |
753 | + } | |
754 | + if (basereg == -1) | |
755 | + base_disp += addr; | |
756 | + | |
757 | + /* Handle single-level case (not indirect) */ | |
758 | + | |
759 | + if ((word & 7) == 0) | |
760 | + { | |
761 | + print_base (basereg, base_disp, stream); | |
762 | + fputs (buf, stream); | |
763 | + return p; | |
764 | + } | |
765 | + | |
766 | + /* Two level. Compute displacement to add after indirection. */ | |
767 | + | |
768 | + outer_disp = 0; | |
769 | + switch (word & 3) | |
770 | + { | |
771 | + case 2: | |
772 | + outer_disp = NEXTWORD (p); | |
773 | + break; | |
774 | + case 3: | |
775 | + outer_disp = NEXTLONG (p); | |
776 | + } | |
777 | + | |
778 | + fprintf (stream, "%d(", outer_disp); | |
779 | + print_base (basereg, base_disp, stream); | |
780 | + | |
781 | + /* If postindexed, print the closeparen before the index. */ | |
782 | + if (word & 4) | |
783 | + fprintf (stream, ")%s", buf); | |
784 | + /* If preindexed, print the closeparen after the index. */ | |
785 | + else | |
786 | + fprintf (stream, "%s)", buf); | |
787 | + | |
788 | + return p; | |
789 | +} | |
790 | + | |
791 | +/* Print a base register REGNO and displacement DISP, on STREAM. | |
792 | + REGNO = -1 for pc, -2 for none (suppressed). */ | |
793 | + | |
794 | +static void | |
795 | +print_base (regno, disp, stream) | |
796 | + int regno; | |
797 | + int disp; | |
798 | + FILE *stream; | |
799 | +{ | |
800 | + if (regno == -2) | |
801 | + fprintf (stream, "%d", disp); | |
802 | + else if (regno == -1) | |
803 | + fprintf (stream, "0x%x", (unsigned) disp); | |
804 | + else | |
805 | + fprintf (stream, "%d(%s)", disp, reg_names[regno]); | |
806 | +} |
@@ -0,0 +1,387 @@ | ||
1 | +/*** nm.c -- Describe symbol table of a rel file. */ | |
2 | +#include "sysdep.h" | |
3 | +#include "bfd.h" | |
4 | +#include "getopt.h" | |
5 | +#include "stab.gnu.h" | |
6 | +#include <ranlib.h> | |
7 | + | |
8 | + | |
9 | + | |
10 | +PROTO(static boolean, display_file, (char *filename)); | |
11 | +PROTO(static boolean, do_one_rel_file, (bfd *file)); | |
12 | +PROTO(static unsigned int, filter_symbols, (bfd *file, asymbol **syms, | |
13 | + unsigned long symcount)); | |
14 | + | |
15 | +PROTO(static void, print_symbols, (bfd *file, asymbol **syms, | |
16 | + unsigned long symcount)); | |
17 | +extern PROTO(int, (*sorters[2][2]), (char *x, char *y)); | |
18 | +PROTO(static void, print_symdef_entry, (bfd * abfd)); | |
19 | + | |
20 | +/* Command options. */ | |
21 | + | |
22 | +int external_only = 0; /* print external symbols only */ | |
23 | +int file_on_each_line = 0; /* print file name on each line */ | |
24 | +int no_sort = 0; /* don't sort; print syms in order found */ | |
25 | +int print_debug_syms = 0; /* print debugger-only symbols too */ | |
26 | +int print_armap = 0; /* describe __.SYMDEF data in archive files. */ | |
27 | +int reverse_sort = 0; /* sort in downward(alpha or numeric) order */ | |
28 | +int sort_numerically = 0; /* sort in numeric rather than alpha order */ | |
29 | +int undefined_only = 0; /* print undefined symbols only */ | |
30 | + | |
31 | +boolean print_each_filename = false; /* Ick. Used in archives. */ | |
32 | + | |
33 | +/* IMPORT */ | |
34 | +extern char *program_name; | |
35 | +extern char *program_version; | |
36 | +extern char *target; | |
37 | + | |
38 | +struct option long_options[] = { | |
39 | + {"debug-syms", 0, &print_debug_syms, 1}, | |
40 | + {"extern-only", 0, &external_only, 1}, | |
41 | + {"no-sort", 0, &no_sort, 1}, | |
42 | + {"numeric-sort", 0, &sort_numerically, 1}, | |
43 | + {"print-armap", 0, &print_armap, 1}, | |
44 | + {"print-file-name", 0, &file_on_each_line, 1}, | |
45 | + {"reverse-sort", 0, &reverse_sort, 1}, | |
46 | + {"target", 2, NULL, NULL}, | |
47 | + {"undefined-only", 0, &undefined_only, 1}, | |
48 | + {0, 0, 0, 0} | |
49 | +}; | |
50 | + | |
51 | +/* Some error-reporting functions */ | |
52 | + | |
53 | +void | |
54 | +usage () | |
55 | +{ | |
56 | + fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n", | |
57 | + program_version, program_name); | |
58 | + exit(0); | |
59 | +} | |
60 | + | |
61 | +int | |
62 | +main (argc, argv) | |
63 | + int argc; | |
64 | + char **argv; | |
65 | +{ | |
66 | + int c; /* sez which option char */ | |
67 | + int ind = 0; /* used by getopt and ignored by us */ | |
68 | + extern int optind; /* steps thru options */ | |
69 | + | |
70 | + program_name = *argv; | |
71 | + | |
72 | + while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) { | |
73 | + switch (c) { | |
74 | + case 'a': print_debug_syms = 1; break; | |
75 | + case 'g': external_only = 1; break; | |
76 | + case 'n': sort_numerically = 1; break; | |
77 | + case 'o': file_on_each_line = 1; break; | |
78 | + case 'p': no_sort = 1; break; | |
79 | + case 'r': reverse_sort = 1; break; | |
80 | + case 's': print_armap = 1; break; | |
81 | + case 'u': undefined_only = 1; break; | |
82 | + | |
83 | + case 0: | |
84 | + if (!strcmp("target",(long_options[option_index]).name)) { | |
85 | + target = optarg; | |
86 | + } | |
87 | + | |
88 | + break; /* we've been given a long option */ | |
89 | + | |
90 | + default: | |
91 | + usage (); | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + /* Strangely, for the shell you should return only a nonzero value | |
96 | + on sucess -- the inverse of the C sense. */ | |
97 | + | |
98 | + /* OK, all options now parsed. If no filename specified, do a.out. */ | |
99 | + if (optind == argc) return !display_file ("a.out"); | |
100 | + | |
101 | + /* We were given several filenames to do: */ | |
102 | + while (optind < argc) | |
103 | + if (!display_file (argv[optind++])) return 1; | |
104 | + | |
105 | + return 0; | |
106 | +} | |
107 | + | |
108 | +/** Display a file's stats */ | |
109 | + | |
110 | +/* goto here is marginally cleaner than the nested if syntax */ | |
111 | + | |
112 | +static boolean | |
113 | +display_file (filename) | |
114 | + char *filename; | |
115 | +{ | |
116 | + boolean retval = false; | |
117 | + bfd *file; | |
118 | + bfd *arfile = NULL; | |
119 | + | |
120 | + file = bfd_openr(filename, target); | |
121 | + if (file == NULL) { | |
122 | + bfd_fatal (filename); | |
123 | + } | |
124 | + | |
125 | + if (bfd_check_format(file, bfd_object)) { | |
126 | + retval = do_one_rel_file (file); | |
127 | + goto closer; | |
128 | + } | |
129 | + | |
130 | + if (!bfd_check_format (file, bfd_archive)) { | |
131 | + fprintf (stderr, "%s: %s: unknown format.\n", program_name, filename); | |
132 | + retval = false; | |
133 | + goto closer; | |
134 | + } | |
135 | + | |
136 | + printf("In archive %s:\n", filename); | |
137 | + if (print_armap) print_symdef_entry (file); | |
138 | + for (;;) { | |
139 | + arfile = bfd_openr_next_archived_file (file, arfile); | |
140 | + | |
141 | + if (arfile == NULL) { | |
142 | + if (bfd_error != no_more_archived_files) | |
143 | + bfd_fatal (filename); | |
144 | + goto closer; | |
145 | + } | |
146 | + | |
147 | + if (!bfd_check_format(arfile, bfd_object)) | |
148 | + printf("%s: not an object file\n", arfile->filename); | |
149 | + else { | |
150 | + printf ("\n%s:\n", arfile->filename); | |
151 | + if (!do_one_rel_file (arfile)) return false; | |
152 | + } | |
153 | + } | |
154 | + | |
155 | + closer: | |
156 | + if (bfd_close(file) == false) | |
157 | + bfd_fatal (filename); | |
158 | + | |
159 | + return retval; | |
160 | +} | |
161 | + | |
162 | + | |
163 | +static boolean | |
164 | +do_one_rel_file (abfd) | |
165 | + bfd *abfd; | |
166 | +{ | |
167 | + unsigned int storage; | |
168 | + asymbol **syms; | |
169 | + unsigned int symcount = 0; | |
170 | + | |
171 | + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { | |
172 | + (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); | |
173 | + return true; | |
174 | + } | |
175 | + | |
176 | + | |
177 | + storage = get_symtab_upper_bound (abfd); | |
178 | + if (storage == 0) { | |
179 | + nosymz: | |
180 | + fprintf (stderr, "%s: Symflags set but there are none?\n", | |
181 | + bfd_get_filename (abfd)); | |
182 | + exit (1); | |
183 | + } | |
184 | + | |
185 | + syms = (asymbol **) xmalloc (storage); | |
186 | + | |
187 | + symcount = bfd_canonicalize_symtab (abfd, syms); | |
188 | + if (symcount == 0) goto nosymz; | |
189 | + | |
190 | + /* Discard the symbols we don't want to print. | |
191 | + It's OK to do this in place; we'll free the storage anyway | |
192 | + (after printing) */ | |
193 | + | |
194 | + symcount = filter_symbols (abfd, syms, symcount); | |
195 | + | |
196 | + if (!no_sort) | |
197 | + qsort((char *) syms, symcount, sizeof (asymbol *), | |
198 | + sorters[sort_numerically][reverse_sort]); | |
199 | + | |
200 | + if (print_each_filename && !file_on_each_line) | |
201 | + printf("\n%s:\n", bfd_get_filename(abfd)); | |
202 | + | |
203 | + print_symbols (abfd, syms, symcount); | |
204 | + free (syms); | |
205 | + return true; | |
206 | +} | |
207 | + | |
208 | +/* Symbol-sorting predicates */ | |
209 | +#define valueof(x) ((x)->section ? (x)->section->vma + (x)->value : (x)->value) | |
210 | +int | |
211 | +numeric_forward (x, y) | |
212 | + char *x; | |
213 | + char *y; | |
214 | +{ | |
215 | + | |
216 | + return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));; | |
217 | +} | |
218 | + | |
219 | +int | |
220 | +numeric_reverse (x, y) | |
221 | + char *x; | |
222 | + char *y; | |
223 | +{ | |
224 | + return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x)); | |
225 | + | |
226 | +} | |
227 | + | |
228 | +int | |
229 | +non_numeric_forward (x, y) | |
230 | + char *x; | |
231 | + char *y; | |
232 | +{ | |
233 | + char *xn = (*(asymbol **) x)->name; | |
234 | + char *yn = (*(asymbol **) y)->name; | |
235 | + | |
236 | + return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) : | |
237 | + ((yn == NULL) ? 1 : strcmp (xn, yn))); | |
238 | +} | |
239 | + | |
240 | +int | |
241 | +non_numeric_reverse (x, y) | |
242 | + char *x; | |
243 | + char *y; | |
244 | +{ | |
245 | + return -(non_numeric_forward (x, y)); | |
246 | +} | |
247 | + | |
248 | +int (*sorters[2][2])() = { | |
249 | + {non_numeric_forward, non_numeric_reverse}, | |
250 | + {numeric_forward, numeric_reverse}, | |
251 | +}; | |
252 | + | |
253 | + | |
254 | +/* Choose which symbol entries to print; | |
255 | + compact them downward to get rid of the rest. | |
256 | + Return the number of symbols to be printed. */ | |
257 | +static unsigned int | |
258 | +filter_symbols (abfd, syms, symcount) | |
259 | + bfd *abfd; | |
260 | + asymbol **syms; | |
261 | + unsigned long symcount; | |
262 | +{ | |
263 | + asymbol **from, **to; | |
264 | + unsigned int dst_count = 0; | |
265 | + unsigned int src_count; | |
266 | + for (from = to = syms, src_count = 0; src_count <symcount; src_count++) { | |
267 | + int keep = 0; | |
268 | + flagword flags = (from[src_count])->flags; | |
269 | + | |
270 | + if (undefined_only) { | |
271 | + keep = (flags & BSF_UNDEFINED); | |
272 | + } else if (external_only) { | |
273 | + keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) || | |
274 | + (flags & BSF_FORT_COMM)); | |
275 | + } else { | |
276 | + keep = 1; | |
277 | + } | |
278 | + | |
279 | + if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) { | |
280 | + keep = 0; | |
281 | + } | |
282 | + | |
283 | + if (keep) { | |
284 | + to[dst_count++] = from[src_count]; | |
285 | + } | |
286 | + } | |
287 | + | |
288 | + return dst_count; | |
289 | +} | |
290 | + | |
291 | + | |
292 | +/* Return a lower-case character corresponding to the symbol class of sym */ | |
293 | +char | |
294 | +decode_symclass (sym) | |
295 | + asymbol *sym; | |
296 | +{ | |
297 | + flagword flags = sym->flags; | |
298 | + | |
299 | + if ((sym->value == 0) && (sym->section != NULL)) | |
300 | + /* Huh? All section names don't begin with "." */ | |
301 | + return (sym->section->name)[1]; | |
302 | + | |
303 | + if (flags & BSF_FORT_COMM) return 'C'; | |
304 | + if (flags & BSF_UNDEFINED) return 'U'; | |
305 | + if (flags & BSF_ABSOLUTE) return 'a'; | |
306 | + | |
307 | + | |
308 | + if ( (flags & BSF_GLOBAL) || (flags & BSF_LOCAL) ){ | |
309 | + if ( !strcmp(sym->section->name, ".text") ){ | |
310 | + return 't'; | |
311 | + } else if ( !strcmp(sym->section->name, ".data") ){ | |
312 | + return 'd'; | |
313 | + } else if ( !strcmp(sym->section->name, ".bss") ){ | |
314 | + return 'b'; | |
315 | + } else { | |
316 | + return 'o'; | |
317 | + } | |
318 | + } | |
319 | + | |
320 | + /* We don't have to handle these cases just yet, but we will soon: | |
321 | + N_SETV: 'v'; | |
322 | + N_SETA: 'l'; | |
323 | + N_SETT: 'x'; | |
324 | + N_SETD: 'z'; | |
325 | + N_SETB: 's'; | |
326 | + N_INDR: 'i'; | |
327 | + */ | |
328 | + | |
329 | + return '?'; | |
330 | +} | |
331 | + | |
332 | +static void | |
333 | +print_symbols (abfd, syms, symcount) | |
334 | + bfd *abfd; | |
335 | + asymbol **syms; | |
336 | + unsigned long symcount; | |
337 | +{ | |
338 | + asymbol **sym = syms, **end = syms + symcount; | |
339 | + char class; | |
340 | + | |
341 | + for (; sym < end; ++sym) { | |
342 | + if (file_on_each_line) printf("%s:", bfd_get_filename(abfd)); | |
343 | + | |
344 | + if (undefined_only) { | |
345 | + if ((*sym)->flags & BSF_UNDEFINED) | |
346 | + puts ((*sym)->name); | |
347 | + } | |
348 | + else { | |
349 | + asymbol *p = *sym; | |
350 | + if (p) { | |
351 | + class = decode_symclass (p); | |
352 | + | |
353 | + if (p->flags & BSF_GLOBAL) | |
354 | + class = toupper (class); | |
355 | + | |
356 | + if (p->value || ((p->flags & BSF_UNDEFINED) != BSF_UNDEFINED)) | |
357 | + printf ("%08lx ", (p->section ? p->value + p->section->vma : p->value)); | |
358 | + else fputs (" ", stdout); | |
359 | + | |
360 | + printf ("%c %s\n", class, p->name); | |
361 | + } | |
362 | + } | |
363 | + } | |
364 | +} | |
365 | + | |
366 | +static void | |
367 | +print_symdef_entry (abfd) | |
368 | + bfd * abfd; | |
369 | +{ | |
370 | + symindex idx = BFD_NO_MORE_SYMBOLS; | |
371 | + carsym *thesym; | |
372 | + boolean everprinted = false; | |
373 | + | |
374 | + for (idx = bfd_get_next_mapent (abfd, idx, &thesym); | |
375 | + idx != BFD_NO_MORE_SYMBOLS; | |
376 | + idx = bfd_get_next_mapent (abfd, idx, &thesym)) { | |
377 | + bfd *elt; | |
378 | + if (!everprinted) { | |
379 | + printf ("\nArchive index:\n"); | |
380 | + everprinted = true; | |
381 | + } | |
382 | + elt = bfd_get_elt_at_index (abfd, idx); | |
383 | + if (thesym->name != (char *)NULL) { | |
384 | + printf ("%s in %s\n", thesym->name, bfd_get_filename (elt)); | |
385 | +} | |
386 | + } | |
387 | +} |
@@ -0,0 +1,714 @@ | ||
1 | +/*** objdump.c -- dump information about an object file. */ | |
2 | + | |
3 | +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | +This file is part of BFD, the Binary File Diddler. | |
6 | + | |
7 | +BFD is free software; you can redistribute it and/or modify | |
8 | +it under the terms of the GNU General Public License as published by | |
9 | +the Free Software Foundation; either version 1, or (at your option) | |
10 | +any later version. | |
11 | + | |
12 | +BFD is distributed in the hope that it will be useful, | |
13 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | +GNU General Public License for more details. | |
16 | + | |
17 | +You should have received a copy of the GNU General Public License | |
18 | +along with BFD; see the file COPYING. If not, write to | |
19 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +/* | |
22 | + $Id$ | |
23 | + $Log$ | |
24 | + Revision 1.1 1991/03/21 21:26:48 gumby | |
25 | + Initial revision | |
26 | + | |
27 | + * Revision 1.2 1991/03/15 18:34:14 rich | |
28 | + * foo | |
29 | + * | |
30 | + * Revision 1.1 1991/03/13 00:34:19 chrisb | |
31 | + * Initial revision | |
32 | + * | |
33 | + * Revision 1.9 1991/03/09 04:36:33 rich | |
34 | + * Modified Files: | |
35 | + * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c | |
36 | + * binutils.h | |
37 | + * | |
38 | + * Pulled sysdep.h out of bfd.h. | |
39 | + * | |
40 | + * Revision 1.8 1991/03/09 03:42:01 rich | |
41 | + * Modified Files: | |
42 | + * Makefile alloca.c ar.c i960-pinsn.c nm.c objdump.c ostrip.c | |
43 | + * strip.c | |
44 | + * | |
45 | + * Ports for intel960 group Portland. | |
46 | + * | |
47 | + * Revision 1.7 1991/03/08 21:54:47 rich | |
48 | + * Modified Files: | |
49 | + * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c | |
50 | + * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h | |
51 | + * sparc-pinsn.c strip.c | |
52 | + * | |
53 | + * Verifying Portland tree with steve's last changes. Also, some partial | |
54 | + * porting. | |
55 | + * | |
56 | + * Revision 1.6 1991/03/08 07:46:26 sac | |
57 | + * Added -l option to disassembly - prints line numbers too. | |
58 | + * | |
59 | + * Revision 1.5 1991/03/07 21:50:24 sac | |
60 | + * More intelligent reloc printing | |
61 | + * | |
62 | + * Revision 1.4 1991/03/05 16:36:54 sac | |
63 | + * Fixed bug where empty symbols would print (null) on suns and crash elsewhere. | |
64 | + * | |
65 | +*/ | |
66 | +/* | |
67 | + * Until there is other documentation, refer to the manual page dump(1) in | |
68 | + * the system 5 program's reference manual | |
69 | + */ | |
70 | + | |
71 | +#include "sysdep.h" | |
72 | +#include "bfd.h" | |
73 | +#include "getopt.h" | |
74 | +#include <stdio.h> | |
75 | +#include <ctype.h> | |
76 | + | |
77 | +char *malloc(); | |
78 | +char *realloc(); | |
79 | +char *xmalloc(); | |
80 | + | |
81 | +char *default_target = NULL; /* default at runtime */ | |
82 | + | |
83 | +char *program_name = NULL; | |
84 | + | |
85 | +int dump_section_contents; /* -s */ | |
86 | +int dump_section_headers; /* -h */ | |
87 | +boolean dump_file_header; /* -f */ | |
88 | +int dump_symtab; /* -t */ | |
89 | +int dump_reloc_info; /* -r */ | |
90 | +int dump_ar_hdrs; /* -a */ | |
91 | +int with_line_numbers; /* -l */ | |
92 | +boolean disassemble; /* -d */ | |
93 | +char *only; | |
94 | + | |
95 | +PROTO (void, display_file, (char *filename, char *target)); | |
96 | +PROTO (void, dump_data, (bfd *abfd)); | |
97 | +PROTO (void, dump_relocs, (bfd *abfd)); | |
98 | +PROTO (void, dump_symbols, (bfd *abfd)); | |
99 | +PROTO (void, print_arelt_descr, (bfd *abfd, boolean verbose)); | |
100 | + | |
101 | + | |
102 | + | |
103 | + | |
104 | + | |
105 | + | |
106 | + | |
107 | +char *machine = (char *)NULL; | |
108 | + asymbol **syms; | |
109 | + asymbol **syms2; | |
110 | + | |
111 | + | |
112 | +unsigned int storage; | |
113 | + | |
114 | +unsigned int symcount = 0; | |
115 | + | |
116 | +void | |
117 | +usage () | |
118 | +{ | |
119 | + fprintf (stderr, | |
120 | + "usage: %s [-ahfdrtxsl] [-m machine] [-j section_name] obj ...\n", | |
121 | + program_name); | |
122 | + exit (1); | |
123 | +} | |
124 | + | |
125 | +static struct option long_options[] = | |
126 | + {{"syms", 0, &dump_symtab, 1}, | |
127 | + {"reloc", 0, &dump_reloc_info, 1}, | |
128 | + {"header", 0, &dump_section_headers, 1}, | |
129 | + {0, 0, 0, 0}}; | |
130 | + | |
131 | + | |
132 | + | |
133 | +static void | |
134 | +dump_headers(abfd) | |
135 | +bfd *abfd; | |
136 | +{ | |
137 | + asection *section; | |
138 | + for (section = abfd->sections; | |
139 | + section != (asection *) NULL; | |
140 | + section = section->next) | |
141 | + { | |
142 | + char *comma = ""; | |
143 | +#define PF(x,y) \ | |
144 | + if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; } | |
145 | + | |
146 | + printf("SECTION %d [%s]\t: size %08x", | |
147 | + section->index, | |
148 | + section->name, | |
149 | +(unsigned) section->size); | |
150 | + printf(" vma %08lx align 2**%2u\n ", | |
151 | + section->vma, | |
152 | + section->alignment_power); | |
153 | + PF(SEC_ALLOC,"ALLOC"); | |
154 | + PF(SEC_LOAD,"LOAD"); | |
155 | + PF(SEC_RELOC,"RELOC"); | |
156 | + PF(SEC_BALIGN,"BALIGN"); | |
157 | + PF(SEC_READONLY,"READONLY"); | |
158 | + PF(SEC_CODE,"CODE"); | |
159 | + PF(SEC_DATA,"DATA"); | |
160 | + PF(SEC_ROM,"ROM"); | |
161 | + printf("\n"); | |
162 | +#undef PF | |
163 | + } | |
164 | +} | |
165 | + | |
166 | +static asymbol ** | |
167 | +slurp_symtab(abfd) | |
168 | +bfd *abfd; | |
169 | +{ | |
170 | + asymbol **sy; | |
171 | + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { | |
172 | + (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); | |
173 | + return(NULL); | |
174 | + } | |
175 | + | |
176 | + storage = get_symtab_upper_bound (abfd); | |
177 | + if (storage) { | |
178 | + sy = (asymbol **) malloc (storage); | |
179 | + if (sy == NULL) { | |
180 | + fprintf (stderr, "%s: out of memory.\n", program_name); | |
181 | + exit (1); | |
182 | + } | |
183 | + } | |
184 | + symcount = bfd_canonicalize_symtab (abfd, sy); | |
185 | +return sy; | |
186 | +} | |
187 | +/* Sort symbols into value order */ | |
188 | +static int comp(ap,bp) | |
189 | +asymbol **ap; | |
190 | +asymbol **bp; | |
191 | +{ | |
192 | + asymbol *a = *ap; | |
193 | + asymbol *b = *bp; | |
194 | + int diff; | |
195 | + | |
196 | + if ( a->name== (char *)NULL || (a->flags &( BSF_DEBUGGING| BSF_UNDEFINED) )) | |
197 | + a->the_bfd = 0; | |
198 | + if ( b->name== (char *)NULL || (b->flags &( BSF_DEBUGGING|BSF_UNDEFINED))) | |
199 | + b->the_bfd =0; | |
200 | + | |
201 | + diff = a->the_bfd - b->the_bfd; | |
202 | + if (diff) { | |
203 | + return -diff; | |
204 | + } | |
205 | + diff = a->value - b->value; | |
206 | + if (diff) { | |
207 | + return diff; | |
208 | + } | |
209 | + return a->section - b->section; | |
210 | +} | |
211 | + | |
212 | +/* Print the supplied address symbolically if possible */ | |
213 | +void | |
214 | +print_address(vma, stream) | |
215 | +bfd_vma vma; | |
216 | +FILE *stream; | |
217 | +{ | |
218 | + /* Perform a binary search looking for the closest symbol to | |
219 | + the required value */ | |
220 | + | |
221 | + unsigned int min = 0; | |
222 | + unsigned int max = symcount; | |
223 | + | |
224 | + unsigned int thisplace = 1; | |
225 | + unsigned int oldthisplace ; | |
226 | + | |
227 | + int vardiff; | |
228 | + if (symcount == 0) | |
229 | + fprintf(stream,"%08lx", vma); | |
230 | + else { | |
231 | + while (true) { | |
232 | + oldthisplace = thisplace; | |
233 | + thisplace = (max + min )/2 ; | |
234 | + if (thisplace == oldthisplace) break; | |
235 | + | |
236 | + | |
237 | + vardiff = syms[thisplace]->value - vma; | |
238 | + | |
239 | + if (vardiff) { | |
240 | + if (vardiff > 0) { | |
241 | + max = thisplace; | |
242 | + } | |
243 | + else { | |
244 | + min = thisplace; | |
245 | + } | |
246 | + } | |
247 | + else { | |
248 | + /* Totally awesome! the exact right symbol */ | |
249 | + fprintf(stream,"%08lx (%s)", vma, syms[thisplace]->name); | |
250 | + return; | |
251 | + } | |
252 | + } | |
253 | + /* We've run out of places to look, print the symbol before this one */ | |
254 | + /* see if this or the symbol before describes this location the best */ | |
255 | + | |
256 | + if (thisplace != 0) { | |
257 | + if (syms[thisplace-1]->value - vma > | |
258 | + syms[thisplace]->value-vma) { | |
259 | + /* Previous symbol is in correct section and is closer */ | |
260 | + thisplace --; | |
261 | + } | |
262 | + } | |
263 | + | |
264 | + { | |
265 | + char *section_name; | |
266 | + asection *sec = syms[thisplace]->section; | |
267 | + if (sec) { | |
268 | + section_name = sec->name; | |
269 | + } | |
270 | + else { | |
271 | + section_name = "abs"; | |
272 | + } | |
273 | + } | |
274 | + if (syms[thisplace]->value > vma) { | |
275 | + fprintf(stream,"%08lx (%s-%lx)", vma, syms[thisplace]->name, | |
276 | + syms[thisplace]->value - vma); | |
277 | + | |
278 | + } | |
279 | + else { | |
280 | + fprintf(stream,"%08lx (%s+%lx)", vma, | |
281 | + syms[thisplace]->name, | |
282 | + vma - syms[thisplace]->value); | |
283 | + } | |
284 | + } | |
285 | +} | |
286 | + | |
287 | +void | |
288 | +disassemble_data(abfd) | |
289 | +bfd *abfd; | |
290 | +{ | |
291 | + bfd_byte *data = NULL; | |
292 | + unsigned int datasize = 0; | |
293 | + unsigned int i; | |
294 | + int (*print)() ; | |
295 | + int print_insn_m68k(); | |
296 | + int print_insn_i960(); | |
297 | + int print_insn_sparc(); | |
298 | + enum bfd_architecture a; | |
299 | + unsigned long m; | |
300 | + asection *section; | |
301 | + /* Replace symbol section relative values with abs values */ | |
302 | + | |
303 | + | |
304 | + for (i = 0; i < symcount; i++) { | |
305 | + if (syms[i]->section != (asection *)NULL) { | |
306 | + syms[i]->value += syms[i]->section->vma; | |
307 | + } | |
308 | + } | |
309 | + | |
310 | + /* We keep a copy of the symbols in the original order */ | |
311 | + syms2 = slurp_symtab(abfd); | |
312 | + | |
313 | + /* Sort the symbols into section and symbol order */ | |
314 | + (void) qsort(syms, symcount, sizeof(asymbol *), comp); | |
315 | + | |
316 | + /* Find the first useless symbol */ | |
317 | + { unsigned int i; | |
318 | + for (i =0; i < symcount; i++) { | |
319 | + if (syms[i]->the_bfd == 0) { | |
320 | + symcount =i; | |
321 | + break; | |
322 | + } | |
323 | + } | |
324 | + } | |
325 | + | |
326 | + | |
327 | + if (machine!= (char *)NULL) { | |
328 | + if (bfd_scan_arch_mach(machine, &a, &m) == false) { | |
329 | + fprintf(stderr,"%s: Can't use supplied machine %s\n", | |
330 | + program_name, | |
331 | + machine); | |
332 | + exit(1); | |
333 | + } | |
334 | + } | |
335 | + else { | |
336 | + a = bfd_get_architecture(abfd); | |
337 | + } | |
338 | + switch (a) { | |
339 | + | |
340 | + case bfd_arch_sparc: | |
341 | + print = print_insn_sparc; | |
342 | + break; | |
343 | + case bfd_arch_m68k: | |
344 | + print = print_insn_m68k; | |
345 | + break; | |
346 | + case bfd_arch_i960: | |
347 | + print = print_insn_i960; | |
348 | + break; | |
349 | + default: | |
350 | + fprintf(stderr,"%s: Can't disassemble for architecture %s\n", | |
351 | + program_name, | |
352 | + bfd_printable_arch_mach(bfd_get_architecture(abfd),0)); | |
353 | + exit(1); | |
354 | + } | |
355 | + | |
356 | + | |
357 | + for (section = abfd->sections; | |
358 | + section != (asection *)NULL; | |
359 | + section = section->next) { | |
360 | + | |
361 | + if (only == (char *)NULL || strcmp(only,section->name) == 0){ | |
362 | + printf("Disassembly of section %s:\n", section->name); | |
363 | + | |
364 | + if (section->size == 0) continue; | |
365 | + | |
366 | + data = (bfd_byte *)malloc(section->size); | |
367 | + | |
368 | + if (data == (bfd_byte *)NULL) { | |
369 | + fprintf (stderr, "%s: memory exhausted.\n", program_name); | |
370 | + exit (1); | |
371 | + } | |
372 | + datasize = section->size; | |
373 | + | |
374 | + | |
375 | + bfd_get_section_contents (abfd, section, data, 0, section->size); | |
376 | + | |
377 | + i = 0; | |
378 | + while ((size_t)i <section->size) { | |
379 | + if (with_line_numbers) { | |
380 | + static prevline; | |
381 | + char *filename; | |
382 | + char *functionname; | |
383 | + int line; | |
384 | + bfd_find_nearest_line(abfd, | |
385 | + section, | |
386 | + syms, | |
387 | + section->vma + i, | |
388 | + &filename, | |
389 | + &functionname, | |
390 | + &line); | |
391 | + | |
392 | + if (filename && functionname && line && line != prevline) { | |
393 | + printf("%s:%d\n", filename, line); | |
394 | + prevline = line; | |
395 | + } | |
396 | + } | |
397 | + print_address(section->vma + i, stdout); | |
398 | + printf(" "); | |
399 | + | |
400 | + i += print(section->vma + i, | |
401 | + data + i, | |
402 | + stdout); | |
403 | + putchar ('\n') ; | |
404 | + } | |
405 | + | |
406 | + | |
407 | + | |
408 | + | |
409 | + free(data); | |
410 | + } | |
411 | + } | |
412 | +} | |
413 | + | |
414 | +void | |
415 | +display_bfd (abfd) | |
416 | + bfd *abfd; | |
417 | +{ | |
418 | + | |
419 | + if (!bfd_check_format (abfd, bfd_object)) { | |
420 | + fprintf (stderr,"%s: %s not an object file\n", program_name, | |
421 | + abfd->filename); | |
422 | + return; | |
423 | + } | |
424 | + printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name); | |
425 | + if (dump_ar_hdrs) print_arelt_descr (abfd, true); | |
426 | + | |
427 | + if (dump_file_header) { | |
428 | + char *comma = ""; | |
429 | + | |
430 | + printf("architecture: %s, ", | |
431 | + bfd_printable_arch_mach (bfd_get_architecture (abfd), | |
432 | + bfd_get_machine (abfd))); | |
433 | + printf("flags 0x%08x:\n", abfd->flags); | |
434 | + | |
435 | +#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";} | |
436 | + PF(HAS_RELOC, "HAS_RELOC"); | |
437 | + PF(EXEC_P, "EXEC_P"); | |
438 | + PF(HAS_LINENO, "HAS_LINENO"); | |
439 | + PF(HAS_DEBUG, "HAS_DEBUG"); | |
440 | + PF(HAS_SYMS, "HAS_SYMS"); | |
441 | + PF(HAS_LOCALS, "HAS_LOCALS"); | |
442 | + PF(DYNAMIC, "DYNAMIC"); | |
443 | + PF(WP_TEXT, "WP_TEXT"); | |
444 | + PF(D_PAGED, "D_PAGED"); | |
445 | + printf("\nstart address 0x%08lx", abfd->start_address); | |
446 | + } | |
447 | + printf("\n"); | |
448 | + | |
449 | + if (dump_section_headers) | |
450 | + dump_headers(abfd); | |
451 | + if (dump_symtab || dump_reloc_info || disassemble) { | |
452 | +syms = slurp_symtab(abfd); | |
453 | + } | |
454 | + if (dump_symtab) dump_symbols (abfd); | |
455 | + if (dump_reloc_info) dump_relocs(abfd); | |
456 | + if (dump_section_contents) dump_data (abfd); | |
457 | + if (disassemble) disassemble_data(abfd); | |
458 | +} | |
459 | + | |
460 | +void | |
461 | +display_file (filename, target) | |
462 | + char *filename; | |
463 | + char *target; | |
464 | +{ | |
465 | + bfd *file, *arfile = (bfd *) NULL; | |
466 | + | |
467 | + file = bfd_openr (filename, target); | |
468 | + if (file == NULL) { | |
469 | + bfd_perror (filename); | |
470 | + return; | |
471 | + } | |
472 | + | |
473 | + if (bfd_check_format (file, bfd_archive) == true) { | |
474 | + printf ("In archive %s:\n", bfd_get_filename (file)); | |
475 | + for(;;) { | |
476 | + bfd_error = no_error; | |
477 | + | |
478 | + arfile = bfd_openr_next_archived_file (file, arfile); | |
479 | + if (arfile == NULL) { | |
480 | + if (bfd_error != no_more_archived_files) | |
481 | + bfd_perror (bfd_get_filename(file)); | |
482 | + return; | |
483 | + } | |
484 | + | |
485 | + display_bfd (arfile); | |
486 | + /* Don't close the archive elements; we need them for next_archive */ | |
487 | + } | |
488 | + } | |
489 | + else | |
490 | + display_bfd(file); | |
491 | + | |
492 | + bfd_close(file); | |
493 | +} | |
494 | + | |
495 | +/* Actually display the various requested regions */ | |
496 | + | |
497 | + | |
498 | + | |
499 | + | |
500 | + | |
501 | + | |
502 | + | |
503 | + | |
504 | + | |
505 | + | |
506 | +void | |
507 | +dump_data (abfd) | |
508 | + bfd *abfd; | |
509 | +{ | |
510 | + asection *section; | |
511 | + bfd_byte *data ; | |
512 | + unsigned int datasize = 0; | |
513 | + size_t i; | |
514 | + | |
515 | + for (section = abfd->sections; section != NULL; section = | |
516 | + section->next) { | |
517 | + int onaline = 16; | |
518 | + | |
519 | + if (only == (char *)NULL || | |
520 | + strcmp(only,section->name) == 0){ | |
521 | + | |
522 | + | |
523 | + | |
524 | + printf("Contents of section %s:\n", section->name); | |
525 | + | |
526 | + if (section->size == 0) continue; | |
527 | + data = (bfd_byte *)malloc(section->size); | |
528 | + if (data == (bfd_byte *)NULL) { | |
529 | + fprintf (stderr, "%s: memory exhausted.\n", program_name); | |
530 | + exit (1); | |
531 | + } | |
532 | + datasize = section->size; | |
533 | + | |
534 | + | |
535 | + bfd_get_section_contents (abfd, section, data, 0, section->size); | |
536 | + | |
537 | + for (i= 0; i < section->size; i += onaline) { | |
538 | + size_t j; | |
539 | + printf(" %04lx ", i + section->vma); | |
540 | + for (j = i; j < i+ onaline; j++) { | |
541 | + if (j < section->size) | |
542 | + printf("%02x", (unsigned)(data[j])); | |
543 | + else | |
544 | + printf(" "); | |
545 | + if ((j & 3 ) == 3) printf(" "); | |
546 | + } | |
547 | + | |
548 | + printf(" "); | |
549 | + for (j = i; j < i+onaline ; j++) { | |
550 | + if (j >= section->size) | |
551 | + printf(" "); | |
552 | + else | |
553 | + printf("%c", isprint(data[j]) ?data[j] : '.'); | |
554 | + } | |
555 | + putchar ('\n'); | |
556 | + } | |
557 | + } | |
558 | + | |
559 | + free (data); | |
560 | + } | |
561 | +} | |
562 | + | |
563 | + | |
564 | + | |
565 | +/* Should perhaps share code and display with nm? */ | |
566 | +void | |
567 | +dump_symbols (abfd) | |
568 | + bfd *abfd; | |
569 | +{ | |
570 | + | |
571 | + unsigned int count; | |
572 | + asymbol **current = syms; | |
573 | + printf("SYMBOL TABLE:\n"); | |
574 | + | |
575 | + for (count = 0; count < symcount; count++) { | |
576 | + if ((*current)->the_bfd) { | |
577 | + bfd_print_symbol((*current)->the_bfd, | |
578 | + stdout, | |
579 | + *current, bfd_print_symbol_all_enum); | |
580 | + | |
581 | + printf("\n"); | |
582 | + } | |
583 | + current++; | |
584 | + } | |
585 | + printf("\n"); | |
586 | + printf("\n"); | |
587 | +} | |
588 | + | |
589 | + | |
590 | +void | |
591 | +dump_relocs(abfd) | |
592 | +bfd *abfd; | |
593 | +{ | |
594 | + arelent **relpp; | |
595 | + unsigned int relcount; | |
596 | + asection *a; | |
597 | + for (a = abfd->sections; a != (asection *)NULL; a = a->next) { | |
598 | + printf("RELOCATION RECORDS FOR [%s]:",a->name); | |
599 | + | |
600 | + if (get_reloc_upper_bound(abfd, a) == 0) { | |
601 | + printf(" (none)\n\n"); | |
602 | + } | |
603 | + else { | |
604 | + arelent **p; | |
605 | + | |
606 | + relpp = (arelent **) xmalloc( get_reloc_upper_bound(abfd,a) ); | |
607 | + relcount = bfd_canonicalize_reloc(abfd,a,relpp, syms); | |
608 | + if (relcount == 0) { | |
609 | + printf(" (none)\n\n"); | |
610 | + } | |
611 | + else { | |
612 | + printf("\n"); | |
613 | + printf("OFFSET TYPE VALUE \n"); | |
614 | + | |
615 | + for (p =relpp; *p != (arelent *)NULL; p++) { | |
616 | + arelent *q = *p; | |
617 | + char *sym_name; | |
618 | + char *section_name = q->section == (asection *)NULL ? "*abs" : | |
619 | + q->section->name; | |
620 | + if (q->sym_ptr_ptr && *q->sym_ptr_ptr) { | |
621 | + sym_name = (*(q->sym_ptr_ptr))->name ; | |
622 | + } | |
623 | + else { | |
624 | + sym_name = 0; | |
625 | + } | |
626 | + if (sym_name) { | |
627 | + printf("%08lx %-8s %s", | |
628 | + q->address, | |
629 | + q->howto->name, | |
630 | + sym_name); | |
631 | + } | |
632 | + else { | |
633 | + printf("%08lx %-8s [%s]", | |
634 | + q->address, | |
635 | + q->howto->name, | |
636 | + section_name); | |
637 | + } | |
638 | + if (q->addend) { | |
639 | + printf("+0x%lx(%ld)", q->addend, (long) q->addend); | |
640 | + } | |
641 | + printf("\n"); | |
642 | + } | |
643 | + printf("\n\n"); | |
644 | + free(relpp); | |
645 | + } | |
646 | + } | |
647 | + | |
648 | + } | |
649 | +} | |
650 | + | |
651 | + | |
652 | +/** main and like trivia */ | |
653 | +int | |
654 | +main (argc, argv) | |
655 | + int argc; | |
656 | + char **argv; | |
657 | +{ | |
658 | + int c; | |
659 | + extern int optind; | |
660 | + extern char *optarg; | |
661 | + char *target = default_target; | |
662 | + boolean seenflag = false; | |
663 | + int ind = 0; | |
664 | + | |
665 | + program_name = *argv; | |
666 | + | |
667 | + while ((c = getopt_long (argc, argv, "b:m:dlfahrtxsj:", long_options, &ind)) | |
668 | + != EOF) { | |
669 | + seenflag = true; | |
670 | + switch (c) { | |
671 | + case 'm': | |
672 | + machine = optarg; | |
673 | + break; | |
674 | + case 'j': | |
675 | + only = optarg; | |
676 | + break; | |
677 | + case 'l': | |
678 | + with_line_numbers = 1; | |
679 | + break; | |
680 | + case 'b': | |
681 | + target = optarg; | |
682 | + break; | |
683 | + case 'f': | |
684 | + dump_file_header = true; | |
685 | + break; | |
686 | + case 'x': | |
687 | + dump_symtab = 1; | |
688 | + dump_reloc_info = 1; | |
689 | + dump_file_header = true; | |
690 | + dump_ar_hdrs = 1; | |
691 | + dump_section_headers = 1; | |
692 | + break; | |
693 | + case 0 : break; /* we've been given a long option */ | |
694 | + case 't': dump_symtab = 1; break; | |
695 | + case 'd': disassemble = true ; break; | |
696 | + case 's': dump_section_contents = 1; break; | |
697 | + case 'r': dump_reloc_info = 1; break; | |
698 | + case 'a': dump_ar_hdrs = 1; break; | |
699 | + case 'h': dump_section_headers = 1; break; | |
700 | + default: | |
701 | + usage (); | |
702 | + } | |
703 | + } | |
704 | + | |
705 | + if (seenflag == false) | |
706 | + usage (); | |
707 | + | |
708 | + if (optind == argc) | |
709 | + display_file ("a.out", target); | |
710 | + else | |
711 | + for (; optind < argc;) | |
712 | + display_file (argv[optind++], target); | |
713 | + return 0; | |
714 | +} |
@@ -0,0 +1,320 @@ | ||
1 | +/*** size.c -- report size of various sections of an executable file */ | |
2 | +/* Extensions/incompatibilities: | |
3 | + o - BSD output has filenames at the end. | |
4 | + o - BSD output can appear in different radicies. | |
5 | + o - SysV output has less redundant whitespace. Filename comes at end. | |
6 | + o - SysV output doesn't show VMA which is always the same as the PMA. | |
7 | + o - We also handle core files. | |
8 | + o - We also handle archives. | |
9 | + If you write shell scripts which manipulate this info then you may be | |
10 | + out of luck; there's no +predantic switch. | |
11 | +*/ | |
12 | +#include "sysdep.h" | |
13 | +#include "bfd.h" | |
14 | +#include "getopt.h" | |
15 | + | |
16 | + | |
17 | +#ifndef BSD_DEFAULT | |
18 | +#define BSD_DEFAULT 1 | |
19 | +#endif | |
20 | + | |
21 | +PROTO(void, display_file, (char *filename)); | |
22 | +PROTO(void, print_sizes, (bfd *file)); | |
23 | + | |
24 | +/* Various program options */ | |
25 | + | |
26 | +enum {decimal, octal, hex} radix = decimal; | |
27 | +int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output */ | |
28 | +int show_version = 0; | |
29 | +int show_help = 0; | |
30 | + | |
31 | +/* IMPORTS */ | |
32 | +extern char *program_version; | |
33 | +extern char *program_name; | |
34 | +extern char *target; | |
35 | + | |
36 | +/** main and like trivia */ | |
37 | + | |
38 | +void | |
39 | +usage () | |
40 | +{ | |
41 | + fprintf (stderr, "size %s\nUsage: %s -{dox}{AB}V files ...\n", | |
42 | + program_version, program_name); | |
43 | + fputs("\t+radix={8|10|16} -- select appropriate output radix.\n\ | |
44 | +\t-d -- output in decimal\n\ | |
45 | +\t-o -- output in octal\n\ | |
46 | +\t-x -- output in hex", stderr); | |
47 | + fputs("\t+format={Berkeley|SysV} -- select display format.\n\ | |
48 | +\t-A -- SysV(AT&T) format\n\ | |
49 | +\t-B -- BSD format", stderr); | |
50 | +#if BSD_DEFAULT | |
51 | + fputs("\t (Default is +format=Berkeley)", stderr); | |
52 | +#else | |
53 | + fputs("\t (Default is +format=SysV)", stderr); | |
54 | +#endif | |
55 | + fputs("\t-V, +version -- display program version, etc.\n\ | |
56 | +\t+help -- this message\n", stderr); | |
57 | + exit(1); | |
58 | +} | |
59 | + | |
60 | +struct option long_options[] = {{"radix", 1, 0, 0}, | |
61 | + {"format", 1, 0, 0}, | |
62 | + {"version", 0, &show_version, 1}, | |
63 | + {"target", 2, NULL, NULL}, | |
64 | + {"help", 0, &show_help, 1}, | |
65 | + {0, 0, 0, 0}}; | |
66 | + | |
67 | +int | |
68 | +main (argc, argv) | |
69 | + int argc; | |
70 | + char **argv; | |
71 | +{ | |
72 | + int temp; | |
73 | + int c; /* sez which option char */ | |
74 | + int option_index = 0; | |
75 | + extern int optind; /* steps thru options */ | |
76 | + program_name = *argv; | |
77 | + | |
78 | + while ((c = getopt_long(argc, argv, "ABVdox", long_options, | |
79 | + &option_index)) != EOF) | |
80 | + switch(c) { | |
81 | + case 0: | |
82 | + if (!strcmp("format",(long_options[option_index]).name)) { | |
83 | + switch(*optarg) { | |
84 | + case 'B': case 'b': berkeley_format = 1; break; | |
85 | + case 'S': case 's': berkeley_format = 0; break; | |
86 | + default: printf("Unknown option to +format: %s\n", optarg); | |
87 | + usage(); | |
88 | + } | |
89 | + break; | |
90 | + } | |
91 | + | |
92 | + if (!strcmp("target",(long_options[option_index]).name)) { | |
93 | + target = optarg; | |
94 | + break; | |
95 | + } | |
96 | + | |
97 | + if (!strcmp("radix",(long_options[option_index]).name)) { | |
98 | +#ifdef ANSI_LIBRARIES | |
99 | + temp = strtol(optarg, NULL, 10); | |
100 | +#else | |
101 | + temp = atol(optarg); | |
102 | +#endif | |
103 | + switch(temp) { | |
104 | + case 10: radix = decimal; break; | |
105 | + case 8: radix = octal; break; | |
106 | + case 16: radix = hex; break; | |
107 | + default: printf("Unknown radix: %s\n", optarg); | |
108 | + usage(); | |
109 | + } | |
110 | + } | |
111 | + break; | |
112 | + case 'A': berkeley_format = 0; break; | |
113 | + case 'B': berkeley_format = 1; break; | |
114 | + case 'V': show_version = 1; break; | |
115 | + case 'd': radix = decimal; break; | |
116 | + case 'x': radix = hex; break; | |
117 | + case 'o': radix = octal; break; | |
118 | + case '?': usage(); | |
119 | + } | |
120 | + | |
121 | + if (show_version) printf("%s version %s\n", program_name, program_version); | |
122 | + if (show_help) usage(); | |
123 | + | |
124 | + if (berkeley_format) | |
125 | +#if 0 /* intel doesn't like bss/stk b/c they don't gave core files */ | |
126 | + puts((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" : | |
127 | + "text\tdata\tbss/stk\tdec\thex\tfilename"); | |
128 | +#else | |
129 | + puts((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" : | |
130 | + "text\tdata\tbss\tdec\thex\tfilename"); | |
131 | +#endif | |
132 | + if (optind == argc) | |
133 | + display_file ("a.out"); | |
134 | + else | |
135 | + for (; optind < argc;) | |
136 | + display_file (argv[optind++]); | |
137 | + | |
138 | + return 0; | |
139 | +} | |
140 | + | |
141 | +/** Display a file's stats */ | |
142 | + | |
143 | +void | |
144 | +display_bfd (abfd) | |
145 | + bfd *abfd; | |
146 | +{ | |
147 | + char *core_cmd; | |
148 | + | |
149 | + if (bfd_check_format(abfd, bfd_archive)) return; | |
150 | + | |
151 | + if (bfd_check_format(abfd, bfd_object)) { | |
152 | + print_sizes(abfd); | |
153 | + goto done; | |
154 | + } | |
155 | + | |
156 | + if (bfd_check_format(abfd, bfd_core)) { | |
157 | + print_sizes(abfd); | |
158 | + fputs(" (core file", stdout); | |
159 | + | |
160 | + core_cmd = bfd_core_file_failing_command(abfd); | |
161 | + if (core_cmd) printf(" invoked as %s", core_cmd); | |
162 | + | |
163 | + puts(")"); | |
164 | + goto done; | |
165 | + } | |
166 | + | |
167 | + printf("Unknown file format: %s.", bfd_get_filename(abfd)); | |
168 | + | |
169 | + done: | |
170 | + | |
171 | + | |
172 | + printf("\n"); | |
173 | + return; | |
174 | +} | |
175 | + | |
176 | +void | |
177 | +display_file(filename) | |
178 | + char *filename; | |
179 | +{ | |
180 | + bfd *file, *arfile = (bfd *) NULL; | |
181 | + | |
182 | + file = bfd_openr (filename, target); | |
183 | + if (file == NULL) { | |
184 | + bfd_perror (filename); | |
185 | + return; | |
186 | + } | |
187 | + | |
188 | + if (bfd_check_format(file, bfd_archive) == true) { | |
189 | + for(;;) { | |
190 | + | |
191 | + bfd_error = no_error; | |
192 | + | |
193 | + arfile = bfd_openr_next_archived_file (file, arfile); | |
194 | + if (arfile == NULL) { | |
195 | + if (bfd_error != no_more_archived_files) | |
196 | + bfd_perror (bfd_get_filename (file)); | |
197 | + return; | |
198 | + } | |
199 | + | |
200 | + display_bfd (arfile); | |
201 | + /* Don't close the archive elements; we need them for next_archive */ | |
202 | + } | |
203 | + } | |
204 | + else | |
205 | + display_bfd (file); | |
206 | + | |
207 | + bfd_close (file); | |
208 | +} | |
209 | + | |
210 | +/* This is what lexical functions are for */ | |
211 | +void | |
212 | +lprint_number (width, num) | |
213 | + int width, num; | |
214 | +{ | |
215 | + printf ((radix == decimal ? "%-*d\t" : | |
216 | + ((radix == octal) ? "%-*o\t" : "%-*x\t")), width, num); | |
217 | +} | |
218 | + | |
219 | +void | |
220 | +rprint_number(width, num) | |
221 | + int width, num; | |
222 | +{ | |
223 | + printf ((radix == decimal ? "%*d\t" : | |
224 | + ((radix == octal) ? "%*o\t" : "%*x\t")), width, num); | |
225 | +} | |
226 | + | |
227 | +static char *bss_section_name = ".bss"; | |
228 | +static char *data_section_name = ".data"; | |
229 | +static char *stack_section_name = ".stack"; | |
230 | +static char *text_section_name = ".text"; | |
231 | + | |
232 | +void print_berkeley_format(abfd) | |
233 | +bfd *abfd; | |
234 | +{ | |
235 | + sec_ptr bsssection = NULL; | |
236 | + sec_ptr datasection = NULL; | |
237 | + sec_ptr textsection = NULL; | |
238 | + unsigned long bsssize = 0; | |
239 | + unsigned long datasize = 0; | |
240 | + unsigned long textsize = 0; | |
241 | + unsigned long total = 0; | |
242 | + | |
243 | + | |
244 | + if ((textsection = bfd_get_section_by_name (abfd, text_section_name)) | |
245 | + != NULL) { | |
246 | + textsize = bfd_section_size (abfd, textsection); | |
247 | + } | |
248 | + | |
249 | + if ((datasection = bfd_get_section_by_name (abfd, data_section_name)) | |
250 | + != NULL) { | |
251 | + datasize = bfd_section_size(abfd, datasection); | |
252 | + } | |
253 | + | |
254 | + if (bfd_get_format (abfd) == bfd_object) { | |
255 | + if ((bsssection = bfd_get_section_by_name (abfd, bss_section_name)) | |
256 | + != NULL) { | |
257 | + bsssize = bfd_section_size(abfd, bsssection); | |
258 | + } | |
259 | + } else { | |
260 | + if ((bsssection = bfd_get_section_by_name (abfd, stack_section_name)) | |
261 | + != NULL) { | |
262 | + bsssize = bfd_section_size(abfd, bsssection); | |
263 | + } | |
264 | + } | |
265 | + | |
266 | + total = textsize + datasize + bsssize; | |
267 | + | |
268 | + lprint_number (7, textsize); | |
269 | + lprint_number (7, datasize); | |
270 | + lprint_number (7, bsssize); | |
271 | + printf (((radix == octal) ? "%-7o\t%-7x\t" : "%-7d\t%-7x\t"), total, total); | |
272 | + | |
273 | + fputs(bfd_get_filename(abfd), stdout); | |
274 | + if (abfd->my_archive) printf (" (ex %s)", abfd->my_archive->filename); | |
275 | +} | |
276 | + | |
277 | +/* I REALLY miss lexical functions! */ | |
278 | +int svi_total = 0; | |
279 | + | |
280 | +void | |
281 | +sysv_internal_printer(file, sec) | |
282 | + bfd *file; | |
283 | + sec_ptr sec; | |
284 | +{ | |
285 | + int size = bfd_section_size (file, sec); | |
286 | + | |
287 | + svi_total += size; | |
288 | + | |
289 | + printf ("%-12s", bfd_section_name(file, sec)); | |
290 | + rprint_number (8, size); | |
291 | + printf(" "); | |
292 | + rprint_number (8, bfd_section_vma(file, sec)); | |
293 | + printf ("\n"); | |
294 | +} | |
295 | + | |
296 | +void | |
297 | +print_sysv_format(file) | |
298 | + bfd *file; | |
299 | +{ | |
300 | + svi_total = 0; | |
301 | + | |
302 | + printf ("%s ", bfd_get_filename (file)); | |
303 | + if (file->my_archive) printf (" (ex %s)", file->my_archive->filename); | |
304 | + | |
305 | + puts(":\nsection\t\tsize\t addr"); | |
306 | + bfd_map_over_sections (file, sysv_internal_printer, NULL); | |
307 | + | |
308 | + printf("Total "); | |
309 | + rprint_number(8, svi_total); | |
310 | + printf("\n"); printf("\n"); | |
311 | +} | |
312 | + | |
313 | +void | |
314 | +print_sizes(file) | |
315 | + bfd *file; | |
316 | +{ | |
317 | + if (berkeley_format) | |
318 | + print_berkeley_format(file); | |
319 | + else print_sysv_format(file); | |
320 | +} |
@@ -0,0 +1,490 @@ | ||
1 | +/* disassemble sparc instructions for objdump | |
2 | + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. | |
3 | + | |
4 | + | |
5 | +This file is part of the binutils. | |
6 | + | |
7 | +The binutils are free software; you can redistribute it and/or modify | |
8 | +it under the terms of the GNU General Public License as published by | |
9 | +the Free Software Foundation; either version 1, or (at your option) | |
10 | +any later version. | |
11 | + | |
12 | +The binutils are distributed in the hope that they will be useful, | |
13 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | +GNU General Public License for more details. | |
16 | + | |
17 | +You should have received a copy of the GNU General Public License | |
18 | +along with the binutils; see the file COPYING. If not, write to | |
19 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +/* $Id$ | |
22 | + $Log$ | |
23 | + Revision 1.1 1991/03/21 21:26:55 gumby | |
24 | + Initial revision | |
25 | + | |
26 | + * Revision 1.1 1991/03/13 00:34:40 chrisb | |
27 | + * Initial revision | |
28 | + * | |
29 | + * Revision 1.3 1991/03/09 04:36:31 rich | |
30 | + * Modified Files: | |
31 | + * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c | |
32 | + * binutils.h | |
33 | + * | |
34 | + * Pulled sysdep.h out of bfd.h. | |
35 | + * | |
36 | + * Revision 1.2 1991/03/08 21:54:53 rich | |
37 | + * Modified Files: | |
38 | + * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c | |
39 | + * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h | |
40 | + * sparc-pinsn.c strip.c | |
41 | + * | |
42 | + * Verifying Portland tree with steve's last changes. Also, some partial | |
43 | + * porting. | |
44 | + * | |
45 | + * Revision 1.1 1991/02/22 16:48:04 sac | |
46 | + * Initial revision | |
47 | + * | |
48 | +*/ | |
49 | + | |
50 | +#include <stdio.h> | |
51 | +#include "sysdep.h" | |
52 | +#include "bfd.h" | |
53 | +#include "sparc-opcode.h" | |
54 | + | |
55 | +extern int fputs(); | |
56 | +extern int print_address(); | |
57 | + | |
58 | +static char *reg_names[] = | |
59 | + { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", | |
60 | + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", | |
61 | + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", | |
62 | + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", | |
63 | + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", | |
64 | + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", | |
65 | + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", | |
66 | + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", | |
67 | + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; | |
68 | + | |
69 | +#define freg_names (®_names[4 * 8]) | |
70 | + | |
71 | +union sparc_insn | |
72 | + { | |
73 | + unsigned long int code; | |
74 | + struct | |
75 | + { | |
76 | + unsigned int OP:2; | |
77 | +#define op ldst.OP | |
78 | + unsigned int RD:5; | |
79 | +#define rd ldst.RD | |
80 | + unsigned int op3:6; | |
81 | + unsigned int RS1:5; | |
82 | +#define rs1 ldst.RS1 | |
83 | + unsigned int i:1; | |
84 | + unsigned int ASI:8; | |
85 | +#define asi ldst.ASI | |
86 | + unsigned int RS2:5; | |
87 | +#define rs2 ldst.RS2 | |
88 | +#define shcnt rs2 | |
89 | + } ldst; | |
90 | + struct | |
91 | + { | |
92 | + unsigned int OP:2, RD:5, op3:6, RS1:5, i:1; | |
93 | + unsigned int IMM13:13; | |
94 | +#define imm13 IMM13.IMM13 | |
95 | + } IMM13; | |
96 | + struct | |
97 | + { | |
98 | + unsigned int OP:2; | |
99 | + unsigned int a:1; | |
100 | + unsigned int cond:4; | |
101 | + unsigned int op2:3; | |
102 | + unsigned int DISP22:22; | |
103 | +#define disp22 branch.DISP22 | |
104 | + } branch; | |
105 | +#define imm22 disp22 | |
106 | + struct | |
107 | + { | |
108 | + unsigned int OP:2; | |
109 | + unsigned int DISP30:30; | |
110 | +#define disp30 call.DISP30 | |
111 | + } call; | |
112 | + }; | |
113 | + | |
114 | +/* Nonzero if INSN is the opcode for a delayed branch. */ | |
115 | +static int | |
116 | +is_delayed_branch (insn) | |
117 | + union sparc_insn insn; | |
118 | +{ | |
119 | + unsigned int i; | |
120 | + | |
121 | + for (i = 0; i < NUMOPCODES; ++i) | |
122 | + { | |
123 | + const struct sparc_opcode *opcode = &sparc_opcodes[i]; | |
124 | + if ((opcode->match & insn.code) == opcode->match | |
125 | + && (opcode->lose & insn.code) == 0 | |
126 | + && (opcode->delayed)) | |
127 | + return 1; | |
128 | + } | |
129 | + return 0; | |
130 | +} | |
131 | + | |
132 | +static int opcodes_sorted = 0; | |
133 | + | |
134 | +/* Print one instruction from MEMADDR on STREAM. */ | |
135 | +int | |
136 | +print_insn_sparc (memaddr, buffer, stream) | |
137 | + bfd_vma memaddr; | |
138 | + bfd_byte *buffer; | |
139 | + FILE *stream; | |
140 | + | |
141 | +{ | |
142 | + union sparc_insn insn; | |
143 | + | |
144 | + register unsigned int i; | |
145 | + | |
146 | + if (!opcodes_sorted) | |
147 | + { | |
148 | + static int compare_opcodes (); | |
149 | + qsort ((char *) sparc_opcodes, NUMOPCODES, | |
150 | + sizeof (sparc_opcodes[0]), compare_opcodes); | |
151 | + opcodes_sorted = 1; | |
152 | + } | |
153 | + | |
154 | +memcpy(&insn,buffer, sizeof (insn)); | |
155 | + | |
156 | + for (i = 0; i < NUMOPCODES; ++i) | |
157 | + { | |
158 | + const struct sparc_opcode *opcode = &sparc_opcodes[i]; | |
159 | + if ((opcode->match & insn.code) == opcode->match | |
160 | + && (opcode->lose & insn.code) == 0) | |
161 | + { | |
162 | + /* Nonzero means that we have found an instruction which has | |
163 | + the effect of adding or or'ing the imm13 field to rs1. */ | |
164 | + int imm_added_to_rs1 = 0; | |
165 | + | |
166 | + /* Nonzero means that we have found a plus sign in the args | |
167 | + field of the opcode table. */ | |
168 | + int found_plus = 0; | |
169 | + | |
170 | + /* Do we have an 'or' instruction where rs1 is the same | |
171 | + as rsd, and which has the i bit set? */ | |
172 | + if (opcode->match == 0x80102000 | |
173 | + && insn.rs1 == insn.rd) | |
174 | + imm_added_to_rs1 = 1; | |
175 | + | |
176 | + if (index (opcode->args, 'S') != 0) | |
177 | + /* Reject the special case for `set'. | |
178 | + The real `sethi' will match. */ | |
179 | + continue; | |
180 | + if (insn.rs1 != insn.rd | |
181 | + && index (opcode->args, 'r') != 0) | |
182 | + /* Can't do simple format if source and dest are different. */ | |
183 | + continue; | |
184 | + | |
185 | + fputs (opcode->name, stream); | |
186 | + | |
187 | + { | |
188 | + register const char *s; | |
189 | + | |
190 | + if (opcode->args[0] != ',') | |
191 | + fputs (" ", stream); | |
192 | + for (s = opcode->args; *s != '\0'; ++s) | |
193 | + { | |
194 | + if (*s == ',') | |
195 | + { | |
196 | + fputs (",", stream); | |
197 | + ++s; | |
198 | + if (*s == 'a') | |
199 | + { | |
200 | + fputs ("a", stream); | |
201 | + ++s; | |
202 | + } | |
203 | + fputs (" ", stream); | |
204 | + } | |
205 | + | |
206 | + switch (*s) | |
207 | + { | |
208 | + case '+': | |
209 | + found_plus = 1; | |
210 | + | |
211 | + /* note fall-through */ | |
212 | + default: | |
213 | + fprintf (stream, "%c", *s); | |
214 | + break; | |
215 | + | |
216 | + case '#': | |
217 | + fputs ("0", stream); | |
218 | + break; | |
219 | + | |
220 | +#define reg(n) fprintf (stream, "%%%s", reg_names[n]) | |
221 | + case '1': | |
222 | + case 'r': | |
223 | + reg (insn.rs1); | |
224 | + break; | |
225 | + | |
226 | + case '2': | |
227 | + reg (insn.rs2); | |
228 | + break; | |
229 | + | |
230 | + case 'd': | |
231 | + reg (insn.rd); | |
232 | + break; | |
233 | +#undef reg | |
234 | + | |
235 | +#define freg(n) fprintf (stream, "%%%s", freg_names[n]) | |
236 | + case 'e': | |
237 | + freg (insn.rs1); | |
238 | + break; | |
239 | + | |
240 | + case 'f': | |
241 | + freg (insn.rs2); | |
242 | + break; | |
243 | + | |
244 | + case 'g': | |
245 | + freg (insn.rd); | |
246 | + break; | |
247 | +#undef freg | |
248 | + | |
249 | +#define creg(n) fprintf (stream, "%%c%u", (unsigned int) (n)) | |
250 | + case 'b': | |
251 | + creg (insn.rs1); | |
252 | + break; | |
253 | + | |
254 | + case 'c': | |
255 | + creg (insn.rs2); | |
256 | + break; | |
257 | + | |
258 | + case 'D': | |
259 | + creg (insn.rd); | |
260 | + break; | |
261 | +#undef creg | |
262 | + | |
263 | + case 'h': | |
264 | + fprintf (stream, "%%hi(%#x)", | |
265 | + (unsigned int) insn.imm22 << 10); | |
266 | + break; | |
267 | + | |
268 | + case 'i': | |
269 | + { | |
270 | + /* We cannot trust the compiler to sign-extend | |
271 | + when extracting the bitfield, hence the shifts. */ | |
272 | + int imm = ((int) insn.imm13 << 19) >> 19; | |
273 | + | |
274 | + /* Check to see whether we have a 1+i, and take | |
275 | + note of that fact. | |
276 | + | |
277 | + Note: because of the way we sort the table, | |
278 | + we will be matching 1+i rather than i+1, | |
279 | + so it is OK to assume that i is after +, | |
280 | + not before it. */ | |
281 | + if (found_plus) | |
282 | + imm_added_to_rs1 = 1; | |
283 | + | |
284 | + if (imm <= 9) | |
285 | + fprintf (stream, "%d", imm); | |
286 | + else | |
287 | + fprintf (stream, "%#x", (unsigned) imm); | |
288 | + } | |
289 | + break; | |
290 | + | |
291 | + case 'L': | |
292 | + print_address ((bfd_vma) memaddr + insn.disp30 * 4, | |
293 | + stream); | |
294 | + break; | |
295 | + | |
296 | + case 'l': | |
297 | + if ((insn.code >> 22) == 0) | |
298 | + /* Special case for `unimp'. Don't try to turn | |
299 | + it's operand into a function offset. */ | |
300 | + fprintf (stream, "%#x", | |
301 | + (unsigned) (((int) insn.disp22 << 10) >> 10)); | |
302 | + else | |
303 | + /* We cannot trust the compiler to sign-extend | |
304 | + when extracting the bitfield, hence the shifts. */ | |
305 | + print_address ((bfd_vma) | |
306 | + (memaddr | |
307 | + + (((int) insn.disp22 << 10) >> 10) * 4), | |
308 | + stream); | |
309 | + break; | |
310 | + | |
311 | + case 'A': | |
312 | + fprintf (stream, "(%d)", (int) insn.asi); | |
313 | + break; | |
314 | + | |
315 | + case 'C': | |
316 | + fputs ("%csr", stream); | |
317 | + break; | |
318 | + | |
319 | + case 'F': | |
320 | + fputs ("%fsr", stream); | |
321 | + break; | |
322 | + | |
323 | + case 'p': | |
324 | + fputs ("%psr", stream); | |
325 | + break; | |
326 | + | |
327 | + case 'q': | |
328 | + fputs ("%fq", stream); | |
329 | + break; | |
330 | + | |
331 | + case 'Q': | |
332 | + fputs ("%cq", stream); | |
333 | + break; | |
334 | + | |
335 | + case 't': | |
336 | + fputs ("%tbr", stream); | |
337 | + break; | |
338 | + | |
339 | + case 'w': | |
340 | + fputs ("%wim", stream); | |
341 | + break; | |
342 | + | |
343 | + case 'y': | |
344 | + fputs ("%y", stream); | |
345 | + break; | |
346 | + } | |
347 | + } | |
348 | + } | |
349 | + | |
350 | + /* If we are adding or or'ing something to rs1, then | |
351 | + check to see whether the previous instruction was | |
352 | + a sethi to the same register as in the sethi. | |
353 | + If so, attempt to print the result of the add or | |
354 | + or (in this context add and or do the same thing) | |
355 | + and its symbolic value. */ | |
356 | + if (imm_added_to_rs1) | |
357 | + { | |
358 | + union sparc_insn prev_insn; | |
359 | + int errcode; | |
360 | + | |
361 | + memcpy(&prev_insn, buffer -4, sizeof (prev_insn)); | |
362 | + | |
363 | + if (errcode == 0) | |
364 | + { | |
365 | + /* If it is a delayed branch, we need to look at the | |
366 | + instruction before the delayed branch. This handles | |
367 | + sequences such as | |
368 | + | |
369 | + sethi %o1, %hi(_foo), %o1 | |
370 | + call _printf | |
371 | + or %o1, %lo(_foo), %o1 | |
372 | + */ | |
373 | + | |
374 | + if (is_delayed_branch (prev_insn)) | |
375 | + memcpy(&prev_insn, buffer - 8, sizeof(prev_insn)); | |
376 | + | |
377 | + } | |
378 | + | |
379 | + /* If there was a problem reading memory, then assume | |
380 | + the previous instruction was not sethi. */ | |
381 | + if (errcode == 0) | |
382 | + { | |
383 | + /* Is it sethi to the same register? */ | |
384 | + if ((prev_insn.code & 0xc1c00000) == 0x01000000 | |
385 | + && prev_insn.rd == insn.rs1) | |
386 | + { | |
387 | + fprintf (stream, "\t! "); | |
388 | + /* We cannot trust the compiler to sign-extend | |
389 | + when extracting the bitfield, hence the shifts. */ | |
390 | + print_address (((int) prev_insn.imm22 << 10) | |
391 | + | (insn.imm13 << 19) >> 19, stream); | |
392 | + } | |
393 | + } | |
394 | + } | |
395 | + | |
396 | + return sizeof (insn); | |
397 | + } | |
398 | + } | |
399 | + | |
400 | + fprintf ("%#8x", insn.code); | |
401 | + return sizeof (insn); | |
402 | +} | |
403 | + | |
404 | + | |
405 | +/* Compare opcodes A and B. */ | |
406 | + | |
407 | +static int | |
408 | +compare_opcodes (a, b) | |
409 | + char *a, *b; | |
410 | +{ | |
411 | + struct sparc_opcode *op0 = (struct sparc_opcode *) a; | |
412 | + struct sparc_opcode *op1 = (struct sparc_opcode *) b; | |
413 | + unsigned long int match0 = op0->match, match1 = op1->match; | |
414 | + unsigned long int lose0 = op0->lose, lose1 = op1->lose; | |
415 | + register unsigned int i; | |
416 | + | |
417 | + /* If a bit is set in both match and lose, there is something | |
418 | + wrong with the opcode table. */ | |
419 | + if (match0 & lose0) | |
420 | + { | |
421 | + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", | |
422 | + op0->name, match0, lose0); | |
423 | + op0->lose &= ~op0->match; | |
424 | + lose0 = op0->lose; | |
425 | + } | |
426 | + | |
427 | + if (match1 & lose1) | |
428 | + { | |
429 | + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", | |
430 | + op1->name, match1, lose1); | |
431 | + op1->lose &= ~op1->match; | |
432 | + lose1 = op1->lose; | |
433 | + } | |
434 | + | |
435 | + /* Because the bits that are variable in one opcode are constant in | |
436 | + another, it is important to order the opcodes in the right order. */ | |
437 | + for (i = 0; i < 32; ++i) | |
438 | + { | |
439 | + unsigned long int x = 1 << i; | |
440 | + int x0 = (match0 & x) != 0; | |
441 | + int x1 = (match1 & x) != 0; | |
442 | + | |
443 | + if (x0 != x1) | |
444 | + return x1 - x0; | |
445 | + } | |
446 | + | |
447 | + for (i = 0; i < 32; ++i) | |
448 | + { | |
449 | + unsigned long int x = 1 << i; | |
450 | + int x0 = (lose0 & x) != 0; | |
451 | + int x1 = (lose1 & x) != 0; | |
452 | + | |
453 | + if (x0 != x1) | |
454 | + return x1 - x0; | |
455 | + } | |
456 | + | |
457 | + /* They are functionally equal. So as long as the opcode table is | |
458 | + valid, we can put whichever one first we want, on aesthetic grounds. */ | |
459 | + { | |
460 | + int length_diff = strlen (op0->args) - strlen (op1->args); | |
461 | + if (length_diff != 0) | |
462 | + /* Put the one with fewer arguments first. */ | |
463 | + return length_diff; | |
464 | + } | |
465 | + | |
466 | + /* Put 1+i before i+1. */ | |
467 | + { | |
468 | + char *p0 = (char *) index(op0->args, '+'); | |
469 | + char *p1 = (char *) index(op1->args, '+'); | |
470 | + | |
471 | + if (p0 && p1) | |
472 | + { | |
473 | + /* There is a plus in both operands. Note that a plus | |
474 | + sign cannot be the first character in args, | |
475 | + so the following [-1]'s are valid. */ | |
476 | + if (p0[-1] == 'i' && p1[1] == 'i') | |
477 | + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ | |
478 | + return 1; | |
479 | + if (p0[1] == 'i' && p1[-1] == 'i') | |
480 | + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ | |
481 | + return -1; | |
482 | + } | |
483 | + } | |
484 | + | |
485 | + /* They are, as far as we can tell, identical. | |
486 | + Since qsort may have rearranged the table partially, there is | |
487 | + no way to tell which one was first in the opcode table as | |
488 | + written, so just say there are equal. */ | |
489 | + return 0; | |
490 | +} |
@@ -0,0 +1,5 @@ | ||
1 | +/*** version.c -- version number for binutils. | |
2 | + They all change in lockstep -- it's easier that way | |
3 | +*/ | |
4 | + | |
5 | +char *program_version = "1.10 (Cygnus BFD)"; |
@@ -0,0 +1,182 @@ | ||
1 | +# | |
2 | +# Makefile for ld version 2 | |
3 | +# | |
4 | +# $Id$ | |
5 | +# | |
6 | +srcdir = . | |
7 | +BASEDIR = ../.. | |
8 | + | |
9 | +INCLUDE = $(srcdir)/$(BASEDIR)/include-cygnus | |
10 | +INCLUDES = -I$(srcdir) -I$(INCLUDE) | |
11 | +DEBUG = -g | |
12 | +CFLAGS = $(INCLUDES) $(DEBUG) | |
13 | + | |
14 | +# go directly to ld.new in case this ld isn't capable of | |
15 | +# linking native object on this host. It can be renamed on | |
16 | +# install. | |
17 | +PROGS = ld.new | |
18 | + | |
19 | +# for self hosting | |
20 | +GNUTARGET=a.out-generic-big | |
21 | +LDEMULATION=gld | |
22 | +bfdlib=$(srcdir)/$(BASEDIR)/bfd/$(HOST)/libbfd.a | |
23 | + | |
24 | +OBJS= ldgram.o ldlex.o ldlang.o ldmain.o ldwrite.o ldexp.o ld-lnk960.o \ | |
25 | + ld-gld.o ld-gld960.o ld-emul.o ldversion.o ldmisc.o ldsym.o ldfile.o | |
26 | + | |
27 | +HEADERS=config.h ldmain.h ldmain.h ldmisc.h ldsym.h ldlang.h ldexp.h \ | |
28 | + ldlex.h ldwrite.h ldversion.h ld-emul.h ldfile.h ldgram.h ld.h | |
29 | + | |
30 | +MANSOURCES=ld.tex | |
31 | + | |
32 | +LDCSOURCES=ldlang.c ldmain.c ldwrite.c ld-lnk960.c ld-gld.c \ | |
33 | + ld-gld960.c ld-emul.c ldversion.c ldmisc.c ldexp.c ldsym.c ldfile.c | |
34 | + | |
35 | +GENERATED_SOURCES=ldgram.tab.c ldlex.c | |
36 | +GENERATED_HEADERS=ldgram.tab.h | |
37 | + | |
38 | +LDSOURCES=$(LDCSOURCES) ldgram.y ldlex.l | |
39 | + | |
40 | +#BFDSOURCES=../bfd/libbfd.c ../bfd/bfd.c ../bfd/sunos.c ../bfd/icoff.c ../bfd/b.out.c ../bfd/archive.c ../bfd/srec.c | |
41 | + | |
42 | +SOURCES= $(LDSOURCES) $(BFDSOURCES) | |
43 | +LINTSOURCES= $(LDCSOURCES) $(BFDSOURCES) $(GENERATED_SOURCES) | |
44 | + | |
45 | +all: $(PROGS) | |
46 | + | |
47 | +$(PROGS): $(OBJS) | |
48 | +# (cd ../bfd; make) | |
49 | +# LDEMULATION=gld; export LDEMULATION; GNUTARGET=a.out-generic-big;./ldok -format a.out-generic-big -o ld /lib/crt0.o $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib | |
50 | +# gld -o ld /lib/crt0.o $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib | |
51 | + $(CC) -Bstatic -o ld.new $(OBJS) $(bfdlib) | |
52 | + | |
53 | + | |
54 | +ld1: ld | |
55 | + gcc -v -B./ -o ld1 $(OBJS) $(bfdlib) | |
56 | + | |
57 | +ld2: ld1 | |
58 | + mv ld1 ld | |
59 | + gcc -v -B./ -o ld2 $(OBJS) $(bfdlib) | |
60 | + | |
61 | +ld3: ld2 | |
62 | + mv ld2 ld | |
63 | + gcc -v -B./ -o ld3 $(OBJS) $(bfdlib) | |
64 | + | |
65 | +ld.dvi:ld.tex | |
66 | + tex ld.tex | |
67 | + | |
68 | +ldgram.o:ldgram.y | |
69 | + yacc -d ldgram.y | |
70 | + mv y.tab.c ldgram.tab.c | |
71 | + $(CC) -c $(CFLAGS) ldgram.tab.c | |
72 | + mv ldgram.tab.o ldgram.o | |
73 | + | |
74 | +ldgram.tab.h:ldgram.o | |
75 | + cp y.tab.h ldgram.tab.h | |
76 | + | |
77 | +ldlex.c: ldlex.l ldgram.tab.h | |
78 | +ldlex.o: ldlex.c ldgram.tab.h | |
79 | + | |
80 | +ldmain.o: ldmain.c | |
81 | +ldversion.o: ldversion.c | |
82 | +ldfile.o: ldfile.c | |
83 | +ldwrite.o: ldwrite.c | |
84 | +ldlang.o: ldlang.c ldgram.tab.h | |
85 | +ld-gld.o: ld-gld.c | |
86 | +ld-gld960.o: ld-gld960.c | |
87 | +ld-emul.o:ld-emul.c | |
88 | +ld-lnk960.o:ld-lnk960.c | |
89 | +ldexp.o:ldexp.c ldgram.tab.h | |
90 | +ldmisc.o:ldmisc.c | |
91 | +ldsym.o:ldsym.c | |
92 | + | |
93 | +clean: | |
94 | + - rm -f $(OBJS) $(GENERATED_SOURCES) $(GENERATED_HEADERS) | |
95 | + - rm -f ld ld1 ld2 | |
96 | + | |
97 | +lintlog:$(SOURCES) Makefile | |
98 | + $(LINT) -abhxzn $(CFLAGS) $(LINTSOURCES) \ | |
99 | +| grep -v "pointer casts may be troublesome" \ | |
100 | +| grep -v "possible pointer alignment problem" \ | |
101 | +| grep -v "ignore" \ | |
102 | +| grep -v "conversion from long may lose accuracy" \ | |
103 | +| grep -v "warning: constant argument to NOT" \ | |
104 | +| grep -v "enumeration type clash, operator CAST" \ | |
105 | +| grep -v "warning: constant in conditional context"\ | |
106 | +| grep -v "archive\.c" | |
107 | + | |
108 | + | |
109 | +tags TAGS:$(SOURCES) $(HEADERS) | |
110 | + etags -t $(SOURCES) $(HEADERS) | |
111 | + | |
112 | +release: | |
113 | + (cd /4/steve/ld; tar cf - $(LDSOURCES) $(HEADERS) $(MANSOURCES)) | tar xf - | |
114 | + | |
115 | +objdump:objdump.c | |
116 | + | |
117 | +install: $(PROGS) | |
118 | + rm -f $G960BASE/bin/$(PROGS) | |
119 | + cp $(PROGS) $$G960BASE/bin/gld960c | |
120 | + | |
121 | +#----------------------------------------------------------------------------- | |
122 | +# 'STANDARD' GNU/960 TARGETS BELOW THIS POINT | |
123 | +# | |
124 | +# 'VERSION' file must be present and contain a string of the form "x.y" | |
125 | +#----------------------------------------------------------------------------- | |
126 | + | |
127 | +ver960.c: FORCE | |
128 | + rm -f ver960.c | |
129 | + echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c | |
130 | + | |
131 | + | |
132 | +# This target should be invoked before building a new release. | |
133 | +# 'VERSION' file must be present and contain a string of the form "x.y" | |
134 | +# | |
135 | +roll: | |
136 | + @V=`cat VERSION` ; \ | |
137 | + MAJ=`sed 's/\..*//' VERSION` ; \ | |
138 | + MIN=`sed 's/.*\.//' VERSION` ; \ | |
139 | + V=$$MAJ.`expr $$MIN + 1` ; \ | |
140 | + rm -f VERSION ; \ | |
141 | + echo $$V >VERSION ; \ | |
142 | + echo Version $$V | |
143 | + | |
144 | +# Dummy target to force execution of dependent targets. | |
145 | +# | |
146 | +.force: | |
147 | +FORCE: | |
148 | + | |
149 | +# Target to uncomment host-specific lines in this makefile. Such lines must | |
150 | +# have the following string beginning in column 1: #__<hostname>__# | |
151 | +# Original Makefile is backed up as 'Makefile.old'. | |
152 | +# | |
153 | +# Invoke with: make make HOST=xxx | |
154 | +# | |
155 | +make: | |
156 | + -@if test $(HOST)x = x ; then \ | |
157 | + echo 'Specify "make make HOST=???"'; \ | |
158 | + exit 1; \ | |
159 | + fi ; \ | |
160 | + grep -s "^#The next line was generated by 'make make'" Makefile; \ | |
161 | + if test $$? = 0 ; then \ | |
162 | + echo "Makefile has already been processed with 'make make'";\ | |
163 | + exit 1; \ | |
164 | + fi ; \ | |
165 | + mv -f Makefile Makefile.old; \ | |
166 | + echo "#The next line was generated by 'make make'" >Makefile ; \ | |
167 | + echo "HOST=$(HOST)" >>Makefile ; \ | |
168 | + echo >>Makefile ; \ | |
169 | + sed "s/^#__$(HOST)__#//" < Makefile.old >>Makefile | |
170 | + | |
171 | +# | |
172 | + | |
173 | +Makefile: ../common/Makefile | |
174 | + mv Makefile Makefile.backup | |
175 | + cp ../common/Makefile . | |
176 | + $(MAKE) "HOST=$(HOST)" make | |
177 | + | |
178 | +### Local Variables: *** | |
179 | +### mode:fundamental *** | |
180 | +### page-delimiter: "^#" *** | |
181 | +### End: *** | |
182 | +### end of file |
@@ -0,0 +1,144 @@ | ||
1 | + | |
2 | + | |
3 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | +This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | +GLD is free software; you can redistribute it and/or modify | |
8 | +it under the terms of the GNU General Public License as published by | |
9 | +the Free Software Foundation; either version 1, or (at your option) | |
10 | +any later version. | |
11 | + | |
12 | +GLD is distributed in the hope that it will be useful, | |
13 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | +GNU General Public License for more details. | |
16 | + | |
17 | +You should have received a copy of the GNU General Public License | |
18 | +along with GLD; see the file COPYING. If not, write to | |
19 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +/* | |
22 | + $Id$ | |
23 | + | |
24 | + $Log$ | |
25 | + Revision 1.1 1991/03/21 21:28:19 gumby | |
26 | + Initial revision | |
27 | + | |
28 | + * Revision 1.1 1991/03/13 00:48:09 chrisb | |
29 | + * Initial revision | |
30 | + * | |
31 | + * Revision 1.4 1991/03/10 09:31:16 rich | |
32 | + * Modified Files: | |
33 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
34 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
35 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
36 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
37 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
38 | + * | |
39 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
40 | + * interest and copy passes my copy test on big endian hosts again. | |
41 | + * | |
42 | + * Revision 1.3 1991/02/22 17:14:55 sac | |
43 | + * Added RCS keywords and copyrights | |
44 | + * | |
45 | +*/ | |
46 | +/* | |
47 | + * clearing house for ld emulation states | |
48 | + */ | |
49 | + | |
50 | +#include "sysdep.h" | |
51 | +#include "bfd.h" | |
52 | + | |
53 | +#include "config.h" | |
54 | +#include "ld.h" | |
55 | +#include "ld-emul.h" | |
56 | +#include "ldmisc.h" | |
57 | + | |
58 | +extern ld_emulation_xfer_type ld_lnk960_emulation; | |
59 | +extern ld_emulation_xfer_type ld_gld_emulation; | |
60 | +extern ld_emulation_xfer_type ld_gld960_emulation; | |
61 | + | |
62 | + | |
63 | + | |
64 | +ld_emulation_xfer_type *ld_emulation; | |
65 | + | |
66 | +void | |
67 | +ldemul_hll(name) | |
68 | +char *name; | |
69 | +{ | |
70 | + ld_emulation->hll(name); | |
71 | +} | |
72 | + | |
73 | + | |
74 | +void ldemul_syslib(name) | |
75 | +char *name; | |
76 | +{ | |
77 | + ld_emulation->syslib(name); | |
78 | +} | |
79 | + | |
80 | +void | |
81 | +ldemul_after_parse() | |
82 | +{ | |
83 | + ld_emulation->after_parse(); | |
84 | +} | |
85 | + | |
86 | +void | |
87 | +ldemul_before_parse() | |
88 | +{ | |
89 | + ld_emulation->before_parse(); | |
90 | +} | |
91 | + | |
92 | +void | |
93 | +ldemul_after_allocation() | |
94 | +{ | |
95 | + ld_emulation->after_allocation(); | |
96 | +} | |
97 | + | |
98 | +void | |
99 | +ldemul_before_allocation() | |
100 | +{ | |
101 | + if (ld_emulation->before_allocation) { | |
102 | + ld_emulation->before_allocation(); | |
103 | + } | |
104 | +} | |
105 | + | |
106 | + | |
107 | +void | |
108 | +ldemul_set_output_arch() | |
109 | +{ | |
110 | + ld_emulation->set_output_arch(); | |
111 | +} | |
112 | + | |
113 | +char * | |
114 | +ldemul_choose_target() | |
115 | +{ | |
116 | + return ld_emulation->choose_target(); | |
117 | +} | |
118 | + | |
119 | +char * | |
120 | +ldemul_get_script() | |
121 | +{ | |
122 | + return ld_emulation->get_script(); | |
123 | +} | |
124 | + | |
125 | +void | |
126 | +ldemul_choose_mode(target) | |
127 | +char *target; | |
128 | +{ | |
129 | + if (strcmp(target,LNK960_EMULATION_NAME)==0) { | |
130 | + ld_emulation = &ld_lnk960_emulation; | |
131 | + } | |
132 | + else if (strcmp(target,GLD_EMULATION_NAME)==0) { | |
133 | + ld_emulation = &ld_gld_emulation; | |
134 | + } | |
135 | + else if (strcmp(target,GLD960_EMULATION_NAME)==0) { | |
136 | + ld_emulation = &ld_gld960_emulation; | |
137 | + } | |
138 | + else { | |
139 | + info("%P%F unrecognised emulation mode: %s",target); | |
140 | + } | |
141 | +} | |
142 | + | |
143 | + | |
144 | + |
@@ -0,0 +1,258 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + * $Id$ | |
21 | + * | |
22 | + * $Log$ | |
23 | + * Revision 1.1 1991/03/21 21:28:24 gumby | |
24 | + * Initial revision | |
25 | + * | |
26 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
27 | + * foo | |
28 | + * | |
29 | + * Revision 1.1 1991/03/13 00:48:11 chrisb | |
30 | + * Initial revision | |
31 | + * | |
32 | + * Revision 1.7 1991/03/10 09:31:18 rich | |
33 | + * Modified Files: | |
34 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
35 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
36 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
37 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
38 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
39 | + * | |
40 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
41 | + * interest and copy passes my copy test on big endian hosts again. | |
42 | + * | |
43 | + * Revision 1.6 1991/03/09 03:23:12 sac | |
44 | + * Added -Ur loader script. | |
45 | + * | |
46 | + * Revision 1.5 1991/03/06 21:59:29 sac | |
47 | + * Completed G++ support | |
48 | + * | |
49 | + * Revision 1.4 1991/03/06 02:23:34 sac | |
50 | + * Added support for partial linking. | |
51 | + * | |
52 | + * Revision 1.3 1991/02/22 17:14:56 sac | |
53 | + * Added RCS keywords and copyrights | |
54 | + * | |
55 | +*/ | |
56 | + | |
57 | +/* | |
58 | + * emulate the original gld | |
59 | + * | |
60 | + * Written by Steve Chamberlain steve@cygnus.com | |
61 | + */ | |
62 | + | |
63 | + | |
64 | +#include "sysdep.h" | |
65 | +#include "bfd.h" | |
66 | + | |
67 | + | |
68 | +#include "ld.h" | |
69 | +#include "config.h" | |
70 | +#include "ld-emul.h" | |
71 | +#include "ldfile.h" | |
72 | +#include "ldmisc.h" | |
73 | + | |
74 | +extern boolean lang_float_flag; | |
75 | + | |
76 | + | |
77 | +extern enum bfd_architecture ldfile_output_architecture; | |
78 | +extern unsigned long ldfile_output_machine; | |
79 | +extern char *ldfile_output_machine_name; | |
80 | + | |
81 | +extern bfd *output_bfd; | |
82 | + | |
83 | + | |
84 | + | |
85 | +static void gld_before_parse() | |
86 | +{ | |
87 | + ldfile_add_library_path("/lib"); | |
88 | + ldfile_add_library_path("/usr/lib"); | |
89 | + ldfile_add_library_path("/usr/local/lib/lib"); | |
90 | + ldfile_output_architecture = bfd_arch_sparc; | |
91 | +} | |
92 | + | |
93 | + | |
94 | +static void | |
95 | +gld_after_parse() | |
96 | +{ | |
97 | + | |
98 | +} | |
99 | + | |
100 | +static void | |
101 | +gld_after_allocation() | |
102 | +{ | |
103 | + | |
104 | +} | |
105 | + | |
106 | +static void | |
107 | +gld_before_allocation() | |
108 | +{ | |
109 | + | |
110 | +} | |
111 | + | |
112 | + | |
113 | +static void | |
114 | +gld_set_output_arch() | |
115 | +{ | |
116 | + /* Set the output architecture and machine if possible */ | |
117 | + unsigned long machine = 0; | |
118 | + bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine); | |
119 | +} | |
120 | + | |
121 | +static char * | |
122 | +gld_choose_target() | |
123 | +{ | |
124 | + char *from_outside = getenv(TARGET_ENVIRON); | |
125 | + if (from_outside != (char *)NULL) | |
126 | + return from_outside; | |
127 | + return GLD_TARGET; | |
128 | +} | |
129 | + | |
130 | +static void | |
131 | +gld_syslib() | |
132 | +{ | |
133 | + info("%S SYSLIB ignored\n"); | |
134 | +} | |
135 | + | |
136 | +static void | |
137 | +gld_hll(ignore) | |
138 | +char *ignore; | |
139 | +{ | |
140 | + info("%S HLL ignored\n"); | |
141 | +} | |
142 | + | |
143 | +static char *gld_script = " \ | |
144 | +SEARCH_DIR(/lib) \ | |
145 | +SEARCH_DIR(/usr/lib) \ | |
146 | +SEARCH_DIR(/usr/local/lib) \ | |
147 | +__DYNAMIC = 0; \ | |
148 | +SECTIONS \ | |
149 | +{ \ | |
150 | + .text 0x2020 BLOCK(0x2000): \ | |
151 | + { \ | |
152 | + CREATE_OBJECT_SYMBOLS \ | |
153 | + *(.text) \ | |
154 | + _etext = ALIGN( 0x2000); \ | |
155 | + } \ | |
156 | + .data ALIGN(0x2000) : \ | |
157 | + { \ | |
158 | + *(.data) \ | |
159 | + ___DTOR_LIST__=. ; \ | |
160 | + LONG((___CTOR_LIST__ - .)/4 -2) \ | |
161 | + *(___DTOR_LIST__) \ | |
162 | + LONG(0) \ | |
163 | + ___CTOR_LIST__=. ; \ | |
164 | + LONG((_edata - .)/4 -2) \ | |
165 | + *(___CTOR_LIST__) \ | |
166 | + LONG(0) \ | |
167 | + _edata = .; \ | |
168 | + } \ | |
169 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
170 | + { \ | |
171 | + *(.bss) \ | |
172 | + [COMMON] \ | |
173 | + _end=.; \ | |
174 | + } \ | |
175 | +}"; | |
176 | + | |
177 | + | |
178 | +static char *gld_script_option_Ur = "\ | |
179 | +SEARCH_DIR(/lib) \ | |
180 | +SEARCH_DIR(/usr/lib) \ | |
181 | +SEARCH_DIR(/usr/local/lib) \ | |
182 | +SECTIONS \ | |
183 | +{ \ | |
184 | + .text 0: \ | |
185 | + { \ | |
186 | + CREATE_OBJECT_SYMBOLS \ | |
187 | + *(.text) \ | |
188 | + } \ | |
189 | + .data SIZEOF(.text) + ADDR(.text) : \ | |
190 | + { \ | |
191 | + *(.data) \ | |
192 | + ___DTOR_LIST__=. ; \ | |
193 | + LONG((___CTOR_LIST__ - .)/4 -2) \ | |
194 | + *(___DTOR_LIST__) \ | |
195 | + LONG(0) \ | |
196 | + ___CTOR_LIST__=. ; \ | |
197 | + LONG((___end_list__ - .)/4 -2) \ | |
198 | + *(___CTOR_LIST__) \ | |
199 | + LONG(0) \ | |
200 | + ___end_list__ = . ; \ | |
201 | + } \ | |
202 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
203 | + { \ | |
204 | + *(.bss) \ | |
205 | + [COMMON] \ | |
206 | + } \ | |
207 | +} \ | |
208 | +"; | |
209 | + | |
210 | +static char *gld_script_option_r = "\ | |
211 | +SEARCH_DIR(/lib) \ | |
212 | +SEARCH_DIR(/usr/lib) \ | |
213 | +SEARCH_DIR(/usr/local/lib) \ | |
214 | +SECTIONS \ | |
215 | +{ \ | |
216 | + .text 0: \ | |
217 | + { \ | |
218 | + CREATE_OBJECT_SYMBOLS \ | |
219 | + *(.text) \ | |
220 | + } \ | |
221 | + .data SIZEOF(.text) + ADDR(.text) : \ | |
222 | + { \ | |
223 | + *(.data) \ | |
224 | + } \ | |
225 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
226 | + { \ | |
227 | + *(.bss) \ | |
228 | + [COMMON] \ | |
229 | + } \ | |
230 | +} \ | |
231 | +"; | |
232 | + | |
233 | +static char *gld_get_script() | |
234 | +{ | |
235 | + extern ld_config_type config; | |
236 | + if (config.relocateable_output == true && | |
237 | + config.build_constructors == true) { | |
238 | + return gld_script_option_Ur; | |
239 | + } | |
240 | + if (config.relocateable_output) { | |
241 | + return gld_script_option_r; | |
242 | + } | |
243 | + | |
244 | + return gld_script; | |
245 | +} | |
246 | +struct ld_emulation_xfer_struct ld_gld_emulation = | |
247 | +{ | |
248 | + gld_before_parse, | |
249 | + gld_syslib, | |
250 | + gld_hll, | |
251 | + gld_after_parse, | |
252 | + gld_after_allocation, | |
253 | + gld_set_output_arch, | |
254 | + gld_choose_target, | |
255 | + gld_before_allocation, | |
256 | + gld_get_script, | |
257 | +}; | |
258 | + |
@@ -0,0 +1,189 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + $Id$ | |
21 | + | |
22 | + $Log$ | |
23 | + Revision 1.1 1991/03/21 21:28:26 gumby | |
24 | + Initial revision | |
25 | + | |
26 | + * Revision 1.3 1991/03/16 22:27:24 rich | |
27 | + * fish | |
28 | + * | |
29 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
30 | + * foo | |
31 | + * | |
32 | + * Revision 1.1 1991/03/13 00:48:12 chrisb | |
33 | + * Initial revision | |
34 | + * | |
35 | + * Revision 1.4 1991/03/10 09:31:19 rich | |
36 | + * Modified Files: | |
37 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
38 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
39 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
40 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
41 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
42 | + * | |
43 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
44 | + * interest and copy passes my copy test on big endian hosts again. | |
45 | + * | |
46 | + * Revision 1.3 1991/02/22 17:14:57 sac | |
47 | + * Added RCS keywords and copyrights | |
48 | + * | |
49 | +*/ | |
50 | + | |
51 | +/* | |
52 | + * emulate the Intels port of gld | |
53 | + */ | |
54 | + | |
55 | + | |
56 | +#include "sysdep.h" | |
57 | +#include "bfd.h" | |
58 | + | |
59 | + | |
60 | +#include "ld.h" | |
61 | +#include "config.h" | |
62 | +#include "ld-emul.h" | |
63 | +#include "ldfile.h" | |
64 | +#include "ldmisc.h" | |
65 | + | |
66 | + | |
67 | +/* IMPORTS */ | |
68 | +extern char *output_filename; | |
69 | +extern boolean lang_float_flag; | |
70 | + | |
71 | + | |
72 | +extern enum bfd_architecture ldfile_output_architecture; | |
73 | +extern unsigned long ldfile_output_machine; | |
74 | +extern char *ldfile_output_machine_name; | |
75 | + | |
76 | +extern bfd *output_bfd; | |
77 | + | |
78 | + | |
79 | + | |
80 | +static void gld960_before_parse() | |
81 | +{ | |
82 | + char *env ; | |
83 | + env = getenv("G960LIB"); | |
84 | + if (env) { | |
85 | + ldfile_add_library_path(env); | |
86 | + } | |
87 | + env = getenv("G960BASE"); | |
88 | + if (env) { | |
89 | + ldfile_add_library_path(concat(env,"/lib","")); | |
90 | + } | |
91 | + ldfile_output_architecture = bfd_arch_i960; | |
92 | +} | |
93 | + | |
94 | + | |
95 | +static void | |
96 | +gld960_after_parse() | |
97 | +{ | |
98 | + | |
99 | +} | |
100 | + | |
101 | +static void | |
102 | +gld960_after_allocation() | |
103 | +{ | |
104 | + | |
105 | +} | |
106 | + | |
107 | +static void | |
108 | +gld960_before_allocation() | |
109 | +{ | |
110 | + | |
111 | +} | |
112 | + | |
113 | + | |
114 | +static void | |
115 | +gld960_set_output_arch() | |
116 | +{ | |
117 | + /* Set the output architecture and machine if possible */ | |
118 | + unsigned long machine = 0; | |
119 | + bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine); | |
120 | +} | |
121 | + | |
122 | +static char * | |
123 | +gld960_choose_target() | |
124 | +{ | |
125 | + char *from_outside = getenv(TARGET_ENVIRON); | |
126 | + output_filename = "b.out"; | |
127 | + | |
128 | + if (from_outside != (char *)NULL) | |
129 | + return from_outside; | |
130 | + return GLD960_TARGET; | |
131 | +} | |
132 | + | |
133 | +static void | |
134 | +gld960_syslib() | |
135 | +{ | |
136 | + info("%S SYSLIB ignored\n"); | |
137 | +} | |
138 | + | |
139 | +static void | |
140 | +gld960_hll() | |
141 | +{ | |
142 | + info("%S HLL ignored\n"); | |
143 | +} | |
144 | + | |
145 | + | |
146 | +static char *script = "\ | |
147 | + \ | |
148 | +SECTIONS \ | |
149 | +{ \ | |
150 | + .text : \ | |
151 | + { \ | |
152 | + CREATE_OBJECT_SYMBOLS \ | |
153 | + *(.text) \ | |
154 | + _etext =.;\ | |
155 | + } \ | |
156 | + \ | |
157 | + .data SIZEOF(.text) + ADDR(.text):\ | |
158 | + { \ | |
159 | + \ | |
160 | + *(.data) \ | |
161 | + _edata = .; \ | |
162 | + } \ | |
163 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
164 | + { _bss_start = .;\ | |
165 | + *(.bss) \ | |
166 | + [COMMON] \ | |
167 | + _end = . ; \ | |
168 | + } \ | |
169 | +} \ | |
170 | +"; | |
171 | + | |
172 | +static char * | |
173 | +gld960_get_script() | |
174 | +{ | |
175 | +return script; | |
176 | +} | |
177 | + | |
178 | +struct ld_emulation_xfer_struct ld_gld960_emulation = | |
179 | +{ | |
180 | + gld960_before_parse, | |
181 | + gld960_syslib, | |
182 | + gld960_hll, | |
183 | + gld960_after_parse, | |
184 | + gld960_after_allocation, | |
185 | + gld960_set_output_arch, | |
186 | + gld960_choose_target, | |
187 | + gld960_before_allocation, | |
188 | + gld960_get_script, | |
189 | +}; |
@@ -0,0 +1,321 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + $Id$ | |
21 | + | |
22 | + $Log$ | |
23 | + Revision 1.1 1991/03/21 21:28:28 gumby | |
24 | + Initial revision | |
25 | + | |
26 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
27 | + * foo | |
28 | + * | |
29 | + * Revision 1.1 1991/03/13 00:48:13 chrisb | |
30 | + * Initial revision | |
31 | + * | |
32 | + * Revision 1.6 1991/03/10 09:31:20 rich | |
33 | + * Modified Files: | |
34 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
35 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
36 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
37 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
38 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
39 | + * | |
40 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
41 | + * interest and copy passes my copy test on big endian hosts again. | |
42 | + * | |
43 | + * Revision 1.5 1991/03/09 03:23:47 sac | |
44 | + * Now looks in G960BASE if I960BASE isn't defined. | |
45 | + * | |
46 | + * Revision 1.4 1991/03/06 02:23:35 sac | |
47 | + * Added support for partial linking. | |
48 | + * | |
49 | + * Revision 1.3 1991/02/22 17:14:58 sac | |
50 | + * Added RCS keywords and copyrights | |
51 | + * | |
52 | +*/ | |
53 | + | |
54 | +/* | |
55 | + | |
56 | + Written by Steve Chamberlain steve@cygnus.com | |
57 | + | |
58 | + * intel coff loader emulation specific stuff | |
59 | + */ | |
60 | + | |
61 | +#include "sysdep.h" | |
62 | +#include "bfd.h" | |
63 | + | |
64 | +/*#include "archures.h"*/ | |
65 | +#include "ld.h" | |
66 | +#include "config.h" | |
67 | +#include "ld-emul.h" | |
68 | +#include "ldmisc.h" | |
69 | +#include "ldlang.h" | |
70 | +#include "ldfile.h" | |
71 | + | |
72 | +extern boolean lang_float_flag; | |
73 | +extern bfd *output_bfd; | |
74 | + | |
75 | + | |
76 | + | |
77 | +extern enum bfd_architecture ldfile_output_architecture; | |
78 | +extern unsigned long ldfile_output_machine; | |
79 | +extern char *ldfile_output_machine_name; | |
80 | + | |
81 | + | |
82 | +typedef struct lib_list { | |
83 | + char *name; | |
84 | + struct lib_list *next; | |
85 | +} lib_list_type; | |
86 | + | |
87 | +static lib_list_type *hll_list; | |
88 | +static lib_list_type **hll_list_tail = &hll_list; | |
89 | + | |
90 | +static lib_list_type *syslib_list; | |
91 | +static lib_list_type **syslib_list_tail = &syslib_list; | |
92 | + | |
93 | + | |
94 | +static void | |
95 | +append(list, name) | |
96 | +lib_list_type ***list; | |
97 | +char *name; | |
98 | +{ | |
99 | + lib_list_type *element = | |
100 | + (lib_list_type *)(ldmalloc(sizeof(lib_list_type))); | |
101 | + | |
102 | + element->name = name; | |
103 | + element->next = (lib_list_type *)NULL; | |
104 | + **list = element; | |
105 | + *list = &element->next; | |
106 | + | |
107 | +} | |
108 | + | |
109 | +static boolean had_hll = false; | |
110 | +static boolean had_hll_name = false; | |
111 | +static void | |
112 | +lnk960_hll(name) | |
113 | +char *name; | |
114 | +{ | |
115 | + had_hll = true; | |
116 | + if (name != (char *)NULL) { | |
117 | + had_hll_name = true; | |
118 | + append(&hll_list_tail, name); | |
119 | + } | |
120 | +} | |
121 | + | |
122 | +static void | |
123 | +lnk960_syslib(name) | |
124 | +char *name; | |
125 | +{ | |
126 | + append(&syslib_list_tail,name); | |
127 | +} | |
128 | + | |
129 | + | |
130 | + | |
131 | +static void | |
132 | +lnk960_before_parse() | |
133 | +{ | |
134 | + char *name = getenv("I960BASE"); | |
135 | + | |
136 | + if (name == (char *)NULL) { | |
137 | + name = getenv("G960BASE"); | |
138 | + if (name == (char *)NULL) { | |
139 | + info("%P%F I960BASE and G960BASE not set\n"); | |
140 | + } | |
141 | + } | |
142 | + | |
143 | + | |
144 | + ldfile_add_library_path(concat(name,"/lib","")); | |
145 | + ldfile_output_architecture = bfd_arch_i960; | |
146 | + ldfile_output_machine = bfd_mach_i960_core; | |
147 | +} | |
148 | + | |
149 | +static void | |
150 | +add_on(list, search) | |
151 | +lib_list_type *list; | |
152 | +lang_input_file_enum_type search; | |
153 | +{ | |
154 | + while (list) { | |
155 | + lang_add_input_file(list->name, | |
156 | + search, | |
157 | + (char *)NULL); | |
158 | + list = list->next; | |
159 | + } | |
160 | +} | |
161 | +static void lnk960_after_parse() | |
162 | +{ | |
163 | + | |
164 | + /* If there has been no arch, default to -KB */ | |
165 | + if (ldfile_output_machine_name[0] ==0) { | |
166 | + ldfile_add_arch("kb"); | |
167 | + } | |
168 | + | |
169 | + /* if there has been no hll list then add our own */ | |
170 | + | |
171 | + if(had_hll && !had_hll_name) { | |
172 | + append(&hll_list_tail,"c"); | |
173 | + if (lang_float_flag == true) { | |
174 | + append(&hll_list_tail,"m"); | |
175 | + } | |
176 | + else { | |
177 | + append(&hll_list_tail,"mstub"); | |
178 | + } | |
179 | + if (ldfile_output_machine == bfd_mach_i960_ka_sa || | |
180 | + ldfile_output_machine == bfd_mach_i960_ca) { | |
181 | + { | |
182 | + append(&hll_list_tail,"f"); | |
183 | + } | |
184 | + } | |
185 | + } | |
186 | + | |
187 | + | |
188 | + | |
189 | + add_on(hll_list, lang_input_file_is_l_enum); | |
190 | + add_on(syslib_list, lang_input_file_is_search_file_enum); | |
191 | + | |
192 | + | |
193 | +} | |
194 | + | |
195 | +static void | |
196 | +lnk960_before_allocation() | |
197 | +{ | |
198 | +} | |
199 | +static void | |
200 | +lnk960_after_allocation() | |
201 | +{ | |
202 | + lang_abs_symbol_at_end_of(".text","_etext"); | |
203 | + lang_abs_symbol_at_end_of(".data","_edata"); | |
204 | + lang_abs_symbol_at_end_of(".bss","_end"); | |
205 | +} | |
206 | + | |
207 | +static struct | |
208 | + { | |
209 | + unsigned long number; | |
210 | + char *name; | |
211 | + } | |
212 | +machine_table[] = { | |
213 | + bfd_mach_i960_core ,"CORE", | |
214 | + bfd_mach_i960_kb_sb ,"KB", | |
215 | + bfd_mach_i960_kb_sb ,"SB", | |
216 | + bfd_mach_i960_mc ,"MC", | |
217 | + bfd_mach_i960_xa ,"XA", | |
218 | + bfd_mach_i960_ca ,"CA", | |
219 | + bfd_mach_i960_ka_sa ,"KA", | |
220 | + bfd_mach_i960_ka_sa ,"SA", | |
221 | + | |
222 | + bfd_mach_i960_core ,"core", | |
223 | + bfd_mach_i960_kb_sb ,"kb", | |
224 | + bfd_mach_i960_kb_sb ,"sb", | |
225 | + bfd_mach_i960_mc ,"mc", | |
226 | + bfd_mach_i960_xa ,"xa", | |
227 | + bfd_mach_i960_ca ,"ca", | |
228 | + bfd_mach_i960_ka_sa ,"ka", | |
229 | + bfd_mach_i960_ka_sa ,"sa", | |
230 | + 0,(char *)NULL | |
231 | +}; | |
232 | + | |
233 | +static void | |
234 | +lnk960_set_output_arch() | |
235 | +{ | |
236 | + /* Set the output architecture and machine if possible */ | |
237 | + unsigned int i; | |
238 | + ldfile_output_machine = bfd_mach_i960_core; | |
239 | + for (i= 0; machine_table[i].name != (char*)NULL; i++) { | |
240 | + if (strcmp(ldfile_output_machine_name,machine_table[i].name)==0) { | |
241 | + ldfile_output_machine = machine_table[i].number; | |
242 | + break; | |
243 | + } | |
244 | + } | |
245 | + bfd_set_arch_mach(output_bfd, ldfile_output_architecture, ldfile_output_machine); | |
246 | +} | |
247 | + | |
248 | +static char * | |
249 | +lnk960_choose_target() | |
250 | +{ | |
251 | + char *from_outside = getenv(TARGET_ENVIRON); | |
252 | + if (from_outside != (char *)NULL) | |
253 | + return from_outside; | |
254 | + return LNK960_TARGET; | |
255 | +} | |
256 | + | |
257 | +/* The default script if none is offered */ | |
258 | +static char *lnk960_script = "\ | |
259 | +SECTIONS \ | |
260 | +{ \ | |
261 | + .text : \ | |
262 | + { \ | |
263 | + *(.text) \ | |
264 | + } \ | |
265 | +_etext = .;\ | |
266 | + .data SIZEOF(.text) + ADDR(.text):\ | |
267 | + { \ | |
268 | + *(.data) \ | |
269 | + } \ | |
270 | +_edata = .; \ | |
271 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
272 | + { \ | |
273 | + _bss_start = . ;\ | |
274 | + *(.bss) \ | |
275 | + [COMMON] \ | |
276 | + } \ | |
277 | +_end = . ; \ | |
278 | +} \ | |
279 | +"; | |
280 | + | |
281 | +static char *lnk960_script_relocateable = "\ | |
282 | +SECTIONS \ | |
283 | +{ \ | |
284 | + .text 0x40000000: \ | |
285 | + { \ | |
286 | + *(.text) \ | |
287 | + } \ | |
288 | + .data 0:\ | |
289 | + { \ | |
290 | + *(.data) \ | |
291 | + } \ | |
292 | + .bss SIZEOF(.data) + ADDR(.data) : \ | |
293 | + { \ | |
294 | + *(.bss) \ | |
295 | + [COMMON] \ | |
296 | + } \ | |
297 | +} \ | |
298 | +"; | |
299 | + | |
300 | +static char *lnk960_get_script() | |
301 | +{ | |
302 | +extern ld_config_type config; | |
303 | +if (config.relocateable_output) { | |
304 | + return lnk960_script_relocateable; | |
305 | +} | |
306 | +return lnk960_script; | |
307 | + | |
308 | + | |
309 | +} | |
310 | +struct ld_emulation_xfer_struct ld_lnk960_emulation = | |
311 | +{ | |
312 | + lnk960_before_parse, | |
313 | + lnk960_syslib, | |
314 | + lnk960_hll, | |
315 | + lnk960_after_parse, | |
316 | + lnk960_after_allocation, | |
317 | + lnk960_set_output_arch, | |
318 | + lnk960_choose_target, | |
319 | + lnk960_before_allocation, | |
320 | + lnk960_get_script, | |
321 | +}; |
@@ -0,0 +1,132 @@ | ||
1 | +/* ld.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | +#define flag_is_not_at_end(x) ((x) & BSF_NOT_AT_END) | |
23 | +#define flag_is_ordinary_local(x) (((x) & (BSF_LOCAL))&!((x) & (BSF_DEBUGGING))) | |
24 | +#define flag_is_debugger(x) ((x) & BSF_DEBUGGING) | |
25 | +#define flag_is_undefined_or_global(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL)) | |
26 | +#define flag_is_defined(x) (!((x) & (BSF_UNDEFINED))) | |
27 | +#define flag_is_global_or_common(x) ((x) & (BSF_GLOBAL | BSF_FORT_COMM)) | |
28 | +#define flag_is_undefined_or_global_or_common(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL | BSF_FORT_COMM)) | |
29 | +#define flag_is_common(x) ((x) & BSF_FORT_COMM) | |
30 | +#define flag_is_global(x) ((x) & (BSF_GLOBAL)) | |
31 | +#define flag_is_undefined(x) ((x) & BSF_UNDEFINED) | |
32 | +#define flag_set(x,y) (x = y) | |
33 | +#define flag_is_fort_comm(x) ((x) & BSF_FORT_COMM) | |
34 | +#define flag_is_absolute(x) ((x) & BSF_ABSOLUTE) | |
35 | +/* Extra information we hold on sections */ | |
36 | +typedef struct user_section_struct { | |
37 | + /* Pointer to the section where this data will go */ | |
38 | + struct lang_input_statement_struct *file; | |
39 | +} section_userdata_type; | |
40 | + | |
41 | + | |
42 | +#define get_userdata(x) ((x)->userdata) | |
43 | +#define as_output_section_statement(x) ((x)->otheruserdata) | |
44 | + | |
45 | +#if 0 | |
46 | +/* | |
47 | + * Structure for communication between do_file_warnings and it's | |
48 | + * helper routines. Will in practice be an array of three of these: | |
49 | + * 0) Current line, 1) Next line, 2) Source file info. | |
50 | + */ | |
51 | +struct line_debug_entry | |
52 | +{ | |
53 | + int line; | |
54 | + char *filename; | |
55 | + struct nlist *sym; | |
56 | +}; | |
57 | + | |
58 | +#endif | |
59 | + | |
60 | + | |
61 | +/* Which symbols should be stripped (omitted from the output): | |
62 | + none, all, or debugger symbols. */ | |
63 | +enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols; | |
64 | + | |
65 | + | |
66 | + | |
67 | + | |
68 | +/* Which local symbols should be omitted: | |
69 | + none, all, or those starting with L. | |
70 | + This is irrelevant if STRIP_NONE. */ | |
71 | +enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals; | |
72 | + | |
73 | + | |
74 | + | |
75 | + | |
76 | + | |
77 | + | |
78 | +#define ALIGN(this, boundary) ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) | |
79 | +#if 0 | |
80 | +#define FOREACHGLOBALSYMBOL(x) ldsym_type *x; for (x = symbol_head; x; x=x->next) | |
81 | + | |
82 | + | |
83 | + | |
84 | + | |
85 | +#define SECTIONLOOP(abfd, ptr) \ | |
86 | + asection *ptr; for(ptr = abfd->sections; ptr;ptr=ptr->next) | |
87 | + | |
88 | + | |
89 | +#endif | |
90 | +typedef struct { | |
91 | + | |
92 | + /* 1 => assign space to common symbols even if `relocatable_output'. */ | |
93 | + boolean force_common_definition; | |
94 | + | |
95 | +} args_type; | |
96 | + | |
97 | +typedef int token_code_type; | |
98 | + | |
99 | +typedef struct | |
100 | +{ | |
101 | + unsigned int specified_data_size; | |
102 | + boolean magic_demand_paged; | |
103 | + boolean make_executable; | |
104 | + /* 1 => write relocation into output file so can re-input it later. */ | |
105 | + boolean relocateable_output; | |
106 | + | |
107 | + /* Will we build contstructors, or leave alone ? */ | |
108 | + boolean build_constructors; | |
109 | + /* 1 => write relocation such that a UNIX linker can understand it. | |
110 | + This is used mainly to finish of sets that were built. */ | |
111 | + boolean unix_relocate; | |
112 | + | |
113 | + | |
114 | +} ld_config_type; | |
115 | +#define set_asymbol_chain(x,y) ((x)->udata = (void *)y) | |
116 | +#define get_asymbol_chain(x) ((asymbol **)((x)->udata)) | |
117 | +#define get_loader_symbol(x) ((loader_global_asymbol *)((x)->udata)) | |
118 | +#define set_loader_symbol(x,y) ((x)->udata = (void *)y) | |
119 | + | |
120 | + | |
121 | + | |
122 | + | |
123 | + | |
124 | + | |
125 | +typedef enum { | |
126 | + lang_first_phase_enum, | |
127 | + lang_allocating_phase_enum, | |
128 | + lang_final_phase_enum } lang_phase_type; | |
129 | + | |
130 | + | |
131 | + | |
132 | + |
@@ -0,0 +1,770 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + $Id$ | |
21 | + | |
22 | + $Log$ | |
23 | + Revision 1.1 1991/03/21 21:28:34 gumby | |
24 | + Initial revision | |
25 | + | |
26 | + * Revision 1.1 1991/03/13 00:48:16 chrisb | |
27 | + * Initial revision | |
28 | + * | |
29 | + * Revision 1.6 1991/03/10 09:31:22 rich | |
30 | + * Modified Files: | |
31 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
32 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
33 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
34 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
35 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
36 | + * | |
37 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
38 | + * interest and copy passes my copy test on big endian hosts again. | |
39 | + * | |
40 | + * Revision 1.5 1991/03/09 03:25:04 sac | |
41 | + * Added support for LONG, SHORT and BYTE keywords in scripts | |
42 | + * | |
43 | + * Revision 1.4 1991/03/06 02:27:15 sac | |
44 | + * Added LONG, SHORT and BYTE keywords | |
45 | + * | |
46 | + * Revision 1.3 1991/02/22 17:14:59 sac | |
47 | + * Added RCS keywords and copyrights | |
48 | + * | |
49 | +*/ | |
50 | + | |
51 | +/* | |
52 | + * Written by Steve Chamberlain | |
53 | + * steve@cygnus.com | |
54 | + * | |
55 | + * This module handles expression trees. | |
56 | + */ | |
57 | + | |
58 | + | |
59 | +#include "sysdep.h" | |
60 | +#include "bfd.h" | |
61 | + | |
62 | +#include "ld.h" | |
63 | +#include "ldmain.h" | |
64 | +#include "ldmisc.h" | |
65 | +#include "ldexp.h" | |
66 | +#include "ldgram.tab.h" | |
67 | +#include "ldsym.h" | |
68 | +#include "ldlang.h" | |
69 | + | |
70 | +extern char *output_filename; | |
71 | +extern unsigned int undefined_global_sym_count; | |
72 | +extern unsigned int defined_global_sym_count; | |
73 | +extern bfd *output_bfd; | |
74 | +extern size_t largest_section; | |
75 | +extern lang_statement_list_type file_chain; | |
76 | +extern args_type command_line; | |
77 | +extern ld_config_type config; | |
78 | + | |
79 | +extern lang_input_statement_type *script_file; | |
80 | +extern unsigned int defined_global_sym_count; | |
81 | + | |
82 | +extern bfd_vma print_dot; | |
83 | + | |
84 | + | |
85 | +static void | |
86 | +exp_print_token(outfile, code) | |
87 | +FILE *outfile; | |
88 | +token_code_type code; | |
89 | +{ | |
90 | + static struct { | |
91 | + token_code_type code; | |
92 | + char *name; | |
93 | + } table[] = | |
94 | + { | |
95 | + INT, "int", | |
96 | + CHAR,"char", | |
97 | + NAME,"NAME", | |
98 | + PLUSEQ,"+=", | |
99 | + MINUSEQ,"-=", | |
100 | + MULTEQ,"*=", | |
101 | + DIVEQ,"/=", | |
102 | + LSHIFTEQ,"<<=", | |
103 | + RSHIFTEQ,">>=", | |
104 | + ANDEQ,"&=", | |
105 | + OREQ,"|=", | |
106 | + OROR,"||", | |
107 | + ANDAND,"&&", | |
108 | + EQ,"==", | |
109 | + NE,"!=", | |
110 | + LE,"<=", | |
111 | + GE,">=", | |
112 | + LSHIFT,"<<", | |
113 | + RSHIFT,">>=", | |
114 | + ALIGN_K,"ALIGN", | |
115 | + BLOCK,"BLOCK", | |
116 | + SECTIONS,"SECTIONS", | |
117 | + ALIGNMENT,"ALIGNMENT", | |
118 | + SIZEOF_HEADERS,"SIZEOF_HEADERS", | |
119 | + NEXT,"NEXT", | |
120 | + SIZEOF,"SIZEOF", | |
121 | + ADDR,"ADDR", | |
122 | + MEMORY,"MEMORY", | |
123 | + DSECT,"DSECT", | |
124 | + NOLOAD,"NOLOAD", | |
125 | + COPY,"COPY", | |
126 | + INFO,"INFO", | |
127 | + OVERLAY,"OVERLAY", | |
128 | + DEFINED,"DEFINED", | |
129 | + TARGET_K,"TARGET", | |
130 | + SEARCH_DIR,"SEARCH_DIR", | |
131 | + MAP,"MAP", | |
132 | + LONG,"LONG", | |
133 | + SHORT,"SHORT", | |
134 | + BYTE,"BYTE", | |
135 | + ENTRY,"ENTRY", | |
136 | + 0,(char *)NULL} ; | |
137 | + | |
138 | + | |
139 | + | |
140 | + unsigned int idx; | |
141 | + for (idx = 0; table[idx].name != (char*)NULL; idx++) { | |
142 | + if (table[idx].code == code) { | |
143 | + fprintf(outfile, "%s", table[idx].name); | |
144 | + return; | |
145 | + } | |
146 | + } | |
147 | + /* Not in table, just print it alone */ | |
148 | + fprintf(outfile, "%c",code); | |
149 | +} | |
150 | + | |
151 | +static void | |
152 | +make_abs(ptr) | |
153 | +etree_value_type *ptr; | |
154 | +{ | |
155 | + if (ptr->section != (lang_output_section_statement_type *)NULL) { | |
156 | + asection *s = ptr->section->bfd_section; | |
157 | + ptr->value += s->vma; | |
158 | + ptr->section = (lang_output_section_statement_type *)NULL; | |
159 | + } | |
160 | + | |
161 | +} | |
162 | +static | |
163 | +etree_value_type new_abs(value) | |
164 | +bfd_vma value; | |
165 | +{ | |
166 | + etree_value_type new; | |
167 | + new.valid = true; | |
168 | + new.section = (lang_output_section_statement_type *)NULL; | |
169 | + new.value = value; | |
170 | + return new; | |
171 | +} | |
172 | + | |
173 | +static void check(os) | |
174 | +lang_output_section_statement_type *os; | |
175 | +{ | |
176 | + if (os == (lang_output_section_statement_type *)NULL) { | |
177 | + info("%F%P undefined section"); | |
178 | + } | |
179 | + if (os->processed == false) { | |
180 | + info("%F%P forward reference of section"); | |
181 | + } | |
182 | +} | |
183 | + | |
184 | +etree_type *exp_intop(value) | |
185 | +bfd_vma value; | |
186 | +{ | |
187 | + etree_type *new = (etree_type *)ldmalloc(sizeof(new->value)); | |
188 | + new->type.node_code = INT; | |
189 | + new->value.value = value; | |
190 | + new->type.node_class = etree_value; | |
191 | + return new; | |
192 | + | |
193 | +} | |
194 | + | |
195 | + | |
196 | +static | |
197 | +etree_value_type new_rel(value, section) | |
198 | +bfd_vma value; | |
199 | +lang_output_section_statement_type *section; | |
200 | +{ | |
201 | + etree_value_type new; | |
202 | + new.valid = true; | |
203 | + new.value = value; | |
204 | + new.section = section; | |
205 | + return new; | |
206 | +} | |
207 | + | |
208 | +static | |
209 | +etree_value_type new_rel_from_section(value, section) | |
210 | +bfd_vma value; | |
211 | +lang_output_section_statement_type *section; | |
212 | +{ | |
213 | + etree_value_type new; | |
214 | + new.valid = true; | |
215 | + new.value = value; | |
216 | + new.section = section; | |
217 | + if (new.section != (lang_output_section_statement_type *)NULL) { | |
218 | + new.value -= section->bfd_section->vma; | |
219 | + } | |
220 | + return new; | |
221 | +} | |
222 | + | |
223 | +static etree_value_type | |
224 | +fold_binary(tree, current_section, allocation_done, dot, dotp) | |
225 | +etree_type *tree; | |
226 | +lang_output_section_statement_type *current_section; | |
227 | +lang_phase_type allocation_done; | |
228 | +bfd_vma dot; | |
229 | +bfd_vma *dotp; | |
230 | +{ | |
231 | + etree_value_type result; | |
232 | + | |
233 | + result = exp_fold_tree(tree->binary.lhs, current_section, | |
234 | + allocation_done, dot, dotp); | |
235 | + if (result.valid) { | |
236 | + etree_value_type other; | |
237 | + other = exp_fold_tree(tree->binary.rhs, | |
238 | + current_section, | |
239 | + allocation_done, dot,dotp) ; | |
240 | + if (other.valid) { | |
241 | + /* If values are from different sections, or this is an */ | |
242 | + /* absolute expression, make both source args absolute */ | |
243 | + if (result.section != other.section || | |
244 | + current_section == (lang_output_section_statement_type *)NULL) { | |
245 | + | |
246 | + make_abs(&result); | |
247 | + make_abs(&other); | |
248 | + } | |
249 | + | |
250 | + switch (tree->type.node_code) | |
251 | + { | |
252 | + case '%': | |
253 | + /* Mod, both absolule*/ | |
254 | + | |
255 | + if (other.value == 0) { | |
256 | + info("%F%S % by zero\n"); | |
257 | + } | |
258 | + result.value %= other.value; | |
259 | + break; | |
260 | + case '/': | |
261 | + if (other.value == 0) { | |
262 | + info("%F%S / by zero\n"); | |
263 | + } | |
264 | + result.value /= other.value; | |
265 | + break; | |
266 | +#define BOP(x,y) case x : result.value = result.value y other.value;break; | |
267 | + BOP('+',+); | |
268 | + BOP('*',*); | |
269 | + BOP('-',-); | |
270 | + BOP(LSHIFT,<<); | |
271 | + BOP(RSHIFT,>>); | |
272 | + BOP(EQ,==); | |
273 | + BOP(NE,!=); | |
274 | + BOP('<',<); | |
275 | + BOP('>',>); | |
276 | + BOP(LE,<=); | |
277 | + BOP(GE,>=); | |
278 | + BOP('&',&); | |
279 | + BOP('^',^); | |
280 | + BOP('|',|); | |
281 | + BOP(ANDAND,&&); | |
282 | + BOP(OROR,||); | |
283 | + default: | |
284 | + FAIL(); | |
285 | + } | |
286 | + } | |
287 | + } | |
288 | + return result; | |
289 | +} | |
290 | +etree_value_type invalid() | |
291 | +{ | |
292 | + etree_value_type new; | |
293 | + new.valid = false; | |
294 | + return new; | |
295 | +} | |
296 | + | |
297 | +etree_value_type fold_name(tree, current_section, allocation_done, dot) | |
298 | +etree_type *tree; | |
299 | +lang_output_section_statement_type *current_section; | |
300 | +lang_phase_type allocation_done; | |
301 | +bfd_vma dot; | |
302 | + | |
303 | +{ | |
304 | + etree_value_type result; | |
305 | + switch (tree->type.node_code) | |
306 | + { | |
307 | + case DEFINED: | |
308 | + result.value = | |
309 | + ldsym_get_soft(tree->name.name) != (ldsym_type *)NULL; | |
310 | + result.section = 0; | |
311 | + result.valid = true; | |
312 | + break; | |
313 | + case NAME: | |
314 | + result.valid = false; | |
315 | + if (tree->name.name[0] == '.' && tree->name.name[1] == 0) { | |
316 | + | |
317 | + if (allocation_done != lang_first_phase_enum) { | |
318 | + result = new_rel_from_section(dot, current_section); | |
319 | + } | |
320 | + else { | |
321 | + result = invalid(); | |
322 | + } | |
323 | + } | |
324 | + else { | |
325 | + if (allocation_done == lang_final_phase_enum) { | |
326 | + ldsym_type *sy = ldsym_get_soft(tree->name.name); | |
327 | + | |
328 | + if (sy) { | |
329 | + asymbol **sdefp = sy->sdefs_chain; | |
330 | + | |
331 | + if (sdefp) { | |
332 | + asymbol *sdef = *sdefp; | |
333 | + if (sdef->section == (asection *)NULL) { | |
334 | + /* This is an absolute symbol */ | |
335 | + result = new_abs(sdef->value); | |
336 | + } | |
337 | + else { | |
338 | + lang_output_section_statement_type *os = | |
339 | + lang_output_section_statement_lookup( sdef->section->output_section->name); | |
340 | + result = new_rel(sdef->value, os); | |
341 | + } | |
342 | + } | |
343 | + } | |
344 | + if (result.valid == false) { | |
345 | + info("%F%S: undefined symbol `%s' referenced in expression.\n", | |
346 | + tree->name.name); | |
347 | + } | |
348 | + | |
349 | + } | |
350 | + } | |
351 | + | |
352 | + break; | |
353 | + | |
354 | + case ADDR: | |
355 | + | |
356 | + if (allocation_done != lang_first_phase_enum) { | |
357 | + lang_output_section_statement_type *os = | |
358 | + lang_output_section_find(tree->name.name); | |
359 | + check(os); | |
360 | + result = new_rel((bfd_vma)0, os); | |
361 | + } | |
362 | + else { | |
363 | + result = invalid(); | |
364 | + } | |
365 | + break; | |
366 | + case SIZEOF: | |
367 | + if(allocation_done != lang_first_phase_enum) { | |
368 | + lang_output_section_statement_type *os = | |
369 | + lang_output_section_find(tree->name.name); | |
370 | + check(os); | |
371 | + result = new_abs((bfd_vma)(os->bfd_section->size)); | |
372 | + } | |
373 | + else { | |
374 | + result = invalid(); | |
375 | + } | |
376 | + break; | |
377 | + | |
378 | + default: | |
379 | + FAIL(); | |
380 | + break; | |
381 | + } | |
382 | + | |
383 | + return result; | |
384 | +} | |
385 | +etree_value_type exp_fold_tree(tree, current_section, allocation_done, | |
386 | + dot, dotp) | |
387 | +etree_type *tree; | |
388 | +lang_output_section_statement_type *current_section; | |
389 | +lang_phase_type allocation_done; | |
390 | +bfd_vma dot; | |
391 | +bfd_vma *dotp; | |
392 | +{ | |
393 | + etree_value_type result; | |
394 | + | |
395 | + if (tree == (etree_type *)NULL) { | |
396 | + result.valid = false; | |
397 | + } | |
398 | + else { | |
399 | + switch (tree->type.node_class) | |
400 | + { | |
401 | + case etree_value: | |
402 | + result = new_rel(tree->value.value, current_section); | |
403 | + break; | |
404 | + case etree_unary: | |
405 | + result = exp_fold_tree(tree->unary.child, | |
406 | + current_section, | |
407 | + allocation_done, dot, dotp); | |
408 | + if (result.valid == true) | |
409 | + { | |
410 | + switch(tree->type.node_code) | |
411 | + { | |
412 | + case ALIGN_K: | |
413 | + if (allocation_done != lang_first_phase_enum) { | |
414 | + result = new_rel_from_section(ALIGN(dot, | |
415 | + result.value) , | |
416 | + current_section); | |
417 | + | |
418 | + } | |
419 | + else { | |
420 | + result.valid = false; | |
421 | + } | |
422 | + break; | |
423 | + case '-': | |
424 | + result.value = -result.value; | |
425 | + break; | |
426 | + case NEXT: | |
427 | + result.valid = false; | |
428 | + break; | |
429 | + default: | |
430 | + FAIL(); | |
431 | + } | |
432 | + } | |
433 | + | |
434 | + break; | |
435 | + case etree_trinary: | |
436 | + | |
437 | + result = exp_fold_tree(tree->trinary.cond, | |
438 | + current_section, | |
439 | + allocation_done, dot, dotp); | |
440 | + if (result.valid) { | |
441 | + result = exp_fold_tree(result.value ? | |
442 | + tree->trinary.lhs:tree->trinary.rhs, | |
443 | + current_section, | |
444 | + allocation_done, dot, dotp); | |
445 | + } | |
446 | + | |
447 | + break; | |
448 | + case etree_binary: | |
449 | + result = fold_binary(tree, current_section, allocation_done, | |
450 | + dot, dotp); | |
451 | + break; | |
452 | + case etree_assign: | |
453 | + if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) { | |
454 | + /* Assignment to dot can only be done during allocation */ | |
455 | + if (allocation_done == lang_allocating_phase_enum) { | |
456 | + result = exp_fold_tree(tree->assign.src, | |
457 | + current_section, | |
458 | + lang_allocating_phase_enum, dot, dotp); | |
459 | + if (result.valid == false) { | |
460 | + info("%F%S invalid assignment to location counter\n"); | |
461 | + } | |
462 | + else { | |
463 | + if (current_section == | |
464 | + (lang_output_section_statement_type *)NULL) { | |
465 | + info("%F%S assignment to location counter invalid outside of SECTION\n"); | |
466 | + } | |
467 | + else { | |
468 | + unsigned long nextdot =result.value + | |
469 | + current_section->bfd_section->vma; | |
470 | + if (nextdot < dot) { | |
471 | + info("%F%S cannot move location counter backwards"); | |
472 | + } | |
473 | + else { | |
474 | + *dotp = nextdot; | |
475 | + } | |
476 | + } | |
477 | + } | |
478 | + } | |
479 | + } | |
480 | + else { | |
481 | + ldsym_type *sy = ldsym_get(tree->assign.dst); | |
482 | + | |
483 | + /* If this symbol has just been created then we'll place it into | |
484 | + * a section of our choice | |
485 | + */ | |
486 | + result = exp_fold_tree(tree->assign.src, | |
487 | + current_section, allocation_done, | |
488 | + dot, dotp); | |
489 | + if (result.valid) | |
490 | + { | |
491 | + asymbol *def; | |
492 | + asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **)); | |
493 | + /* Add this definition to script file */ | |
494 | + def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd); | |
495 | + *def_ptr = def; | |
496 | + | |
497 | + | |
498 | + def->value = result.value; | |
499 | + if (result.section != | |
500 | + (lang_output_section_statement_type *)NULL) { | |
501 | + if (current_section != | |
502 | + (lang_output_section_statement_type *)NULL) { | |
503 | + | |
504 | + def->section = result.section->bfd_section; | |
505 | + def->flags = BSF_GLOBAL | BSF_EXPORT; | |
506 | + } | |
507 | + else { | |
508 | + /* Force to absolute */ | |
509 | + def->value += result.section->bfd_section->vma; | |
510 | + def->section = (asection *)NULL; | |
511 | + def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE; | |
512 | + } | |
513 | + | |
514 | + | |
515 | + } | |
516 | + else { | |
517 | + def->section = (asection *)NULL; | |
518 | + def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE; | |
519 | + } | |
520 | + | |
521 | + | |
522 | + def->udata = (void *)NULL; | |
523 | + def->name = sy->name; | |
524 | + Q_enter_global_ref(def_ptr); | |
525 | + } | |
526 | + | |
527 | + } | |
528 | + | |
529 | + | |
530 | + break; | |
531 | + case etree_name: | |
532 | + result = fold_name(tree, current_section, allocation_done, dot); | |
533 | + break; | |
534 | + default: | |
535 | + info("%F%S Need more of these %d",tree->type.node_class ); | |
536 | + | |
537 | + } | |
538 | + } | |
539 | + | |
540 | + return result; | |
541 | +} | |
542 | + | |
543 | + | |
544 | +etree_value_type exp_fold_tree_no_dot(tree, current_section, allocation_done) | |
545 | +etree_type *tree; | |
546 | +lang_output_section_statement_type *current_section; | |
547 | +lang_phase_type allocation_done; | |
548 | +{ | |
549 | +return exp_fold_tree(tree, current_section, allocation_done, (bfd_vma) | |
550 | + 0, (bfd_vma *)NULL); | |
551 | +} | |
552 | + | |
553 | +etree_type * | |
554 | +exp_binop(code, lhs, rhs) | |
555 | +int code; | |
556 | +etree_type *lhs; | |
557 | +etree_type *rhs; | |
558 | +{ | |
559 | + etree_type value, *new; | |
560 | + etree_value_type r; | |
561 | + | |
562 | + value.type.node_code = code; | |
563 | + value.binary.lhs = lhs; | |
564 | + value.binary.rhs = rhs; | |
565 | + value.type.node_class = etree_binary; | |
566 | + r = exp_fold_tree_no_dot(&value, (lang_output_section_statement_type *)NULL, | |
567 | + lang_first_phase_enum ); | |
568 | + if (r.valid) | |
569 | + { | |
570 | + return exp_intop(r.value); | |
571 | + } | |
572 | + new = (etree_type *)ldmalloc(sizeof(new->binary)); | |
573 | + memcpy((char *)new, (char *)&value, sizeof(new->binary)); | |
574 | + return new; | |
575 | +} | |
576 | + | |
577 | +etree_type * | |
578 | +exp_trinop(code, cond, lhs, rhs) | |
579 | +int code; | |
580 | +etree_type *cond; | |
581 | +etree_type *lhs; | |
582 | +etree_type *rhs; | |
583 | +{ | |
584 | + etree_type value, *new; | |
585 | + etree_value_type r; | |
586 | + value.type.node_code = code; | |
587 | + value.trinary.lhs = lhs; | |
588 | + value.trinary.cond = cond; | |
589 | + value.trinary.rhs = rhs; | |
590 | + value.type.node_class = etree_trinary; | |
591 | + r= exp_fold_tree_no_dot(&value, (lang_output_section_statement_type | |
592 | + *)NULL,lang_first_phase_enum); | |
593 | + if (r.valid) { | |
594 | + return exp_intop(r.value); | |
595 | + } | |
596 | + new = (etree_type *)ldmalloc(sizeof(new->trinary)); | |
597 | + memcpy((char *)new,(char *) &value, sizeof(new->trinary)); | |
598 | + return new; | |
599 | +} | |
600 | + | |
601 | + | |
602 | +etree_type * | |
603 | +exp_unop(code, child) | |
604 | +int code; | |
605 | +etree_type *child; | |
606 | +{ | |
607 | + etree_type value, *new; | |
608 | + | |
609 | + etree_value_type r; | |
610 | + value.unary.type.node_code = code; | |
611 | + value.unary.child = child; | |
612 | + value.unary.type.node_class = etree_unary; | |
613 | +r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL, | |
614 | + lang_first_phase_enum); | |
615 | +if (r.valid) { | |
616 | + return exp_intop(r.value); | |
617 | + } | |
618 | + new = (etree_type *)ldmalloc(sizeof(new->unary)); | |
619 | + memcpy((char *)new, (char *)&value, sizeof(new->unary)); | |
620 | + return new; | |
621 | +} | |
622 | + | |
623 | + | |
624 | +etree_type * | |
625 | +exp_nameop(code, name) | |
626 | +int code; | |
627 | +char *name; | |
628 | +{ | |
629 | + | |
630 | + etree_type value, *new; | |
631 | + | |
632 | + etree_value_type r; | |
633 | + value.name.type.node_code = code; | |
634 | + value.name.name = name; | |
635 | + value.name.type.node_class = etree_name; | |
636 | + | |
637 | + | |
638 | + r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL, | |
639 | + lang_first_phase_enum); | |
640 | + if (r.valid) { | |
641 | + return exp_intop(r.value); | |
642 | + } | |
643 | + new = (etree_type *)ldmalloc(sizeof(new->name)); | |
644 | + memcpy((char *)new, (char *)&value, sizeof(new->name)); | |
645 | + return new; | |
646 | + | |
647 | +} | |
648 | + | |
649 | + | |
650 | + | |
651 | + | |
652 | +etree_type * | |
653 | +exp_assop(code, dst, src) | |
654 | +int code; | |
655 | +char *dst; | |
656 | +etree_type *src; | |
657 | +{ | |
658 | + etree_type value, *new; | |
659 | + | |
660 | + value.assign.type.node_code = code; | |
661 | + | |
662 | + | |
663 | + value.assign.src = src; | |
664 | + value.assign.dst = dst; | |
665 | + value.assign.type.node_class = etree_assign; | |
666 | + | |
667 | +#if 0 | |
668 | + if (exp_fold_tree_no_dot(&value, &result)) { | |
669 | + return exp_intop(result); | |
670 | + } | |
671 | +#endif | |
672 | + new = (etree_type*)ldmalloc(sizeof(new->assign)); | |
673 | + memcpy((char *)new, (char *)&value, sizeof(new->assign)); | |
674 | + return new; | |
675 | +} | |
676 | + | |
677 | +void | |
678 | +exp_print_tree(outfile, tree) | |
679 | +FILE *outfile; | |
680 | +etree_type *tree; | |
681 | +{ | |
682 | + switch (tree->type.node_class) { | |
683 | + case etree_value: | |
684 | + fprintf(outfile,"0x%08lx",(bfd_vma)(tree->value.value)); | |
685 | + return; | |
686 | + case etree_assign: | |
687 | +#if 0 | |
688 | + if (tree->assign.dst->sdefs != (asymbol *)NULL){ | |
689 | + fprintf(outfile,"%s (%x) ",tree->assign.dst->name, | |
690 | + tree->assign.dst->sdefs->value); | |
691 | + } | |
692 | + else { | |
693 | + fprintf(outfile,"%s (UNDEFINED)",tree->assign.dst->name); | |
694 | + } | |
695 | +#endif | |
696 | + fprintf(outfile,"%s ",tree->assign.dst); | |
697 | + exp_print_token(outfile,tree->type.node_code); | |
698 | + exp_print_tree(outfile,tree->assign.src); | |
699 | + break; | |
700 | + case etree_binary: | |
701 | + exp_print_tree(outfile,tree->binary.lhs); | |
702 | + exp_print_token(outfile,tree->type.node_code); | |
703 | + exp_print_tree(outfile,tree->binary.rhs); | |
704 | + break; | |
705 | + case etree_trinary: | |
706 | + exp_print_tree(outfile,tree->trinary.cond); | |
707 | + fprintf(outfile,"?"); | |
708 | + exp_print_tree(outfile,tree->trinary.lhs); | |
709 | + fprintf(outfile,":"); | |
710 | + exp_print_tree(outfile,tree->trinary.rhs); | |
711 | + break; | |
712 | + case etree_unary: | |
713 | + exp_print_token(outfile,tree->unary.type.node_code); | |
714 | + fprintf(outfile,"("); | |
715 | + exp_print_tree(outfile,tree->unary.child); | |
716 | + fprintf(outfile,")"); | |
717 | + break; | |
718 | + case etree_undef: | |
719 | + fprintf(outfile,"????????"); | |
720 | + break; | |
721 | + case etree_name: | |
722 | + if (tree->type.node_code == NAME) { | |
723 | + fprintf(outfile,"%s", tree->name.name); | |
724 | + } | |
725 | + else { | |
726 | + exp_print_token(outfile,tree->type.node_code); | |
727 | + fprintf(outfile,"(%s)", tree->name.name); | |
728 | + } | |
729 | + break; | |
730 | + default: | |
731 | + FAIL(); | |
732 | + break; | |
733 | + } | |
734 | +} | |
735 | + | |
736 | + | |
737 | + | |
738 | + | |
739 | +bfd_vma | |
740 | +exp_get_vma(tree, def, name, allocation_done) | |
741 | +etree_type *tree; | |
742 | +bfd_vma def; | |
743 | +char *name; | |
744 | +lang_phase_type allocation_done; | |
745 | +{ | |
746 | + etree_value_type r; | |
747 | + | |
748 | + if (tree != (etree_type *)NULL) { | |
749 | + r = exp_fold_tree_no_dot(tree, | |
750 | + (lang_output_section_statement_type *)NULL, | |
751 | + allocation_done); | |
752 | + if (r.valid == false && name) { | |
753 | + info("%F%S Nonconstant expression for %s\n",name); | |
754 | + } | |
755 | + return r.value; | |
756 | + } | |
757 | + else { | |
758 | + return def; | |
759 | + } | |
760 | +} | |
761 | + | |
762 | +int | |
763 | +exp_get_value_int(tree,def,name, allocation_done) | |
764 | +etree_type *tree; | |
765 | +int def; | |
766 | +char *name; | |
767 | +lang_phase_type allocation_done; | |
768 | +{ | |
769 | + return (int)exp_get_vma(tree,(bfd_vma)def,name, allocation_done); | |
770 | +} |
@@ -0,0 +1,99 @@ | ||
1 | +/* ldexp.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | + | |
23 | + | |
24 | +/* The result of an expression tree */ | |
25 | +typedef struct | |
26 | +{ | |
27 | + bfd_vma value; | |
28 | + struct lang_output_section_statement_struct *section; | |
29 | + boolean valid; | |
30 | +} etree_value_type; | |
31 | + | |
32 | + | |
33 | + | |
34 | +typedef struct | |
35 | +{ | |
36 | + int node_code; | |
37 | + enum { etree_binary, | |
38 | + etree_trinary, | |
39 | + etree_unary, | |
40 | + etree_name, | |
41 | + etree_assign, | |
42 | + etree_undef, | |
43 | + etree_unspec, | |
44 | + etree_value } node_class; | |
45 | +} node_type; | |
46 | + | |
47 | + | |
48 | + | |
49 | +typedef union etree_union | |
50 | +{ | |
51 | + node_type type; | |
52 | + struct { | |
53 | + node_type type; | |
54 | + union etree_union *lhs; | |
55 | + union etree_union *rhs; | |
56 | + } binary; | |
57 | + struct { | |
58 | + node_type type; | |
59 | + union etree_union *cond; | |
60 | + union etree_union *lhs; | |
61 | + union etree_union *rhs; | |
62 | + } trinary; | |
63 | + struct { | |
64 | + node_type type; | |
65 | + char *dst; | |
66 | + union etree_union *src; | |
67 | + } assign; | |
68 | + | |
69 | + struct { | |
70 | + node_type type; | |
71 | + union etree_union *child; | |
72 | + } unary; | |
73 | + struct { | |
74 | + node_type type; | |
75 | + char *name; | |
76 | + } name; | |
77 | + struct { | |
78 | + node_type type; | |
79 | + bfd_vma value; | |
80 | + } value; | |
81 | + | |
82 | +} etree_type; | |
83 | + | |
84 | + | |
85 | +PROTO(etree_type *,exp_intop,(bfd_vma)); | |
86 | + | |
87 | +PROTO(etree_value_type, invalid,(void)); | |
88 | +PROTO(etree_value_type, exp_fold_tree,(etree_type *, struct | |
89 | + lang_output_section_statement_struct *, lang_phase_type, | |
90 | + bfd_vma, bfd_vma *)); | |
91 | + | |
92 | +PROTO(etree_type *, exp_binop,(int, etree_type *, etree_type *)); | |
93 | +PROTO(etree_type *,exp_trinop,(int,etree_type *, etree_type *, etree_type *)); | |
94 | +PROTO(etree_type *,exp_unop,(int, etree_type *)); | |
95 | +PROTO(etree_type *,exp_nameop,(int, char *)); | |
96 | +PROTO(etree_type *,exp_assop,(int, char *, etree_type *)); | |
97 | +PROTO(void, exp_print_tree,(struct _iobuf *, etree_type *)); | |
98 | +PROTO(bfd_vma, exp_get_vma,(etree_type *, bfd_vma, char *, enum boolean)); | |
99 | +PROTO(int, exp_get_value_int,(etree_type *, int, char *, enum boolean)); |
@@ -0,0 +1,284 @@ | ||
1 | + | |
2 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
3 | + | |
4 | +This file is part of GLD, the Gnu Linker. | |
5 | + | |
6 | +GLD is free software; you can redistribute it and/or modify | |
7 | +it under the terms of the GNU General Public License as published by | |
8 | +the Free Software Foundation; either version 1, or (at your option) | |
9 | +any later version. | |
10 | + | |
11 | +GLD is distributed in the hope that it will be useful, | |
12 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | +GNU General Public License for more details. | |
15 | + | |
16 | +You should have received a copy of the GNU General Public License | |
17 | +along with GLD; see the file COPYING. If not, write to | |
18 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | + | |
20 | +/* | |
21 | + $Id$ | |
22 | + | |
23 | + $Log$ | |
24 | + Revision 1.1 1991/03/21 21:28:37 gumby | |
25 | + Initial revision | |
26 | + | |
27 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
28 | + * foo | |
29 | + * | |
30 | + * Revision 1.1 1991/03/13 00:48:18 chrisb | |
31 | + * Initial revision | |
32 | + * | |
33 | + * Revision 1.4 1991/03/10 09:31:24 rich | |
34 | + * Modified Files: | |
35 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
36 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
37 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
38 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
39 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
40 | + * | |
41 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
42 | + * interest and copy passes my copy test on big endian hosts again. | |
43 | + * | |
44 | + * Revision 1.3 1991/02/22 17:15:00 sac | |
45 | + * Added RCS keywords and copyrights | |
46 | + * | |
47 | +*/ | |
48 | + | |
49 | +/* | |
50 | + ldfile.c | |
51 | + | |
52 | + look after all the file stuff | |
53 | + | |
54 | + */ | |
55 | + | |
56 | +#include "sysdep.h" | |
57 | +#include "bfd.h" | |
58 | + | |
59 | +#include "ldmisc.h" | |
60 | +#include "ldlang.h" | |
61 | +#include "ldfile.h" | |
62 | + | |
63 | +#include <ctype.h> | |
64 | + | |
65 | +/* EXPORT */ | |
66 | +char *ldfile_input_filename; | |
67 | +char *ldfile_output_machine_name; | |
68 | +unsigned long ldfile_output_machine; | |
69 | +enum bfd_architecture ldfile_output_architecture; | |
70 | +boolean had_script; | |
71 | + | |
72 | +/* IMPORT */ | |
73 | + | |
74 | +extern boolean option_v; | |
75 | + | |
76 | + | |
77 | + | |
78 | + | |
79 | + | |
80 | +/* LOACL */ | |
81 | +typedef struct search_dirs_struct | |
82 | +{ | |
83 | + char *name; | |
84 | + struct search_dirs_struct *next; | |
85 | +} search_dirs_type; | |
86 | + | |
87 | +static search_dirs_type *search_head; | |
88 | +static search_dirs_type **search_tail_ptr = &search_head; | |
89 | + | |
90 | +typedef struct search_arch_struct | |
91 | +{ | |
92 | + char *name; | |
93 | + struct search_arch_struct *next; | |
94 | +} search_arch_type; | |
95 | + | |
96 | +static search_arch_type *search_arch_head; | |
97 | +static search_arch_type **search_arch_tail_ptr = &search_arch_head; | |
98 | + | |
99 | +void | |
100 | +ldfile_add_library_path(name) | |
101 | +char *name; | |
102 | +{ | |
103 | + search_dirs_type *new = | |
104 | + (search_dirs_type *)ldmalloc(sizeof(search_dirs_type)); | |
105 | + new->name = name; | |
106 | + new->next = (search_dirs_type*)NULL; | |
107 | + *search_tail_ptr = new; | |
108 | + search_tail_ptr = &new->next; | |
109 | +} | |
110 | + | |
111 | + | |
112 | +static bfd* | |
113 | +cached_bfd_openr(attempt,entry) | |
114 | +char *attempt; | |
115 | +lang_input_statement_type *entry; | |
116 | +{ | |
117 | + entry->the_bfd = bfd_openr(attempt, entry->target); | |
118 | + | |
119 | + | |
120 | + return entry->the_bfd; | |
121 | +} | |
122 | + | |
123 | +static bfd * | |
124 | +open_a(arch, entry, lib, suffix) | |
125 | +char *arch; | |
126 | +lang_input_statement_type *entry; | |
127 | +char *lib; | |
128 | +char *suffix; | |
129 | +{ | |
130 | + bfd*desc; | |
131 | + search_dirs_type *search ; | |
132 | + for (search = search_head; | |
133 | + search != (search_dirs_type *)NULL; | |
134 | + search = search->next) | |
135 | + { | |
136 | + char buffer[1000]; | |
137 | + char *string; | |
138 | + if (entry->is_archive == true) { | |
139 | + sprintf(buffer, | |
140 | + "%s/%s%s%s%s", | |
141 | + search->name, | |
142 | + lib, | |
143 | + entry->filename, arch, suffix); | |
144 | + } | |
145 | + else { | |
146 | + if (entry->filename[0] == '/') { | |
147 | + strcpy(buffer, entry->filename); | |
148 | + } else { | |
149 | + sprintf(buffer,"%s/%s",search->name, entry->filename); | |
150 | + } /* */ | |
151 | + } | |
152 | + string = buystring(buffer); | |
153 | + desc = cached_bfd_openr (string, entry); | |
154 | + if (desc) | |
155 | + { | |
156 | + entry->filename = string; | |
157 | + entry->search_dirs_flag = false; | |
158 | + entry->the_bfd = desc; | |
159 | + return desc; | |
160 | + } | |
161 | + free(string); | |
162 | + } | |
163 | + return (bfd *)NULL; | |
164 | +} | |
165 | + | |
166 | +/* Open the input file specified by 'entry', and return a descriptor. | |
167 | + The open file is remembered; if the same file is opened twice in a row, | |
168 | + a new open is not actually done. */ | |
169 | + | |
170 | +void | |
171 | +ldfile_open_file (entry) | |
172 | +lang_input_statement_type *entry; | |
173 | +{ | |
174 | + | |
175 | + if (entry->superfile) | |
176 | + ldfile_open_file (entry->superfile); | |
177 | + | |
178 | + if (entry->search_dirs_flag) | |
179 | + { | |
180 | + search_arch_type *arch; | |
181 | + for (arch = search_arch_head; | |
182 | + arch != (search_arch_type *)NULL; | |
183 | + arch = arch->next) { | |
184 | + if (open_a(arch->name,entry,"","") != (bfd *)NULL) { | |
185 | + return; | |
186 | + } | |
187 | + if (open_a(arch->name,entry,"lib",".a") != (bfd *)NULL) { | |
188 | + return; | |
189 | + } | |
190 | + | |
191 | + } | |
192 | + | |
193 | + | |
194 | + } | |
195 | + else { | |
196 | + entry->the_bfd = cached_bfd_openr (entry->filename, entry); | |
197 | + | |
198 | + } | |
199 | + if (!entry->the_bfd) info("%F%P: %E %I\n", entry); | |
200 | + | |
201 | +} | |
202 | + | |
203 | + | |
204 | + | |
205 | + | |
206 | + | |
207 | + | |
208 | +static FILE * | |
209 | +try_open(name, exten) | |
210 | +char *name; | |
211 | +char *exten; | |
212 | +{ | |
213 | + FILE *result; | |
214 | + char buff[1000]; | |
215 | + result = fopen(name, "r"); | |
216 | + if (result && option_v == true) { | |
217 | + info("%s\n",name); | |
218 | + return result; | |
219 | + } | |
220 | + sprintf(buff, "%s%s", name, exten); | |
221 | + result = fopen(buff, "r"); | |
222 | + | |
223 | + if (result && option_v == true) { | |
224 | + info("%s\n", buff); | |
225 | + } | |
226 | + return result; | |
227 | +} | |
228 | +static FILE * | |
229 | +find_a_name(name, extend) | |
230 | +char *name; | |
231 | +char *extend; | |
232 | +{ | |
233 | + search_dirs_type *search; | |
234 | + FILE *result; | |
235 | + char buffer[1000]; | |
236 | + /* First try raw name */ | |
237 | + result = try_open(name,""); | |
238 | + if (result == (FILE *)NULL) { | |
239 | + /* Try now prefixes */ | |
240 | + for (search = search_head; | |
241 | + search != (search_dirs_type *)NULL; | |
242 | + search = search->next) { | |
243 | + sprintf(buffer,"%s/%s", search->name, name); | |
244 | + result = try_open(buffer, extend); | |
245 | + if (result)break; | |
246 | + } | |
247 | + } | |
248 | + return result; | |
249 | +} | |
250 | + | |
251 | +void ldfile_open_command_file(name) | |
252 | +char *name; | |
253 | +{ | |
254 | + extern FILE *ldlex_input_stack; | |
255 | + ldlex_input_stack = find_a_name(name, ".ld"); | |
256 | + | |
257 | + if (ldlex_input_stack == (FILE *)NULL) { | |
258 | + info("%P%F cannot open load script file %s\n",name); | |
259 | + } | |
260 | + ldfile_input_filename = name; | |
261 | + had_script = true; | |
262 | +} | |
263 | + | |
264 | + | |
265 | + | |
266 | + | |
267 | +void | |
268 | +ldfile_add_arch(name) | |
269 | +char *name; | |
270 | +{ | |
271 | + search_arch_type *new = | |
272 | + (search_arch_type *)ldmalloc(sizeof(search_arch_type)); | |
273 | + ldfile_output_machine_name = name; | |
274 | + | |
275 | + new->name = name; | |
276 | + new->next = (search_arch_type*)NULL; | |
277 | + while (*name) { | |
278 | + if (isupper(*name)) *name = tolower(*name); | |
279 | + name++; | |
280 | + } | |
281 | + *search_arch_tail_ptr = new; | |
282 | + search_arch_tail_ptr = &new->next; | |
283 | + | |
284 | +} |
@@ -0,0 +1,27 @@ | ||
1 | +/* ldfile.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | + | |
23 | +PROTO(void,ldfile_add_arch,(char *)); | |
24 | +PROTO(void,ldfile_add_library_path,(char *)); | |
25 | +PROTO(void,ldfile_open_command_file,(char *name)); | |
26 | +PROTO(void,ldfile_open_file,(struct lang_input_statement_struct *)); | |
27 | + |
@@ -0,0 +1,693 @@ | ||
1 | +%{ | |
2 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
3 | + | |
4 | +This file is part of GLD, the Gnu Linker. | |
5 | + | |
6 | +GLD is free software; you can redistribute it and/or modify | |
7 | +it under the terms of the GNU General Public License as published by | |
8 | +the Free Software Foundation; either version 1, or (at your option) | |
9 | +any later version. | |
10 | + | |
11 | +GLD is distributed in the hope that it will be useful, | |
12 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | +GNU General Public License for more details. | |
15 | + | |
16 | +You should have received a copy of the GNU General Public License | |
17 | +along with GLD; see the file COPYING. If not, write to | |
18 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | + | |
20 | +/* | |
21 | + * $Id$ | |
22 | + * | |
23 | + * $Log$ | |
24 | + * Revision 1.1 1991/03/21 21:28:41 gumby | |
25 | + * Initial revision | |
26 | + * | |
27 | + * Revision 1.2 1991/03/16 22:27:24 rich | |
28 | + * fish | |
29 | + * | |
30 | + * Revision 1.1 1991/03/13 00:48:21 chrisb | |
31 | + * Initial revision | |
32 | + * | |
33 | + * Revision 1.6 1991/03/10 09:31:26 rich | |
34 | + * Modified Files: | |
35 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
36 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
37 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
38 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
39 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
40 | + * | |
41 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
42 | + * interest and copy passes my copy test on big endian hosts again. | |
43 | + * | |
44 | + * Revision 1.5 1991/03/09 03:25:48 sac | |
45 | + * Can now parse the -Ur flag | |
46 | + * | |
47 | + * Revision 1.4 1991/03/06 02:26:01 sac | |
48 | + * Added support for constructor sections. | |
49 | + * Remove parsing ambiguity. | |
50 | + * Lint | |
51 | + * | |
52 | + * Revision 1.3 1991/02/22 17:15:13 sac | |
53 | + * Added RCS keywords and copyrights | |
54 | + * | |
55 | +*/ | |
56 | + | |
57 | +/* | |
58 | + This is a YACC grammer intended to parse a superset of the AT&T | |
59 | + linker scripting languaue. | |
60 | + | |
61 | + | |
62 | + Written by Steve Chamberlain steve@cygnus.com | |
63 | +*/ | |
64 | + | |
65 | + | |
66 | +/*SUPPRESS 166*/ | |
67 | +/*SUPPRESS 112*/ | |
68 | + | |
69 | +#include "sysdep.h" | |
70 | +#include "bfd.h" | |
71 | + | |
72 | +#include "ld.h" | |
73 | +#include "ldexp.h" | |
74 | +#include "ldversion.h" | |
75 | +#include "ldlang.h" | |
76 | +#include "ld-emul.h" | |
77 | +#include "ldfile.h" | |
78 | +#include "ldmisc.h" | |
79 | +#define YYDEBUG 1 | |
80 | + | |
81 | +boolean option_v; | |
82 | + | |
83 | + | |
84 | +extern unsigned int lineno; | |
85 | +extern boolean trace_files; | |
86 | +extern boolean write_map; | |
87 | + | |
88 | +boolean hex_mode; | |
89 | + | |
90 | + | |
91 | + | |
92 | + | |
93 | +lang_memory_region_type *region; | |
94 | + | |
95 | + | |
96 | +lang_memory_region_type *lang_memory_region_lookup(); | |
97 | +lang_output_section_statement_type *lang_output_section_statement_lookup(); | |
98 | + | |
99 | +#ifdef __STDC__ | |
100 | + | |
101 | +void lang_add_data(int type, union etree_union *exp); | |
102 | +void lang_enter_output_section_statement(char *output_section_statement_name, etree_type *address_exp, bfd_vma block_value); | |
103 | + | |
104 | +#else | |
105 | + | |
106 | +void lang_add_data(); | |
107 | +void lang_enter_output_section_statement(); | |
108 | + | |
109 | +#endif /* __STDC__ */ | |
110 | + | |
111 | +extern args_type command_line; | |
112 | +char *current_file; | |
113 | +boolean ldgram_want_filename = true; | |
114 | +boolean had_script = false; | |
115 | +boolean force_make_executable = false; | |
116 | +boolean ldgram_mustbe_filename = false; | |
117 | +boolean ldgram_mustbe_symbolname = false; | |
118 | +boolean ldgram_has_inputfile = false; | |
119 | + | |
120 | +/* LOCALS */ | |
121 | + | |
122 | + | |
123 | + | |
124 | + | |
125 | +%} | |
126 | +%union { | |
127 | + bfd_vma integer; | |
128 | + int voidval; | |
129 | + char *name; | |
130 | + int token; | |
131 | + union etree_union *etree; | |
132 | + asection *section; | |
133 | + struct lang_output_section_statement_struct *output_section_statement; | |
134 | + union lang_statement_union **statement_ptr; | |
135 | + int lineno; | |
136 | + struct { | |
137 | + FILE *file; | |
138 | + char *name; | |
139 | + unsigned int lineno; | |
140 | + } state; | |
141 | + | |
142 | + | |
143 | +} | |
144 | + | |
145 | +%type <etree> exp opt_exp exp_head | |
146 | +%type <integer> fill_opt opt_block | |
147 | +%type <name> memspec_opt | |
148 | +%token <integer> INT CHAR | |
149 | +%token <name> NAME | |
150 | +%type <integer> length | |
151 | + | |
152 | +%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ | |
153 | +%right <token> '?' ':' | |
154 | +%left <token> OROR | |
155 | +%left <token> ANDAND | |
156 | +%left <token> '|' | |
157 | +%left <token> '^' | |
158 | +%left <token> '&' | |
159 | +%left <token> EQ NE | |
160 | +%left <token> '<' '>' LE GE | |
161 | +%left <token> LSHIFT RSHIFT | |
162 | +%left <token> '+' '-' | |
163 | +%left <token> '*' '/' '%' | |
164 | +%right UNARY | |
165 | +%left <token> '(' | |
166 | +%token <token> ALIGN_K BLOCK LONG SHORT BYTE | |
167 | +%token SECTIONS | |
168 | +%token '{' '}' | |
169 | +%token ALIGNMENT SIZEOF_HEADERS | |
170 | +%token NEXT SIZEOF ADDR | |
171 | +%token MEMORY | |
172 | +%token DSECT NOLOAD COPY INFO OVERLAY | |
173 | +%token NAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY | |
174 | +%token OPTION_e OPTION_c OPTION_noinhibit_exec OPTION_s OPTION_S OPTION_format | |
175 | +%token OPTION_d OPTION_dc OPTION_dp OPTION_x OPTION_X | |
176 | +%token OPTION_v OPTION_M OPTION_t STARTUP HLL SYSLIB FLOAT NOFLOAT OPTION_defsym | |
177 | +%token OPTION_n OPTION_r OPTION_o OPTION_b OPTION_A | |
178 | +%token <name> OPTION_l OPTION_L OPTION_T OPTION_Aarch OPTION_Tfile OPTION_Texp | |
179 | +%token OPTION_Ur | |
180 | +%token ORIGIN FILL OPTION_g | |
181 | +%token LENGTH BIND SUBSECTION_ALIGN CREATE_OBJECT_SYMBOLS INPUT OUTPUT | |
182 | +%type <token> assign_op SIZEOF NEXT ADDR | |
183 | +%type <etree> assignment | |
184 | +%type <name> filename | |
185 | + | |
186 | +%{ | |
187 | +ld_config_type config; | |
188 | +%} | |
189 | + | |
190 | +%% | |
191 | + | |
192 | + | |
193 | + | |
194 | +file: command_line { lang_final(); }; | |
195 | + | |
196 | + | |
197 | +filename: | |
198 | + { | |
199 | + ldgram_mustbe_filename =true; | |
200 | + } | |
201 | + NAME | |
202 | + { | |
203 | + ldgram_mustbe_filename = false; | |
204 | + $$ = $2; | |
205 | + } | |
206 | + | |
207 | +command_line: | |
208 | + command_line command_line_option | |
209 | + | | |
210 | + ; | |
211 | + | |
212 | +command_line_option: | |
213 | + OPTION_v | |
214 | + { | |
215 | + ldversion(); | |
216 | + option_v = true; | |
217 | + } | |
218 | + | OPTION_t { | |
219 | + trace_files = true; | |
220 | + } | |
221 | + | OPTION_M { | |
222 | + write_map = true; | |
223 | + } | |
224 | + | OPTION_n { | |
225 | + config.magic_demand_paged = false; | |
226 | + config.make_executable = false; | |
227 | + } | |
228 | + | OPTION_s { | |
229 | + strip_symbols = STRIP_ALL; | |
230 | + } | |
231 | + | OPTION_S { | |
232 | + strip_symbols = STRIP_DEBUGGER; | |
233 | + } | |
234 | + | |
235 | + | OPTION_r { | |
236 | + config.relocateable_output = true; | |
237 | + config.build_constructors = false; | |
238 | + config.magic_demand_paged = false; | |
239 | + } | |
240 | + | OPTION_Ur { | |
241 | + config.relocateable_output = true; | |
242 | + config.build_constructors = true; | |
243 | + config.magic_demand_paged = false; | |
244 | + } | |
245 | + | OPTION_o filename | |
246 | + { | |
247 | + lang_add_output($2); | |
248 | + } | |
249 | + | OPTION_e NAME | |
250 | + { lang_add_entry($2); | |
251 | + } | |
252 | + | OPTION_X { | |
253 | + discard_locals = DISCARD_L; | |
254 | + } | |
255 | + | OPTION_x { | |
256 | + discard_locals = DISCARD_ALL; | |
257 | + } | |
258 | + | |
259 | + | OPTION_noinhibit_exec | |
260 | + { | |
261 | + force_make_executable = true; | |
262 | + } | |
263 | + | OPTION_d { | |
264 | + command_line.force_common_definition = true; | |
265 | + } | |
266 | + | OPTION_dc | |
267 | + { | |
268 | + command_line.force_common_definition = true; | |
269 | + } | |
270 | + | OPTION_g | |
271 | + { | |
272 | + /* Ignored */ | |
273 | + } | |
274 | + | OPTION_dp | |
275 | + { | |
276 | + command_line.force_common_definition = true; | |
277 | + } | |
278 | + | OPTION_format NAME | |
279 | + { | |
280 | + lang_add_target($2); | |
281 | + } | |
282 | + | |
283 | + | OPTION_Texp { hex_mode =true; } | |
284 | + exp_head | |
285 | + { lang_section_start($1, $3); | |
286 | + hex_mode = false; } | |
287 | + | |
288 | + | OPTION_Aarch | |
289 | + { ldfile_add_arch($1); } | |
290 | + | OPTION_b NAME | |
291 | + { | |
292 | + lang_add_target($2); | |
293 | + } | |
294 | + | OPTION_L | |
295 | + { | |
296 | + ldfile_add_library_path($1); | |
297 | + } | |
298 | + | ifile_p1 | |
299 | + | input_list | |
300 | + | OPTION_c filename | |
301 | + { ldfile_open_command_file($2); } | |
302 | + | OPTION_Tfile | |
303 | + { ldfile_open_command_file($1); } | |
304 | + | |
305 | + | OPTION_T filename | |
306 | + { ldfile_open_command_file($2); } | |
307 | + | |
308 | + | OPTION_l | |
309 | + { | |
310 | + lang_add_input_file($1, | |
311 | + lang_input_file_is_l_enum, | |
312 | + (char *)NULL); | |
313 | + } | |
314 | + | OPTION_A filename | |
315 | + { | |
316 | + lang_add_input_file($2, | |
317 | + lang_input_file_is_symbols_only_enum, | |
318 | + (char *)NULL); | |
319 | + } | |
320 | + | OPTION_defsym assignment_with_nospaces | |
321 | + ; | |
322 | + | |
323 | + | |
324 | +input_section_spec: | |
325 | + NAME | |
326 | + { | |
327 | + lang_add_wild((char *)NULL, $1); | |
328 | + } | |
329 | + | '[' | |
330 | + { | |
331 | + current_file = (char *)NULL; | |
332 | + } | |
333 | + file_NAME_list | |
334 | + ']' | |
335 | + | NAME | |
336 | + { | |
337 | + current_file =$1; | |
338 | + } | |
339 | + '(' file_NAME_list ')' | |
340 | + | '*' | |
341 | + { | |
342 | + current_file = (char *)NULL; | |
343 | + } | |
344 | + '(' file_NAME_list ')' | |
345 | + ; | |
346 | + | |
347 | + | |
348 | + | |
349 | +file_NAME_list: | |
350 | + NAME | |
351 | + { lang_add_wild($1, current_file); } | |
352 | + | file_NAME_list opt_comma NAME | |
353 | + { lang_add_wild($3, current_file); } | |
354 | + ; | |
355 | + | |
356 | + | |
357 | + | |
358 | +ifile_p1: | |
359 | + memory | |
360 | + | sections | |
361 | + | startup | |
362 | + | high_level_library | |
363 | + | low_level_library | |
364 | + | floating_point_support | |
365 | + | assignment end | |
366 | + | TARGET_K '(' NAME ')' | |
367 | + { lang_add_target($3); } | |
368 | + | SEARCH_DIR '(' filename ')' | |
369 | + { ldfile_add_library_path($3); } | |
370 | + | OUTPUT '(' filename ')' | |
371 | + { lang_add_output($3); } | |
372 | + | INPUT '(' input_list ')' | |
373 | + | MAP '(' filename ')' | |
374 | + { lang_add_map($3); } | |
375 | + ; | |
376 | + | |
377 | +input_list: | |
378 | + NAME | |
379 | + { lang_add_input_file($1,lang_input_file_is_file_enum, | |
380 | + (char *)NULL); } | |
381 | + | input_list ',' NAME | |
382 | + { lang_add_input_file($3,lang_input_file_is_file_enum, | |
383 | + (char *)NULL); } | |
384 | + | input_list NAME | |
385 | + { lang_add_input_file($2, lang_input_file_is_file_enum, | |
386 | + (char *)NULL); } | |
387 | + ; | |
388 | + | |
389 | +sections: | |
390 | + SECTIONS '{'sec_or_group_p1 '}' | |
391 | + ; | |
392 | + | |
393 | +sec_or_group_p1: | |
394 | + sec_or_group_p1 section | |
395 | + | sec_or_group_p1 statement_anywhere | |
396 | + | | |
397 | + ; | |
398 | + | |
399 | +statement_anywhere: | |
400 | + ENTRY '(' NAME ')' | |
401 | + { lang_add_entry($3); } | |
402 | + | assignment end | |
403 | + ; | |
404 | + | |
405 | +statement: | |
406 | + statement assignment end | |
407 | + | statement CREATE_OBJECT_SYMBOLS | |
408 | + { lang_add_attribute(lang_object_symbols_statement_enum); } | |
409 | + | statement input_section_spec | |
410 | + | statement length '(' exp_head ')' | |
411 | + { | |
412 | + lang_add_data($2,$4); | |
413 | + } | |
414 | + | |
415 | + | statement FILL '(' exp_head ')' | |
416 | + { | |
417 | + lang_add_fill | |
418 | + (exp_get_value_int($4, | |
419 | + 0, | |
420 | + "fill value", | |
421 | + lang_first_phase_enum)); | |
422 | + } | |
423 | + | | |
424 | + ; | |
425 | + | |
426 | +length: | |
427 | + LONG | |
428 | + { $$ = $1; } | |
429 | + | SHORT | |
430 | + { $$ = $1; } | |
431 | + | BYTE | |
432 | + { $$ = $1; } | |
433 | + ; | |
434 | + | |
435 | +fill_opt: | |
436 | + '=' exp_head | |
437 | + { | |
438 | + $$ = exp_get_value_int($2, | |
439 | + 0, | |
440 | + "fill value", | |
441 | + lang_first_phase_enum); | |
442 | + } | |
443 | + | { $$ = 0; } | |
444 | + ; | |
445 | + | |
446 | + | |
447 | + | |
448 | +assign_op: | |
449 | + PLUSEQ | |
450 | + { $$ = '+'; } | |
451 | + | MINUSEQ | |
452 | + { $$ = '-'; } | |
453 | + | MULTEQ | |
454 | + { $$ = '*'; } | |
455 | + | DIVEQ | |
456 | + { $$ = '/'; } | |
457 | + | LSHIFTEQ | |
458 | + { $$ = LSHIFT; } | |
459 | + | RSHIFTEQ | |
460 | + { $$ = RSHIFT; } | |
461 | + | ANDEQ | |
462 | + { $$ = '&'; } | |
463 | + | OREQ | |
464 | + { $$ = '|'; } | |
465 | + | |
466 | + ; | |
467 | + | |
468 | +end: ';' | ',' | |
469 | + ; | |
470 | + | |
471 | +assignment_with_nospaces: | |
472 | + { ldgram_want_filename = false; } | |
473 | + assignment | |
474 | + { ldgram_want_filename = true; } | |
475 | + ; | |
476 | + | |
477 | +assignment: | |
478 | + | |
479 | + NAME '=' exp_head | |
480 | + { | |
481 | + lang_add_assignment(exp_assop($2,$1,$3)); | |
482 | + } | |
483 | + | NAME assign_op exp_head | |
484 | + { | |
485 | + lang_add_assignment(exp_assop('=',$1,exp_binop($2,exp_nameop(NAME,$1),$3))); | |
486 | + } | |
487 | + | |
488 | + ; | |
489 | + | |
490 | + | |
491 | +opt_comma: | |
492 | + ',' | ; | |
493 | + | |
494 | + | |
495 | +memory: | |
496 | + MEMORY '{' memory_spec memory_spec_list '}' | |
497 | + ; | |
498 | + | |
499 | +memory_spec_list: | |
500 | + memory_spec_list memory_spec | |
501 | + | memory_spec_list ',' memory_spec | |
502 | + | | |
503 | + ; | |
504 | + | |
505 | + | |
506 | +memory_spec: | |
507 | + NAME | |
508 | + { region = lang_memory_region_lookup($1); } | |
509 | + attributes_opt ':' origin_spec opt_comma length_spec | |
510 | + | |
511 | + { | |
512 | + | |
513 | + | |
514 | + } | |
515 | + ; | |
516 | +origin_spec: | |
517 | + ORIGIN '=' exp | |
518 | + { region->current = | |
519 | + region->origin = | |
520 | + exp_get_vma($3, 0L,"origin", lang_first_phase_enum); } | |
521 | + ; | |
522 | +length_spec: | |
523 | + LENGTH '=' exp | |
524 | + { region->length = exp_get_vma($3, | |
525 | + ~((bfd_vma)0), | |
526 | + "length", | |
527 | + lang_first_phase_enum); | |
528 | + } | |
529 | + | |
530 | + | |
531 | +attributes_opt: | |
532 | + '(' NAME ')' | |
533 | + { | |
534 | + lang_set_flags(®ion->flags, $2); | |
535 | + } | |
536 | + | | |
537 | + | |
538 | + ; | |
539 | + | |
540 | +startup: | |
541 | + STARTUP '(' filename ')' | |
542 | + { lang_startup($3); } | |
543 | + ; | |
544 | + | |
545 | +high_level_library: | |
546 | + HLL '(' high_level_library_NAME_list ')' | |
547 | + | HLL '(' ')' | |
548 | + { ldemul_hll((char *)NULL); } | |
549 | + ; | |
550 | + | |
551 | +high_level_library_NAME_list: | |
552 | + high_level_library_NAME_list opt_comma filename | |
553 | + { ldemul_hll($3); } | |
554 | + | filename | |
555 | + { ldemul_hll($1); } | |
556 | + | |
557 | + ; | |
558 | + | |
559 | +low_level_library: | |
560 | + SYSLIB '(' low_level_library_NAME_list ')' | |
561 | + ; | |
562 | +low_level_library_NAME_list: | |
563 | + low_level_library_NAME_list opt_comma filename | |
564 | + { ldemul_syslib($3); } | |
565 | + | | |
566 | + ; | |
567 | + | |
568 | +floating_point_support: | |
569 | + FLOAT | |
570 | + { lang_float(true); } | |
571 | + | NOFLOAT | |
572 | + { lang_float(false); } | |
573 | + ; | |
574 | + | |
575 | + | |
576 | + | |
577 | + | |
578 | +exp : | |
579 | + '-' exp %prec UNARY | |
580 | + { $$ = exp_unop('-', $2); } | |
581 | + | '(' exp ')' | |
582 | + { $$ = $2; } | |
583 | + | NEXT '(' exp ')' %prec UNARY | |
584 | + { $$ = exp_unop($1,$3); } | |
585 | + | '!' exp %prec UNARY | |
586 | + { $$ = exp_unop('!', $2); } | |
587 | + | '+' exp %prec UNARY | |
588 | + { $$ = $2; } | |
589 | + | '~' exp %prec UNARY | |
590 | + { $$ = exp_unop('~', $2);} | |
591 | + | |
592 | + | exp '*' exp | |
593 | + { $$ = exp_binop('*', $1, $3); } | |
594 | + | exp '/' exp | |
595 | + { $$ = exp_binop('/', $1, $3); } | |
596 | + | exp '%' exp | |
597 | + { $$ = exp_binop('%', $1, $3); } | |
598 | + | exp '+' exp | |
599 | + { $$ = exp_binop('+', $1, $3); } | |
600 | + | exp '-' exp | |
601 | + { $$ = exp_binop('-' , $1, $3); } | |
602 | + | exp LSHIFT exp | |
603 | + { $$ = exp_binop(LSHIFT , $1, $3); } | |
604 | + | exp RSHIFT exp | |
605 | + { $$ = exp_binop(RSHIFT , $1, $3); } | |
606 | + | exp EQ exp | |
607 | + { $$ = exp_binop(EQ , $1, $3); } | |
608 | + | exp NE exp | |
609 | + { $$ = exp_binop(NE , $1, $3); } | |
610 | + | exp LE exp | |
611 | + { $$ = exp_binop(LE , $1, $3); } | |
612 | + | exp GE exp | |
613 | + { $$ = exp_binop(GE , $1, $3); } | |
614 | + | exp '<' exp | |
615 | + { $$ = exp_binop('<' , $1, $3); } | |
616 | + | exp '>' exp | |
617 | + { $$ = exp_binop('>' , $1, $3); } | |
618 | + | exp '&' exp | |
619 | + { $$ = exp_binop('&' , $1, $3); } | |
620 | + | exp '^' exp | |
621 | + { $$ = exp_binop('^' , $1, $3); } | |
622 | + | exp '|' exp | |
623 | + { $$ = exp_binop('|' , $1, $3); } | |
624 | + | exp '?' exp ':' exp | |
625 | + { $$ = exp_trinop('?' , $1, $3, $5); } | |
626 | + | exp ANDAND exp | |
627 | + { $$ = exp_binop(ANDAND , $1, $3); } | |
628 | + | exp OROR exp | |
629 | + { $$ = exp_binop(OROR , $1, $3); } | |
630 | + | DEFINED '(' NAME ')' | |
631 | + { $$ = exp_nameop(DEFINED, $3); } | |
632 | + | INT | |
633 | + { $$ = exp_intop($1); } | |
634 | + | |
635 | + | SIZEOF '(' NAME ')' | |
636 | + { $$ = exp_nameop($1,$3); } | |
637 | + | ADDR '(' NAME ')' | |
638 | + { $$ = exp_nameop($1,$3); } | |
639 | + | ALIGN_K '(' exp ')' | |
640 | + { $$ = exp_unop($1,$3); } | |
641 | + | NAME | |
642 | + { $$ = exp_nameop(NAME,$1); } | |
643 | + ; | |
644 | + | |
645 | + | |
646 | + | |
647 | + | |
648 | +section: NAME opt_exp opt_block ':' opt_things'{' | |
649 | + { | |
650 | + lang_enter_output_section_statement($1,$2,$3); | |
651 | + } | |
652 | + statement '}' fill_opt memspec_opt | |
653 | + { | |
654 | + lang_leave_output_section_statement($10, $11); | |
655 | + } | |
656 | + | |
657 | + ; | |
658 | + | |
659 | +opt_things: | |
660 | + { | |
661 | + | |
662 | + } | |
663 | + ; | |
664 | + | |
665 | +exp_head: | |
666 | + { ldgram_mustbe_symbolname = true; } | |
667 | + exp | |
668 | + { ldgram_mustbe_symbolname = false; | |
669 | + $$ = $2; | |
670 | + } | |
671 | + | |
672 | +opt_exp: | |
673 | + exp | |
674 | + { $$ = $1; } | |
675 | + | { $$= (etree_type *)NULL; } | |
676 | + ; | |
677 | + | |
678 | +opt_block: | |
679 | + BLOCK '(' exp_head ')' | |
680 | + { $$ = exp_get_value_int($3, | |
681 | + 1L, | |
682 | + "block", | |
683 | + lang_first_phase_enum); | |
684 | + } | |
685 | + | { $$ = 1; } | |
686 | + ; | |
687 | + | |
688 | +memspec_opt: | |
689 | + '>' NAME | |
690 | + { $$ = $2; } | |
691 | + | { $$ = "*default*"; } | |
692 | + ; | |
693 | + |
@@ -0,0 +1,2231 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* $Id$ | |
20 | + * | |
21 | + * $Log$ | |
22 | + * Revision 1.1 1991/03/21 21:28:45 gumby | |
23 | + * Initial revision | |
24 | + * | |
25 | + * Revision 1.3 1991/03/16 22:19:21 rich | |
26 | + * pop | |
27 | + * | |
28 | + * Revision 1.2 1991/03/15 18:52:42 rich | |
29 | + * pop | |
30 | + * | |
31 | + * Revision 1.1 1991/03/13 00:48:23 chrisb | |
32 | + * Initial revision | |
33 | + * | |
34 | + * Revision 1.8 1991/03/10 09:31:28 rich | |
35 | + * Modified Files: | |
36 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
37 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
38 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
39 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
40 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
41 | + * | |
42 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
43 | + * interest and copy passes my copy test on big endian hosts again. | |
44 | + * | |
45 | + * Revision 1.7 1991/03/09 03:31:03 sac | |
46 | + * After a fatal info message, the output file is deleted. | |
47 | + * | |
48 | + * Revision 1.6 1991/03/09 03:25:06 sac | |
49 | + * Added support for LONG, SHORT and BYTE keywords in scripts | |
50 | + * | |
51 | + * Revision 1.5 1991/03/06 21:59:31 sac | |
52 | + * Completed G++ support | |
53 | + * | |
54 | + * Revision 1.4 1991/03/06 02:26:02 sac | |
55 | + * Added support for constructor sections. | |
56 | + * Remove parsing ambiguity. | |
57 | + * Lint | |
58 | + * | |
59 | + * Revision 1.3 1991/02/22 17:15:01 sac | |
60 | + * Added RCS keywords and copyrights | |
61 | + * | |
62 | +*/ | |
63 | + | |
64 | + | |
65 | + | |
66 | +#include "sysdep.h" | |
67 | +#include "bfd.h" | |
68 | + | |
69 | +#include "ld.h" | |
70 | +#include "ldmain.h" | |
71 | +#include "ldsym.h" | |
72 | +#include "ldgram.tab.h" | |
73 | +#include "ldmisc.h" | |
74 | +#include "ldlang.h" | |
75 | +#include "ldexp.h" | |
76 | +#include "ld-emul.h" | |
77 | +#include "ldlex.h" | |
78 | + | |
79 | +/* EXPORTS */ | |
80 | + | |
81 | + | |
82 | + | |
83 | +extern unsigned int undefined_global_sym_count; | |
84 | + | |
85 | +static char *startup_file; | |
86 | +static lang_input_statement_type *first_file; | |
87 | +lang_statement_list_type statement_list; | |
88 | +lang_statement_list_type *stat_ptr = &statement_list; | |
89 | +lang_statement_list_type lang_output_section_statement; | |
90 | +lang_statement_list_type input_file_chain; | |
91 | +lang_statement_list_type file_chain; | |
92 | +extern char *current_file; | |
93 | +static boolean placed_commons = false; | |
94 | + | |
95 | +boolean lang_float_flag; | |
96 | + | |
97 | +static lang_output_section_statement_type *default_common_section; | |
98 | + | |
99 | + | |
100 | +/* FORWARDS */ | |
101 | +PROTO(static void, print_statements,(void)); | |
102 | +PROTO(static void, print_statement,(lang_statement_union_type *, | |
103 | + lang_output_section_statement_type *)); | |
104 | + | |
105 | + | |
106 | + | |
107 | +/* EXPORTS */ | |
108 | +boolean lang_has_input_file = false; | |
109 | + | |
110 | + | |
111 | +extern bfd *output_bfd; | |
112 | +size_t largest_section; | |
113 | + | |
114 | + | |
115 | +extern enum bfd_architecture ldfile_output_architecture; | |
116 | +extern unsigned long ldfile_output_machine; | |
117 | +extern char *ldfile_output_machine_name; | |
118 | + | |
119 | + | |
120 | +extern ldsym_type *symbol_head; | |
121 | + | |
122 | +bfd_vma print_dot; | |
123 | +unsigned int commons_pending; | |
124 | + | |
125 | + | |
126 | + | |
127 | + | |
128 | +extern args_type command_line; | |
129 | +extern ld_config_type config; | |
130 | + | |
131 | +char *entry_symbol; | |
132 | + | |
133 | + | |
134 | + | |
135 | +lang_output_section_statement_type *create_object_symbols; | |
136 | + | |
137 | +extern boolean had_script; | |
138 | +static boolean map_option_f; | |
139 | + | |
140 | + | |
141 | +boolean had_output_filename = false; | |
142 | +extern boolean write_map; | |
143 | + | |
144 | + | |
145 | + | |
146 | + | |
147 | + | |
148 | + | |
149 | +size_t longest_section_name = 8; | |
150 | + | |
151 | + | |
152 | +lang_input_statement_type *script_file; | |
153 | + | |
154 | +section_userdata_type common_section_userdata; | |
155 | +asection common_section; | |
156 | + | |
157 | +#ifdef __STDC__ | |
158 | +#define cat(a,b) a##b | |
159 | +#else | |
160 | +#define cat(a,b) a/**/b | |
161 | +#endif | |
162 | + | |
163 | +#define new_stat(x,y) (cat(x,_type)*) new_statement(cat(x,_enum), sizeof(cat(x,_type)),y) | |
164 | + | |
165 | +#define outside_section_address(q) ( (q)->output_offset + (q)->output_section->vma) | |
166 | + | |
167 | +#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section)) | |
168 | + | |
169 | +boolean option_longmap = false; | |
170 | + | |
171 | +static void lang_list_init(list) | |
172 | +lang_statement_list_type *list; | |
173 | +{ | |
174 | +list->head = (lang_statement_union_type *)NULL; | |
175 | +list->tail = &list->head; | |
176 | +} | |
177 | + | |
178 | +static void | |
179 | +print_section(name) | |
180 | +char *name; | |
181 | +{ | |
182 | + printf("%*s", -longest_section_name, name); | |
183 | +} | |
184 | +static void | |
185 | +print_space() | |
186 | +{ | |
187 | + printf(" "); | |
188 | +} | |
189 | +static void | |
190 | +print_nl() | |
191 | +{ | |
192 | + printf("\n"); | |
193 | +} | |
194 | +static void | |
195 | +print_address(value) | |
196 | +bfd_vma value; | |
197 | +{ | |
198 | + printf("%8lx", value); | |
199 | +} | |
200 | +static void | |
201 | +print_size(value) | |
202 | +size_t value; | |
203 | +{ | |
204 | + printf("%5x", (unsigned)value); | |
205 | +} | |
206 | +static void | |
207 | +print_alignment(value) | |
208 | +unsigned int value; | |
209 | +{ | |
210 | + printf("2**%2u",value); | |
211 | +} | |
212 | +static void | |
213 | +print_fill(value) | |
214 | +fill_type value; | |
215 | +{ | |
216 | + printf("%04x",(unsigned)value); | |
217 | +} | |
218 | + | |
219 | + | |
220 | +static | |
221 | +lang_statement_union_type *new_statement(type, size, list) | |
222 | +enum statement_enum type; | |
223 | +size_t size; | |
224 | +lang_statement_list_type *list; | |
225 | +{ | |
226 | + lang_statement_union_type *new = (lang_statement_union_type *) | |
227 | + ldmalloc(size); | |
228 | + new->header.type = type; | |
229 | + new->header.next = (lang_statement_union_type *)NULL; | |
230 | + lang_statement_append(list, new, &new->header.next); | |
231 | + return new; | |
232 | +} | |
233 | + | |
234 | +static lang_input_statement_type * | |
235 | +new_afile(name, file_type, target) | |
236 | +char *name; | |
237 | +lang_input_file_enum_type file_type; | |
238 | +char *target; | |
239 | +{ | |
240 | + lang_input_statement_type *p = new_stat(lang_input_statement, | |
241 | + stat_ptr); | |
242 | + lang_has_input_file = true; | |
243 | + p->target = target; | |
244 | + switch (file_type) { | |
245 | + case lang_input_file_is_symbols_only_enum: | |
246 | + p->filename = name; | |
247 | + p->is_archive =false; | |
248 | + p->real = true; | |
249 | + p->local_sym_name= name; | |
250 | + p->just_syms_flag = true; | |
251 | + p->search_dirs_flag = false; | |
252 | + break; | |
253 | + case lang_input_file_is_fake_enum: | |
254 | + p->filename = name; | |
255 | + p->is_archive =false; | |
256 | + p->real = false; | |
257 | + p->local_sym_name= name; | |
258 | + p->just_syms_flag = false; | |
259 | + p->search_dirs_flag =false; | |
260 | + | |
261 | + break; | |
262 | + case lang_input_file_is_l_enum: | |
263 | + p->is_archive = true; | |
264 | + p->filename = name; | |
265 | + p->real = true; | |
266 | + p->local_sym_name = concat("-l",name,""); | |
267 | + p->just_syms_flag = false; | |
268 | + p->search_dirs_flag = true; | |
269 | + break; | |
270 | + | |
271 | + case lang_input_file_is_search_file_enum: | |
272 | + case lang_input_file_is_marker_enum: | |
273 | + p->filename = name; | |
274 | + p->is_archive =false; | |
275 | + p->real = true; | |
276 | + p->local_sym_name= name; | |
277 | + p->just_syms_flag = false; | |
278 | + p->search_dirs_flag =true; | |
279 | + break; | |
280 | + | |
281 | + | |
282 | + | |
283 | + case lang_input_file_is_file_enum: | |
284 | + p->filename = name; | |
285 | + p->is_archive =false; | |
286 | + p->real = true; | |
287 | + p->local_sym_name= name; | |
288 | + p->just_syms_flag = false; | |
289 | + p->search_dirs_flag =false; | |
290 | + break; | |
291 | + | |
292 | + | |
293 | + default: | |
294 | + FAIL(); | |
295 | + } | |
296 | + p->asymbols = (asymbol **)NULL; | |
297 | + p->superfile = (lang_input_statement_type *)NULL; | |
298 | + | |
299 | + p->next_real_file = (lang_statement_union_type*)NULL; | |
300 | + p->next = (lang_statement_union_type*)NULL; | |
301 | + p->symbol_count = 0; | |
302 | + p->common_output_section = (asection *)NULL; | |
303 | + | |
304 | + lang_statement_append(&input_file_chain, | |
305 | + (lang_statement_union_type *)p, | |
306 | + &p->next_real_file); | |
307 | + return p; | |
308 | +} | |
309 | + | |
310 | +lang_input_statement_type * | |
311 | +lang_add_input_file(name, | |
312 | + file_type, | |
313 | + target) | |
314 | +char *name; | |
315 | +lang_input_file_enum_type file_type; | |
316 | +char *target; | |
317 | +{ | |
318 | + /* Look it up or build a new one */ | |
319 | + | |
320 | + lang_input_statement_type *p; | |
321 | + | |
322 | + for (p = (lang_input_statement_type *)input_file_chain.head; | |
323 | + p != (lang_input_statement_type *)NULL; | |
324 | + p = (lang_input_statement_type *)(p->next_real_file)) | |
325 | + { | |
326 | + /* Sometimes we have incomplete entries in here */ | |
327 | + if (p->filename != (char *)NULL) { | |
328 | + if(strcmp(name,p->filename) == 0) return p; | |
329 | + } | |
330 | + } | |
331 | + | |
332 | + return new_afile(name, file_type, target); | |
333 | +} | |
334 | + | |
335 | + | |
336 | + | |
337 | +void | |
338 | +lang_init() | |
339 | +{ | |
340 | + | |
341 | + stat_ptr= &statement_list; | |
342 | + lang_list_init(stat_ptr); | |
343 | + | |
344 | + lang_list_init(&input_file_chain); | |
345 | + lang_list_init(&lang_output_section_statement); | |
346 | + lang_list_init(&file_chain); | |
347 | + first_file = lang_add_input_file((char *)NULL, | |
348 | + lang_input_file_is_marker_enum, | |
349 | + (char *)NULL); | |
350 | + | |
351 | +} | |
352 | + | |
353 | +static void | |
354 | +lang_init2() | |
355 | +{ | |
356 | + script_file = lang_add_input_file("script file", | |
357 | + lang_input_file_is_fake_enum, | |
358 | + (char *)NULL); | |
359 | + script_file->the_bfd = bfd_create("script file", output_bfd); | |
360 | + script_file->symbol_count = 0; | |
361 | + | |
362 | + common_section.userdata = &common_section_userdata; | |
363 | + | |
364 | +} | |
365 | + | |
366 | + | |
367 | + | |
368 | +/* this function mainains a dictionary of regions. If the *default* | |
369 | + region is asked for then a pointer to the first region is | |
370 | + returned. If there is no first pointer then one is created | |
371 | +*/ | |
372 | + | |
373 | +static lang_memory_region_type *lang_memory_region_list; | |
374 | +static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list; | |
375 | + | |
376 | +lang_memory_region_type * | |
377 | +lang_memory_region_lookup(name) | |
378 | +char *name; | |
379 | +{ | |
380 | + | |
381 | + lang_memory_region_type *p = lang_memory_region_list; | |
382 | + for (p = lang_memory_region_list; | |
383 | + p != ( lang_memory_region_type *)NULL; | |
384 | + p = p->next) { | |
385 | + if (strcmp(p->name, name) == 0) { | |
386 | + return p; | |
387 | + } | |
388 | + } | |
389 | + if (strcmp(name,"*default*")==0) { | |
390 | + /* This is the default region, dig out first one on the list */ | |
391 | + if (lang_memory_region_list != (lang_memory_region_type*)NULL){ | |
392 | + return lang_memory_region_list; | |
393 | + } | |
394 | + } | |
395 | + { | |
396 | + lang_memory_region_type *new = | |
397 | + (lang_memory_region_type *)ldmalloc(sizeof(lang_memory_region_type)); | |
398 | + new->name = name; | |
399 | + new->next = (lang_memory_region_type *)NULL; | |
400 | + | |
401 | + *lang_memory_region_list_tail = new; | |
402 | + lang_memory_region_list_tail = &new->next; | |
403 | + new->origin = 0; | |
404 | + new->length = ~0; | |
405 | + new->current = 0; | |
406 | + return new; | |
407 | + } | |
408 | +} | |
409 | + | |
410 | + | |
411 | + | |
412 | +lang_output_section_statement_type * | |
413 | +lang_output_section_find(name) | |
414 | +char *name; | |
415 | +{ | |
416 | + lang_statement_union_type *u; | |
417 | + lang_output_section_statement_type *lookup; | |
418 | + | |
419 | + for (u = lang_output_section_statement.head; | |
420 | + u != (lang_statement_union_type *)NULL; | |
421 | + u = lookup->next) | |
422 | + { | |
423 | + lookup = &u->output_section_statement; | |
424 | + if (strcmp(name, lookup->name)==0) { | |
425 | + return lookup; | |
426 | + } | |
427 | + } | |
428 | + return (lang_output_section_statement_type *)NULL; | |
429 | +} | |
430 | + | |
431 | +lang_output_section_statement_type * | |
432 | +lang_output_section_statement_lookup(name) | |
433 | +char *name; | |
434 | + | |
435 | +{ | |
436 | + lang_output_section_statement_type *lookup; | |
437 | + lookup =lang_output_section_find(name); | |
438 | + if (lookup == (lang_output_section_statement_type *)NULL) { | |
439 | + | |
440 | + lookup =(lang_output_section_statement_type *) | |
441 | + new_stat(lang_output_section_statement, stat_ptr); | |
442 | + lookup->region = (lang_memory_region_type *)NULL; | |
443 | + lookup->fill = 0; | |
444 | + lookup->block_value = 1; | |
445 | + lookup->name = name; | |
446 | + | |
447 | + lookup->next = (lang_statement_union_type*)NULL; | |
448 | + lookup->bfd_section = (asection *)NULL; | |
449 | + lookup->processed = false; | |
450 | + lookup->addr_tree = (etree_type *)NULL; | |
451 | + lang_list_init(&lookup->children); | |
452 | + | |
453 | + lang_statement_append(&lang_output_section_statement, | |
454 | + (lang_statement_union_type *)lookup, | |
455 | + &lookup->next); | |
456 | + } | |
457 | + return lookup; | |
458 | +} | |
459 | + | |
460 | + | |
461 | + | |
462 | + | |
463 | + | |
464 | +static void | |
465 | + print_flags(outfile, ignore_flags) | |
466 | +FILE *outfile; | |
467 | +lang_section_flags_type *ignore_flags; | |
468 | +{ | |
469 | + fprintf(outfile,"("); | |
470 | +#if 0 | |
471 | + if (flags->flag_read) fprintf(outfile,"R"); | |
472 | + if (flags->flag_write) fprintf(outfile,"W"); | |
473 | + if (flags->flag_executable) fprintf(outfile,"X"); | |
474 | + if (flags->flag_loadable) fprintf(outfile,"L"); | |
475 | +#endif | |
476 | + fprintf(outfile,")"); | |
477 | +} | |
478 | + | |
479 | +void | |
480 | +lang_map(outfile) | |
481 | + FILE *outfile; | |
482 | +{ | |
483 | + lang_memory_region_type *m; | |
484 | + fprintf(outfile,"**MEMORY CONFIGURATION**\n\n"); | |
485 | + | |
486 | + fprintf(outfile,"name\t\torigin\t\tlength\t\tattributes\n"); | |
487 | + for (m = lang_memory_region_list; | |
488 | + m != (lang_memory_region_type *)NULL; | |
489 | + m = m->next) | |
490 | + { | |
491 | + fprintf(outfile,"%-16s", m->name); | |
492 | + | |
493 | + fprintf(outfile,"%08lx\t%08lx\t", m->origin, m->length); | |
494 | + print_flags(outfile, &m->flags); | |
495 | + fprintf(outfile,"\n"); | |
496 | + } | |
497 | + fprintf(outfile,"\n\n**LINK EDITOR MEMORY MAP**\n\n"); | |
498 | + fprintf(outfile,"output\t\tinput\t\tvirtual\n"); | |
499 | + fprintf(outfile,"section\t\tsection\t\taddress\tsize\n\n"); | |
500 | + | |
501 | + print_statements(); | |
502 | + | |
503 | +} | |
504 | + | |
505 | +/* | |
506 | + * | |
507 | + */ | |
508 | +static void init_os(s) | |
509 | +lang_output_section_statement_type *s; | |
510 | +{ | |
511 | + section_userdata_type *new = | |
512 | + (section_userdata_type *) | |
513 | + ldmalloc(sizeof(section_userdata_type)); | |
514 | + | |
515 | + s->bfd_section = bfd_make_section(output_bfd, s->name); | |
516 | + s->bfd_section->output_section = s->bfd_section; | |
517 | + s->bfd_section->flags = SEC_NO_FLAGS; | |
518 | + /* We initialize an output sections output offset to minus its own */ | |
519 | + /* vma to allow us to output a section through itself */ | |
520 | + s->bfd_section->output_offset = 0; | |
521 | + get_userdata( s->bfd_section) = new; | |
522 | +} | |
523 | + | |
524 | +static void | |
525 | +wild_doit(ptr, section,output, file) | |
526 | +lang_statement_list_type *ptr; | |
527 | +asection *section; | |
528 | +lang_output_section_statement_type *output; | |
529 | +lang_input_statement_type *file; | |
530 | +{ | |
531 | + if(output->bfd_section == (asection *)NULL) | |
532 | + { | |
533 | + init_os(output); | |
534 | + } | |
535 | + | |
536 | + if (section != (asection *)NULL | |
537 | + && section->output_section == (asection *)NULL) { | |
538 | + /* Add a section reference to the list */ | |
539 | + lang_input_section_type *new = new_stat(lang_input_section, ptr); | |
540 | + | |
541 | + new->section = section; | |
542 | + new->ifile = file; | |
543 | + section->output_section = output->bfd_section; | |
544 | + section->output_section->flags |= section->flags; | |
545 | + if (section->alignment_power > output->bfd_section->alignment_power) { | |
546 | + output->bfd_section->alignment_power = section->alignment_power; | |
547 | + } | |
548 | + | |
549 | + } | |
550 | +} | |
551 | + | |
552 | +static asection * | |
553 | +our_bfd_get_section_by_name(abfd, section) | |
554 | +bfd *abfd; | |
555 | +char *section; | |
556 | +{ | |
557 | + return bfd_get_section_by_name(abfd, section); | |
558 | + | |
559 | +} | |
560 | +static void | |
561 | +wild_section(ptr, section, file , output) | |
562 | +lang_wild_statement_type *ptr; | |
563 | +char *section; | |
564 | +lang_input_statement_type *file; | |
565 | +lang_output_section_statement_type *output; | |
566 | +{ | |
567 | + asection *s; | |
568 | + if (section == (char *)NULL) { | |
569 | + /* Do the creation to all sections in the file */ | |
570 | + for (s = file->the_bfd->sections; s != (asection *)NULL; s=s->next) { | |
571 | + wild_doit(&ptr->children, s, output, file); | |
572 | + } | |
573 | + } | |
574 | + else { | |
575 | + /* Do the creation to the named section only */ | |
576 | + wild_doit(&ptr->children, | |
577 | + our_bfd_get_section_by_name(file->the_bfd, section), | |
578 | + output, file); | |
579 | + } | |
580 | + | |
581 | + | |
582 | + | |
583 | +} | |
584 | + | |
585 | + | |
586 | + | |
587 | +static | |
588 | +lang_input_statement_type *lookup_name(name, target) | |
589 | +char *name; | |
590 | +char *target; | |
591 | +{ | |
592 | + lang_input_statement_type *search; | |
593 | + for(search = (lang_input_statement_type *)input_file_chain.head; | |
594 | + search != (lang_input_statement_type *)NULL; | |
595 | + search = (lang_input_statement_type *)search->next_real_file) | |
596 | + { | |
597 | + if (search->filename == (char *)NULL && name == (char *)NULL) { | |
598 | + return search; | |
599 | + } | |
600 | + if (search->filename != (char *)NULL && name != (char *)NULL) { | |
601 | + if (strcmp(search->filename, name) == 0) { | |
602 | + Q_read_file_symbols(search); | |
603 | + return search; | |
604 | + } | |
605 | + } | |
606 | + } | |
607 | + | |
608 | + /* There isn't an afile entry for this file yet, this must be */ | |
609 | + /* because the name has only appeared inside a load script and not */ | |
610 | + /* on the command line */ | |
611 | + search = new_afile(name, lang_input_file_is_file_enum, target); | |
612 | + Q_read_file_symbols(search); | |
613 | + return search; | |
614 | +} | |
615 | + | |
616 | +static void | |
617 | + | |
618 | +wild(s, section, file, target, output) | |
619 | +lang_wild_statement_type *s; | |
620 | +char *section; | |
621 | +char *file; | |
622 | +char *target; | |
623 | +lang_output_section_statement_type *output; | |
624 | +{ | |
625 | + lang_input_statement_type *f; | |
626 | + if (file == (char *)NULL) { | |
627 | + /* Perform the iteration over all files in the list */ | |
628 | + for (f = (lang_input_statement_type *)file_chain.head; | |
629 | + f != (lang_input_statement_type *)NULL; | |
630 | + f = (lang_input_statement_type *)f->next) { | |
631 | + wild_section(s, section, f, output); | |
632 | + } | |
633 | + } | |
634 | + else { | |
635 | + /* Perform the iteration over a single file */ | |
636 | + wild_section( s, section, lookup_name(file, target), output); | |
637 | + } | |
638 | +} | |
639 | + | |
640 | +/* | |
641 | + read in all the files | |
642 | + */ | |
643 | +static bfd * | |
644 | +open_output(name, target) | |
645 | +char *name; | |
646 | +char *target; | |
647 | +{ | |
648 | + extern char *output_filename; | |
649 | + bfd * output = bfd_openw(name, target); | |
650 | + output_filename = name; | |
651 | + if (output == (bfd *)NULL) | |
652 | + { | |
653 | + if (bfd_error == invalid_target) { | |
654 | + info("%P%F target %s not found\n", target); | |
655 | + } | |
656 | + info("%P%F problem opening output file %s, %E", name); | |
657 | + } | |
658 | + | |
659 | + output->flags |= D_PAGED; | |
660 | + bfd_set_format(output, bfd_object); | |
661 | + return output; | |
662 | +} | |
663 | +extern char *default_target; | |
664 | +static void | |
665 | +lang_phase_0(sh,target) | |
666 | +lang_statement_union_type *sh; | |
667 | +char *target; | |
668 | +{ | |
669 | + lang_statement_union_type *s = (lang_statement_union_type *)sh; | |
670 | + for (; s != (lang_statement_union_type *)NULL ; s = s->next) | |
671 | + { | |
672 | + switch (s->header.type) { | |
673 | + case lang_output_section_statement_enum: | |
674 | + lang_phase_0(s->output_section_statement.children.head, | |
675 | + target); | |
676 | + break; | |
677 | + case lang_output_statement_enum: | |
678 | +#if 1 | |
679 | + output_bfd = open_output(s->output_statement.name, | |
680 | + target == (char *)NULL ? | |
681 | + default_target : target); | |
682 | + ldemul_set_output_arch(); | |
683 | +#endif | |
684 | + break; | |
685 | + case lang_target_statement_enum: | |
686 | + target = s->target_statement.target; | |
687 | + break; | |
688 | + case lang_wild_statement_enum: | |
689 | + /* Maybe we should load the file's symbols */ | |
690 | + if (s->wild_statement.filename) { | |
691 | + (void) lookup_name(s->wild_statement.filename, target); | |
692 | + } | |
693 | + break; | |
694 | + /* Attatch this to the current output section */ | |
695 | + case lang_common_statement_enum: | |
696 | + case lang_fill_statement_enum: | |
697 | + case lang_input_section_enum: | |
698 | + case lang_object_symbols_statement_enum: | |
699 | + case lang_address_statement_enum: | |
700 | + case lang_data_statement_enum: | |
701 | + break; | |
702 | + case lang_afile_asection_pair_statement_enum: | |
703 | + | |
704 | + FAIL(); | |
705 | + break; | |
706 | + | |
707 | + case lang_input_statement_enum: | |
708 | + if (s->input_statement.real == true) { | |
709 | + s->input_statement.target = target; | |
710 | + lookup_name(s->input_statement.filename, target); | |
711 | + } | |
712 | + break; | |
713 | + case lang_assignment_statement_enum: | |
714 | +#if 0 | |
715 | + (void) exp_fold_tree(s->assignment_statement.exp, | |
716 | + output_section, | |
717 | + false); | |
718 | +#endif | |
719 | + break; | |
720 | + | |
721 | + case lang_padding_statement_enum: | |
722 | + | |
723 | + break; | |
724 | + } | |
725 | + } | |
726 | + | |
727 | +} | |
728 | + | |
729 | +/* If there are [COMMONS] statements, put a wild one into the bss section */ | |
730 | + | |
731 | +static void | |
732 | +lang_reasonable_defaults() | |
733 | +{ | |
734 | + default_common_section = | |
735 | + lang_output_section_statement_lookup(".bss"); | |
736 | + if (placed_commons == false) { | |
737 | + lang_wild_statement_type *new = | |
738 | + new_stat(lang_wild_statement, | |
739 | + &default_common_section->children); | |
740 | + new->section_name = "COMMON"; | |
741 | + new->filename = (char *)NULL; | |
742 | + lang_list_init(&new->children); | |
743 | + } | |
744 | +} | |
745 | + | |
746 | +static void lang() | |
747 | +{ | |
748 | + if (had_script == false) { | |
749 | + parse_line(ldemul_get_script()); | |
750 | + } | |
751 | + | |
752 | + lang_reasonable_defaults(); | |
753 | + lang_phase_0(statement_list.head,default_target); | |
754 | +} | |
755 | + | |
756 | + | |
757 | +/* Open input files and attatch to output sections */ | |
758 | +static void | |
759 | +lang_open_input(s, target, output_section_statement) | |
760 | +lang_statement_union_type *s; | |
761 | +char *target; | |
762 | +lang_output_section_statement_type *output_section_statement; | |
763 | +{ | |
764 | + for (; s != (lang_statement_union_type *)NULL ; s = s->next) | |
765 | + { | |
766 | + switch (s->header.type) { | |
767 | + case lang_wild_statement_enum: | |
768 | + wild(&s->wild_statement, s->wild_statement.section_name, | |
769 | + s->wild_statement.filename, target, | |
770 | + output_section_statement); | |
771 | + | |
772 | + break; | |
773 | + | |
774 | + case lang_output_section_statement_enum: | |
775 | + lang_open_input(s->output_section_statement.children.head, | |
776 | + target, | |
777 | + &s->output_section_statement); | |
778 | + break; | |
779 | + case lang_output_statement_enum: | |
780 | + break; | |
781 | + case lang_target_statement_enum: | |
782 | + target = s->target_statement.target; | |
783 | + break; | |
784 | + case lang_common_statement_enum: | |
785 | + case lang_fill_statement_enum: | |
786 | + case lang_input_section_enum: | |
787 | + case lang_object_symbols_statement_enum: | |
788 | + case lang_data_statement_enum: | |
789 | + break; | |
790 | + case lang_afile_asection_pair_statement_enum: | |
791 | + FAIL(); | |
792 | + break; | |
793 | + | |
794 | + case lang_assignment_statement_enum: | |
795 | + case lang_padding_statement_enum: | |
796 | + | |
797 | + break; | |
798 | + case lang_address_statement_enum: | |
799 | + /* Mark the specified section with the supplied address */ | |
800 | + { | |
801 | + lang_output_section_statement_type *os = | |
802 | + lang_output_section_statement_lookup | |
803 | + (s->address_statement.section_name); | |
804 | + os->addr_tree = s->address_statement.address; | |
805 | + } | |
806 | + break; | |
807 | + case lang_input_statement_enum: | |
808 | + /* A standard input statement, has no wildcards */ | |
809 | + /* Q_read_file_symbols(&s->input_statement);*/ | |
810 | + break; | |
811 | + } | |
812 | + } | |
813 | +} | |
814 | + | |
815 | + | |
816 | + | |
817 | + | |
818 | + | |
819 | +static void | |
820 | +print_output_section_statement(output_section_statement) | |
821 | +lang_output_section_statement_type *output_section_statement; | |
822 | +{ | |
823 | + asection *section = output_section_statement->bfd_section; | |
824 | + print_nl(); | |
825 | + print_section(output_section_statement->name); | |
826 | + | |
827 | + if (section) { | |
828 | + print_dot = section->vma; | |
829 | + print_space(); | |
830 | + print_section(""); | |
831 | + print_space(); | |
832 | + print_address(section->vma); | |
833 | + print_space(); | |
834 | + print_size(section->size); | |
835 | + print_space(); | |
836 | + print_alignment(section->alignment_power); | |
837 | + print_space(); | |
838 | +#if 0 | |
839 | + printf("%s flags", output_section_statement->region->name); | |
840 | + print_flags(stdout, &output_section_statement->flags); | |
841 | +#endif | |
842 | + | |
843 | + } | |
844 | + else { | |
845 | + printf("No attached output section"); | |
846 | + } | |
847 | + print_nl(); | |
848 | + print_statement(output_section_statement->children.head, | |
849 | + output_section_statement); | |
850 | + | |
851 | +} | |
852 | + | |
853 | +static void | |
854 | +print_assignment(assignment, output_section) | |
855 | +lang_assignment_statement_type *assignment; | |
856 | +lang_output_section_statement_type *output_section; | |
857 | +{ | |
858 | + etree_value_type result; | |
859 | + print_section(""); | |
860 | + print_space(); | |
861 | + print_section(""); | |
862 | + print_space(); | |
863 | + print_address(print_dot); | |
864 | + print_space(); | |
865 | + result = exp_fold_tree(assignment->exp->assign.src, | |
866 | + output_section, | |
867 | + lang_final_phase_enum, | |
868 | + print_dot, | |
869 | + &print_dot); | |
870 | + | |
871 | + if (result.valid) { | |
872 | + print_address(result.value); | |
873 | + } | |
874 | + else | |
875 | + { | |
876 | + printf("*undefined*"); | |
877 | + } | |
878 | + print_space(); | |
879 | + exp_print_tree(stdout, assignment->exp); | |
880 | + printf("\n"); | |
881 | +} | |
882 | + | |
883 | +static void | |
884 | +print_input_statement(statm) | |
885 | +lang_input_statement_type *statm; | |
886 | +{ | |
887 | + printf("LOAD %s\n",statm->filename); | |
888 | +} | |
889 | + | |
890 | +static void print_symbol(q) | |
891 | +asymbol *q; | |
892 | +{ | |
893 | + print_section(""); | |
894 | + printf(" "); | |
895 | + print_section(""); | |
896 | + printf(" "); | |
897 | + print_address(outside_symbol_address(q)); | |
898 | + printf(" %s", q->name ? q->name : " "); | |
899 | + print_nl(); | |
900 | +} | |
901 | +static void | |
902 | +print_input_section(in) | |
903 | +lang_input_section_type *in; | |
904 | +{ | |
905 | + asection *i = in->section; | |
906 | + | |
907 | + if(i->size != 0) { | |
908 | + print_section(""); | |
909 | + printf(" "); | |
910 | + print_section(i->name); | |
911 | + printf(" "); | |
912 | + if (i->output_section) { | |
913 | + print_address(i->output_section->vma + i->output_offset); | |
914 | + printf(" "); | |
915 | + print_size(i->size); | |
916 | + printf(" "); | |
917 | + print_alignment(i->alignment_power); | |
918 | + printf(" "); | |
919 | + if (in->ifile) { | |
920 | + bfd *abfd = in->ifile->the_bfd; | |
921 | + printf(" %s ",abfd->xvec->name); | |
922 | + if(abfd->my_archive != (bfd *)NULL) { | |
923 | + printf("[%s]%s", abfd->my_archive->filename, | |
924 | + abfd->filename); | |
925 | + } | |
926 | + else { | |
927 | + printf("%s", abfd->filename); | |
928 | + } | |
929 | + print_nl(); | |
930 | + | |
931 | + /* Find all the symbols in this file defined in this section */ | |
932 | + { | |
933 | + asymbol **p; | |
934 | + for (p = in->ifile->asymbols; *p; p++) { | |
935 | + asymbol *q = *p; | |
936 | + | |
937 | + if (bfd_get_section(q) == i && q->flags & BSF_GLOBAL) { | |
938 | + print_symbol(q); | |
939 | + } | |
940 | + } | |
941 | + } | |
942 | + } | |
943 | + else { | |
944 | + print_nl(); | |
945 | + } | |
946 | + | |
947 | + | |
948 | + print_dot = outside_section_address(i) + i->size; | |
949 | + } | |
950 | + else { | |
951 | + printf("No output section allocated\n"); | |
952 | + } | |
953 | + } | |
954 | +} | |
955 | +static void | |
956 | +print_common_statement() | |
957 | +{ | |
958 | + ldsym_type *lgs; | |
959 | + print_section(""); | |
960 | + print_space(); | |
961 | + print_section(common_section.output_section->name); | |
962 | + print_space(); | |
963 | + print_address(common_section.output_offset + | |
964 | + common_section.output_section->vma); | |
965 | + print_space(); | |
966 | + print_size(common_section.size); | |
967 | + print_space(); | |
968 | + printf("(common)"); | |
969 | + print_nl(); | |
970 | + /* Print out all the global symbols */ | |
971 | + | |
972 | + | |
973 | + for (lgs = symbol_head; lgs != (ldsym_type *)NULL; lgs = | |
974 | + lgs->next) { | |
975 | + if (lgs->sdefs_chain) { | |
976 | + asymbol *def = *(lgs->sdefs_chain); | |
977 | + if (def->section == &common_section) { | |
978 | + print_symbol(def); | |
979 | + } | |
980 | + } | |
981 | + | |
982 | + } | |
983 | + print_dot = common_section.output_offset + | |
984 | + common_section.output_section->vma + common_section.size; | |
985 | + | |
986 | + | |
987 | +} | |
988 | +static void | |
989 | +print_fill_statement(fill) | |
990 | +lang_fill_statement_type *fill; | |
991 | +{ | |
992 | + printf("FILL mask "); | |
993 | + print_fill( fill->fill); | |
994 | +} | |
995 | + | |
996 | +static void | |
997 | +print_data_statement(data) | |
998 | +lang_data_statement_type *data; | |
999 | +{ | |
1000 | +/* bfd_vma value; */ | |
1001 | + print_section(""); | |
1002 | + print_space(); | |
1003 | + print_section(""); | |
1004 | + print_space(); | |
1005 | + ASSERT(print_dot == data->output_vma); | |
1006 | + | |
1007 | + print_address(data->output_vma); | |
1008 | + print_space(); | |
1009 | + print_address(data->value); | |
1010 | + print_space(); | |
1011 | + switch (data->type) { | |
1012 | + case BYTE : | |
1013 | + printf("BYTE "); | |
1014 | + print_dot += BYTE_SIZE; | |
1015 | + break; | |
1016 | + case SHORT: | |
1017 | + printf("SHORT "); | |
1018 | + print_dot += SHORT_SIZE; | |
1019 | + break; | |
1020 | + case LONG: | |
1021 | + printf("LONG "); | |
1022 | + print_dot += LONG_SIZE; | |
1023 | + break; | |
1024 | + } | |
1025 | + | |
1026 | + exp_print_tree(stdout, data->exp); | |
1027 | + | |
1028 | + printf("\n"); | |
1029 | +} | |
1030 | + | |
1031 | + | |
1032 | +static void | |
1033 | +print_padding_statement(s) | |
1034 | +lang_padding_statement_type *s; | |
1035 | +{ | |
1036 | + print_section(""); | |
1037 | + print_space(); | |
1038 | + print_section("*fill*"); | |
1039 | + print_space(); | |
1040 | + print_address(s->output_offset + s->output_section->vma); | |
1041 | + print_space(); | |
1042 | + print_size(s->size); | |
1043 | + print_space(); | |
1044 | + print_fill(s->fill); | |
1045 | + print_nl(); | |
1046 | +} | |
1047 | + | |
1048 | +static void print_wild_statement(w,os) | |
1049 | +lang_wild_statement_type *w; | |
1050 | +lang_output_section_statement_type *os; | |
1051 | +{ | |
1052 | + if (w->filename != (char *)NULL) { | |
1053 | + printf("%s",w->filename); | |
1054 | + } | |
1055 | + else { | |
1056 | + printf("*"); | |
1057 | + } | |
1058 | + if (w->section_name != (char *)NULL) { | |
1059 | + printf("(%s)",w->section_name); | |
1060 | + } | |
1061 | + else { | |
1062 | + printf("(*)"); | |
1063 | + } | |
1064 | + print_nl(); | |
1065 | + print_statement(w->children.head, os); | |
1066 | + | |
1067 | +} | |
1068 | +static void | |
1069 | +print_statement(s, os) | |
1070 | +lang_statement_union_type *s; | |
1071 | +lang_output_section_statement_type *os; | |
1072 | +{ | |
1073 | + while (s) { | |
1074 | + switch (s->header.type) { | |
1075 | + case lang_wild_statement_enum: | |
1076 | + print_wild_statement(&s->wild_statement, os); | |
1077 | + break; | |
1078 | + default: | |
1079 | + printf("Fail with %d\n",s->header.type); | |
1080 | + FAIL(); | |
1081 | + break; | |
1082 | + case lang_address_statement_enum: | |
1083 | + printf("address\n"); | |
1084 | + break; | |
1085 | + case lang_common_statement_enum: | |
1086 | + print_common_statement(); | |
1087 | + break; | |
1088 | + case lang_object_symbols_statement_enum: | |
1089 | + printf("object symbols\n"); | |
1090 | + break; | |
1091 | + case lang_fill_statement_enum: | |
1092 | + print_fill_statement(&s->fill_statement); | |
1093 | + break; | |
1094 | + case lang_data_statement_enum: | |
1095 | + print_data_statement(&s->data_statement); | |
1096 | + break; | |
1097 | + | |
1098 | + | |
1099 | + case lang_input_section_enum: | |
1100 | + print_input_section(&s->input_section); | |
1101 | + break; | |
1102 | + case lang_padding_statement_enum: | |
1103 | + print_padding_statement(&s->padding_statement); | |
1104 | + break; | |
1105 | + case lang_output_section_statement_enum: | |
1106 | + print_output_section_statement(&s->output_section_statement); | |
1107 | + break; | |
1108 | + case lang_assignment_statement_enum: | |
1109 | + print_assignment(&s->assignment_statement, | |
1110 | + os); | |
1111 | + break; | |
1112 | + | |
1113 | + | |
1114 | + case lang_target_statement_enum: | |
1115 | + printf("TARGET(%s)\n", s->target_statement.target); | |
1116 | + break; | |
1117 | + case lang_output_statement_enum: | |
1118 | + printf("OUTPUT(%s)\n", s->output_statement.name); | |
1119 | + break; | |
1120 | + case lang_input_statement_enum: | |
1121 | + print_input_statement(&s->input_statement); | |
1122 | + break; | |
1123 | + case lang_afile_asection_pair_statement_enum: | |
1124 | + FAIL(); | |
1125 | + break; | |
1126 | + } | |
1127 | + s = s->next; | |
1128 | + } | |
1129 | +} | |
1130 | + | |
1131 | + | |
1132 | +static void | |
1133 | +print_statements() | |
1134 | +{ | |
1135 | + print_statement(statement_list.head, | |
1136 | + (lang_output_section_statement_type *)NULL); | |
1137 | +} | |
1138 | + | |
1139 | +static bfd_vma | |
1140 | +insert_pad(this_ptr, fill, power, output_section_statement, dot) | |
1141 | +lang_statement_union_type **this_ptr; | |
1142 | +fill_type fill; | |
1143 | +unsigned int power; | |
1144 | +asection * output_section_statement; | |
1145 | +bfd_vma dot; | |
1146 | +{ | |
1147 | + /* Align this section first to the | |
1148 | + input sections requirement, then | |
1149 | + to the output section's requirement. | |
1150 | + If this alignment is > than any seen before, | |
1151 | + then record it too. Perform the alignment by | |
1152 | + inserting a magic 'padding' statement. | |
1153 | + */ | |
1154 | + | |
1155 | + unsigned int alignment_needed = align_power(dot, power) - dot; | |
1156 | + | |
1157 | + if (alignment_needed != 0) | |
1158 | + { | |
1159 | + lang_statement_union_type *new = | |
1160 | + (lang_statement_union_type *) | |
1161 | + ldmalloc(sizeof(lang_padding_statement_type)); | |
1162 | + /* Link into existing chain */ | |
1163 | + new->header.next = *this_ptr; | |
1164 | + *this_ptr = new; | |
1165 | + new->header.type = lang_padding_statement_enum; | |
1166 | + new->padding_statement.output_section = output_section_statement; | |
1167 | + new->padding_statement.output_offset = | |
1168 | + dot - output_section_statement->vma; | |
1169 | + new->padding_statement.fill = fill; | |
1170 | + new->padding_statement.size = alignment_needed; | |
1171 | + } | |
1172 | + | |
1173 | + | |
1174 | + /* Remember the most restrictive alignment */ | |
1175 | + if (power > output_section_statement->alignment_power) { | |
1176 | + output_section_statement->alignment_power = power; | |
1177 | + } | |
1178 | + output_section_statement->size += alignment_needed; | |
1179 | + return alignment_needed + dot; | |
1180 | + | |
1181 | +} | |
1182 | + | |
1183 | +/* | |
1184 | + size_common runs run though each global symboxl, and works | |
1185 | + out how big the common section will be. | |
1186 | + */ | |
1187 | + | |
1188 | +static bfd_vma | |
1189 | +size_common(output_section_statement, this_ptr, dot) | |
1190 | +lang_output_section_statement_type *output_section_statement; | |
1191 | +lang_statement_union_type **this_ptr; | |
1192 | +bfd_vma dot; | |
1193 | +{ | |
1194 | + extern ldsym_type *symbol_head; | |
1195 | + ldsym_type *sp; | |
1196 | + /* Make sure that each symbol is only defined once. | |
1197 | + Allocate common symbols | |
1198 | + Make the ref chain point to the defining asymbol. | |
1199 | + */ | |
1200 | + /* Now, for each symbol, verify that it is defined globally at most once. | |
1201 | + Put the global value into the symbol entry. | |
1202 | + Common symbols are allocated here, in the BSS section. | |
1203 | + Each defined symbol is given a '->defined' field | |
1204 | + which is the correct N_ code for its definition, | |
1205 | + except in the case of common symbols with -r. | |
1206 | + Then make all the references point at the symbol entry | |
1207 | + instead of being chained together. */ | |
1208 | + | |
1209 | + | |
1210 | + common_section.name = output_section_statement->bfd_section->name; | |
1211 | + common_section.output_section = output_section_statement->bfd_section; | |
1212 | + common_section.output_offset = | |
1213 | + dot - output_section_statement->bfd_section->vma; | |
1214 | + if (config.relocateable_output == false || | |
1215 | + command_line.force_common_definition== true) { | |
1216 | + dot = insert_pad(this_ptr, | |
1217 | + 0x0, 4, output_section_statement->bfd_section, dot); | |
1218 | + | |
1219 | + for (sp = symbol_head; sp != (ldsym_type *)NULL; sp = sp->next) | |
1220 | + { | |
1221 | + /* Attatch this symbol to the correct output section*/ | |
1222 | + | |
1223 | + /* Allocate as common if wanted */ | |
1224 | + | |
1225 | + if (sp->scoms_chain ) | |
1226 | + | |
1227 | + { | |
1228 | + unsigned long com = (*(sp->scoms_chain))->value; | |
1229 | + /* Work out what alignment this common item s | |
1230 | + hould be put on. Anything < int is int aligned, | |
1231 | + anything bigger is self aligned, | |
1232 | + up to the restriction of the machine */ | |
1233 | + | |
1234 | + unsigned int align = sizeof(int); | |
1235 | + | |
1236 | + /* Round up size of object to nearest int */ | |
1237 | + com = ALIGN(com, sizeof(int)); | |
1238 | + /* See what alignment is necessary -*/ | |
1239 | + if (com) { | |
1240 | + while ((com & align)==0) align <<=1; | |
1241 | + /* FIXME */ | |
1242 | + if (align > 8) { | |
1243 | + align = 8; | |
1244 | + } | |
1245 | + } | |
1246 | + dot = ALIGN(dot, align); | |
1247 | + | |
1248 | + | |
1249 | + /* Transmogrify this from a common symbol | |
1250 | + into a definition of a symbol in common | |
1251 | + */ | |
1252 | + sp->sdefs_chain = sp->scoms_chain; | |
1253 | + | |
1254 | + { | |
1255 | + asymbol *com_ptr = *(sp->sdefs_chain); | |
1256 | + | |
1257 | + sp->scoms_chain = (asymbol **)NULL; | |
1258 | + commons_pending--; | |
1259 | + /* Assign address, but keep section relative */ | |
1260 | + | |
1261 | + /* Force the symbol to belong in the bss section */ | |
1262 | + com_ptr->flags = BSF_EXPORT | BSF_GLOBAL ; | |
1263 | + com_ptr->section = &common_section; | |
1264 | + common_section.size += com; | |
1265 | + if (write_map) | |
1266 | + { | |
1267 | + printf ("Allocating common %s: %lx at %lx\n", | |
1268 | + sp->name, | |
1269 | + com, | |
1270 | + com_ptr->value); | |
1271 | + } | |
1272 | + com_ptr->value = common_section.size; | |
1273 | + } | |
1274 | + } | |
1275 | + } | |
1276 | + } | |
1277 | + if (dot > | |
1278 | + (common_section.output_section->vma + | |
1279 | + common_section.output_section->size)) { | |
1280 | + common_section.output_section->size = | |
1281 | + dot - common_section.output_section->vma; | |
1282 | + } | |
1283 | + return dot + common_section.size; | |
1284 | +} | |
1285 | + | |
1286 | +static bfd_vma | |
1287 | +size_input_section( this_ptr, output_section_statement, fill, dot) | |
1288 | +lang_statement_union_type **this_ptr; | |
1289 | +lang_output_section_statement_type*output_section_statement; | |
1290 | +unsigned short fill; | |
1291 | +bfd_vma dot; | |
1292 | +{ | |
1293 | + lang_input_section_type *is = &((*this_ptr)->input_section); | |
1294 | + asection *i = is->section; | |
1295 | + | |
1296 | + dot = insert_pad(this_ptr, fill, i->alignment_power, | |
1297 | + output_section_statement->bfd_section, dot); | |
1298 | + | |
1299 | + /* remember the largest size so we can malloc the largest area */ | |
1300 | + /* needed for the output stage */ | |
1301 | + if (i->size > largest_section) { | |
1302 | + largest_section = i->size; | |
1303 | + } | |
1304 | + | |
1305 | + /* Remember where in the output section this input section goes */ | |
1306 | + i->output_offset = dot - output_section_statement->bfd_section->vma; | |
1307 | + | |
1308 | + /* Mark how big the output section must be to contain this now */ | |
1309 | + dot += i->size; | |
1310 | + output_section_statement->bfd_section->size = | |
1311 | + dot - output_section_statement->bfd_section->vma; | |
1312 | + | |
1313 | + | |
1314 | + return dot ; | |
1315 | +} | |
1316 | + | |
1317 | + | |
1318 | +/* Work out the size of the output sections | |
1319 | + from the sizes of the input sections */ | |
1320 | +static bfd_vma | |
1321 | +lang_size_sections(s, output_section_statement, prev, fill, dot) | |
1322 | +lang_statement_union_type *s; | |
1323 | +lang_output_section_statement_type * output_section_statement; | |
1324 | +lang_statement_union_type **prev; | |
1325 | +unsigned short fill; | |
1326 | +bfd_vma dot; | |
1327 | +{ | |
1328 | + /* Size up the sections from their constituent parts */ | |
1329 | + for (; s != (lang_statement_union_type *)NULL ; s = s->next) | |
1330 | + { | |
1331 | + switch (s->header.type) { | |
1332 | + case lang_output_section_statement_enum: | |
1333 | + { | |
1334 | + bfd_vma after; | |
1335 | + lang_output_section_statement_type *os = | |
1336 | + &(s->output_section_statement); | |
1337 | + /* The start of a section */ | |
1338 | + | |
1339 | + if (os->addr_tree == (etree_type *)NULL) { | |
1340 | + /* No address specified for this section, get one | |
1341 | + from the region specification | |
1342 | + */ | |
1343 | + if (os->region == (lang_memory_region_type *)NULL) { | |
1344 | + os->region = lang_memory_region_lookup("*default*"); | |
1345 | + } | |
1346 | + dot = os->region->current; | |
1347 | + } | |
1348 | + else { | |
1349 | + etree_value_type r ; | |
1350 | + r = exp_fold_tree(os->addr_tree, | |
1351 | + (lang_output_section_statement_type *)NULL, | |
1352 | + lang_allocating_phase_enum, | |
1353 | + dot, &dot); | |
1354 | + if (r.valid == false) { | |
1355 | + info("%F%S: non constant address expression for section %s\n", | |
1356 | + os->name); | |
1357 | + } | |
1358 | + dot = r.value; | |
1359 | + } | |
1360 | + /* The section starts here */ | |
1361 | + /* First, align to what the section needs */ | |
1362 | + | |
1363 | + dot = align_power(dot, os->bfd_section->alignment_power); | |
1364 | + os->bfd_section->vma = dot; | |
1365 | + os->bfd_section->output_offset = 0; | |
1366 | + | |
1367 | + (void) lang_size_sections(os->children.head, os, &os->children.head, | |
1368 | + os->fill, dot); | |
1369 | + /* Ignore the size of the input sections, use the vma and size to */ | |
1370 | + /* align against */ | |
1371 | + | |
1372 | + | |
1373 | + after = ALIGN(os->bfd_section->vma + | |
1374 | + os->bfd_section->size, | |
1375 | + os->block_value) ; | |
1376 | + | |
1377 | + | |
1378 | + os->bfd_section->size = after - os->bfd_section->vma; | |
1379 | + dot = os->bfd_section->vma + os->bfd_section->size; | |
1380 | + os->processed = true; | |
1381 | + | |
1382 | + /* Replace into region ? */ | |
1383 | + if (os->addr_tree == (etree_type *)NULL | |
1384 | + && os->region !=(lang_memory_region_type*)NULL ) { | |
1385 | + os->region->current = dot; | |
1386 | + } | |
1387 | + } | |
1388 | + | |
1389 | + break; | |
1390 | + | |
1391 | + case lang_data_statement_enum: | |
1392 | + { | |
1393 | + unsigned int size; | |
1394 | + s->data_statement.output_vma = dot; | |
1395 | + s->data_statement.output_section = | |
1396 | + output_section_statement->bfd_section; | |
1397 | + | |
1398 | + switch (s->data_statement.type) { | |
1399 | + case LONG: | |
1400 | + size = LONG_SIZE; | |
1401 | + break; | |
1402 | + case SHORT: | |
1403 | + size = SHORT_SIZE; | |
1404 | + break; | |
1405 | + case BYTE: | |
1406 | + size = BYTE_SIZE; | |
1407 | + break; | |
1408 | + | |
1409 | + } | |
1410 | + dot += size; | |
1411 | + output_section_statement->bfd_section->size += size; | |
1412 | + } | |
1413 | + break; | |
1414 | + | |
1415 | + case lang_wild_statement_enum: | |
1416 | + | |
1417 | + dot = lang_size_sections(s->wild_statement.children.head, | |
1418 | + output_section_statement, | |
1419 | + &s->wild_statement.children.head, | |
1420 | + | |
1421 | + fill, dot); | |
1422 | + | |
1423 | + break; | |
1424 | + | |
1425 | + case lang_object_symbols_statement_enum: | |
1426 | + create_object_symbols = output_section_statement; | |
1427 | + break; | |
1428 | + case lang_output_statement_enum: | |
1429 | + | |
1430 | + case lang_target_statement_enum: | |
1431 | + break; | |
1432 | + case lang_common_statement_enum: | |
1433 | + dot = size_common(output_section_statement, prev, dot); | |
1434 | + | |
1435 | + break; | |
1436 | + | |
1437 | + case lang_input_section_enum: | |
1438 | + dot = size_input_section(prev, | |
1439 | + output_section_statement, | |
1440 | + output_section_statement->fill, dot); | |
1441 | + break; | |
1442 | + case lang_input_statement_enum: | |
1443 | + break; | |
1444 | + case lang_fill_statement_enum: | |
1445 | + fill = s->fill_statement.fill; | |
1446 | + break; | |
1447 | + case lang_assignment_statement_enum: | |
1448 | + { | |
1449 | + bfd_vma newdot = dot; | |
1450 | + exp_fold_tree(s->assignment_statement.exp, | |
1451 | + output_section_statement, | |
1452 | + lang_allocating_phase_enum, | |
1453 | + dot, | |
1454 | + &newdot); | |
1455 | + | |
1456 | + if (newdot != dot) | |
1457 | + /* We've been moved ! so insert a pad */ | |
1458 | + { | |
1459 | + lang_statement_union_type *new = | |
1460 | + (lang_statement_union_type *) | |
1461 | + ldmalloc(sizeof(lang_padding_statement_type)); | |
1462 | + /* Link into existing chain */ | |
1463 | + new->header.next = *prev; | |
1464 | + *prev = new; | |
1465 | + new->header.type = lang_padding_statement_enum; | |
1466 | + new->padding_statement.output_section = | |
1467 | + output_section_statement->bfd_section; | |
1468 | + new->padding_statement.output_offset = | |
1469 | + dot - output_section_statement->bfd_section->vma; | |
1470 | + new->padding_statement.fill = fill; | |
1471 | + new->padding_statement.size = newdot - dot; | |
1472 | + output_section_statement->bfd_section->size += | |
1473 | + new->padding_statement.size; | |
1474 | + dot = newdot; | |
1475 | + } | |
1476 | + } | |
1477 | + | |
1478 | + break; | |
1479 | + case lang_padding_statement_enum: | |
1480 | + FAIL(); | |
1481 | + break; | |
1482 | + default: | |
1483 | + FAIL(); | |
1484 | + break; | |
1485 | + case lang_address_statement_enum: | |
1486 | + break; | |
1487 | + } | |
1488 | + prev = &s->header.next; | |
1489 | + } | |
1490 | + return dot; | |
1491 | +} | |
1492 | + | |
1493 | + | |
1494 | +static bfd_vma | |
1495 | +lang_do_assignments(s, output_section_statement, fill, dot) | |
1496 | +lang_statement_union_type *s; | |
1497 | +lang_output_section_statement_type * output_section_statement; | |
1498 | +unsigned short fill; | |
1499 | +bfd_vma dot; | |
1500 | +{ | |
1501 | + | |
1502 | + for (; s != (lang_statement_union_type *)NULL ; s = s->next) | |
1503 | + { | |
1504 | + switch (s->header.type) { | |
1505 | + case lang_output_section_statement_enum: | |
1506 | + { | |
1507 | + lang_output_section_statement_type *os = | |
1508 | + &(s->output_section_statement); | |
1509 | + dot = os->bfd_section->vma; | |
1510 | + (void) lang_do_assignments(os->children.head, os, os->fill, dot); | |
1511 | + dot = os->bfd_section->vma + os->bfd_section->size; | |
1512 | + } | |
1513 | + break; | |
1514 | + case lang_wild_statement_enum: | |
1515 | + | |
1516 | + dot = lang_do_assignments(s->wild_statement.children.head, | |
1517 | + output_section_statement, | |
1518 | + fill, dot); | |
1519 | + | |
1520 | + break; | |
1521 | + | |
1522 | + case lang_object_symbols_statement_enum: | |
1523 | + case lang_output_statement_enum: | |
1524 | + case lang_target_statement_enum: | |
1525 | + case lang_common_statement_enum: | |
1526 | + break; | |
1527 | + case lang_data_statement_enum: | |
1528 | + { | |
1529 | + etree_value_type value ; | |
1530 | + value = exp_fold_tree(s->data_statement.exp, | |
1531 | + 0, lang_final_phase_enum, dot, &dot); | |
1532 | + s->data_statement.value = value.value; | |
1533 | + if (value.valid == false) info("%F%P: Invalid data statement\n"); | |
1534 | + } | |
1535 | + switch (s->data_statement.type) { | |
1536 | + case LONG: | |
1537 | + dot += LONG_SIZE; | |
1538 | + break; | |
1539 | + case SHORT: | |
1540 | + dot += SHORT_SIZE; | |
1541 | + break; | |
1542 | + case BYTE: | |
1543 | + dot += BYTE_SIZE; | |
1544 | + break; | |
1545 | + } | |
1546 | + break; | |
1547 | + case lang_input_section_enum: | |
1548 | + { | |
1549 | + asection *in = s->input_section.section; | |
1550 | + dot += in->size; | |
1551 | + } | |
1552 | + break; | |
1553 | + | |
1554 | + case lang_input_statement_enum: | |
1555 | + break; | |
1556 | + case lang_fill_statement_enum: | |
1557 | + fill = s->fill_statement.fill; | |
1558 | + break; | |
1559 | + case lang_assignment_statement_enum: | |
1560 | + { | |
1561 | + exp_fold_tree(s->assignment_statement.exp, | |
1562 | + output_section_statement, | |
1563 | + lang_final_phase_enum, | |
1564 | + dot, | |
1565 | + &dot); | |
1566 | + } | |
1567 | + | |
1568 | + break; | |
1569 | + case lang_padding_statement_enum: | |
1570 | + dot += s->padding_statement.size; | |
1571 | + break; | |
1572 | + default: | |
1573 | + FAIL(); | |
1574 | + break; | |
1575 | + case lang_address_statement_enum: | |
1576 | + break; | |
1577 | + } | |
1578 | + | |
1579 | + } | |
1580 | + return dot; | |
1581 | +} | |
1582 | + | |
1583 | + | |
1584 | + | |
1585 | +static void lang_relocate_globals() | |
1586 | +{ | |
1587 | + | |
1588 | + /* | |
1589 | + Each ldsym_type maintains a chain of pointers to asymbols which | |
1590 | + references the definition. Replace each pointer to the referenence | |
1591 | + with a pointer to only one place, preferably the definition. If | |
1592 | + the defintion isn't available then the common symbol, and if | |
1593 | + there isn't one of them then choose one reference. | |
1594 | + */ | |
1595 | + | |
1596 | + FOR_EACH_LDSYM(lgs) { | |
1597 | + asymbol *it; | |
1598 | + if (lgs->sdefs_chain) { | |
1599 | + it = *(lgs->sdefs_chain); | |
1600 | + } | |
1601 | + else if (lgs->scoms_chain != (asymbol **)NULL) { | |
1602 | + it = *(lgs->scoms_chain); | |
1603 | + } | |
1604 | + else if (lgs->srefs_chain != (asymbol **)NULL) { | |
1605 | + it = *(lgs->srefs_chain); | |
1606 | + } | |
1607 | + else { | |
1608 | + FAIL(); | |
1609 | + } | |
1610 | + if (it != (asymbol *)NULL) | |
1611 | + { | |
1612 | + asymbol **ptr= lgs->srefs_chain; | |
1613 | + | |
1614 | + while (ptr != (asymbol **)NULL) { | |
1615 | + asymbol *ref = *ptr; | |
1616 | + *ptr = it; | |
1617 | + ptr = (asymbol **)(ref->udata); | |
1618 | + } | |
1619 | + } | |
1620 | + } | |
1621 | +} | |
1622 | + | |
1623 | + | |
1624 | + | |
1625 | +/* now that all the jiggery pokery is finished, copy important data from | |
1626 | + * out internal form to the bfd way. Also create a section | |
1627 | + * for each dummy file | |
1628 | + */ | |
1629 | + | |
1630 | +static void | |
1631 | +lang_create_output_section_statements() | |
1632 | +{ | |
1633 | + lang_statement_union_type*os; | |
1634 | + for (os = lang_output_section_statement.head; | |
1635 | + os != (lang_statement_union_type*)NULL; | |
1636 | + os = os->output_section_statement.next) { | |
1637 | + lang_output_section_statement_type *s = | |
1638 | + &os->output_section_statement; | |
1639 | + init_os(s); | |
1640 | + } | |
1641 | + script_file->the_bfd->sections = output_bfd->sections; | |
1642 | +} | |
1643 | + | |
1644 | +static void | |
1645 | +lang_finish() | |
1646 | +{ | |
1647 | + ldsym_type *lgs; | |
1648 | + | |
1649 | + if (entry_symbol == (char *)NULL) { | |
1650 | + /* No entry has been specified, look for start */ | |
1651 | + entry_symbol = "start"; | |
1652 | + } | |
1653 | + lgs = ldsym_get_soft(entry_symbol); | |
1654 | + if (lgs && lgs->sdefs_chain) { | |
1655 | + asymbol *sy = *(lgs->sdefs_chain); | |
1656 | + /* We can set the entry address*/ | |
1657 | + bfd_set_start_address(output_bfd, | |
1658 | + outside_symbol_address(sy)); | |
1659 | + | |
1660 | + } | |
1661 | + else { | |
1662 | + /* Can't find anything reasonable, | |
1663 | + use the first address in the text section | |
1664 | + */ | |
1665 | + asection *ts = bfd_get_section_by_name(output_bfd, ".text"); | |
1666 | + if (ts) { | |
1667 | + bfd_set_start_address(output_bfd, ts->vma); | |
1668 | + } | |
1669 | + } | |
1670 | +} | |
1671 | + | |
1672 | +/* By now we know the target architecture, and we may have an */ | |
1673 | +/* ldfile_output_machine_name */ | |
1674 | +static void | |
1675 | +lang_check() | |
1676 | +{ | |
1677 | + lang_statement_union_type *file; | |
1678 | + | |
1679 | + | |
1680 | + for (file = file_chain.head; | |
1681 | + file != (lang_statement_union_type *)NULL; | |
1682 | + file=file->input_statement.next) | |
1683 | + { | |
1684 | + /* Inspect the architecture and ensure we're linking like | |
1685 | + with like | |
1686 | + */ | |
1687 | + | |
1688 | + if (bfd_arch_compatible( file->input_statement.the_bfd, | |
1689 | + output_bfd, | |
1690 | + &ldfile_output_architecture, | |
1691 | + &ldfile_output_machine)) { | |
1692 | + bfd_set_arch_mach(output_bfd, | |
1693 | + ldfile_output_architecture, ldfile_output_machine); | |
1694 | + } | |
1695 | + else { | |
1696 | + enum bfd_architecture this_architecture = | |
1697 | + bfd_get_architecture(file->input_statement.the_bfd); | |
1698 | + unsigned long this_machine = | |
1699 | + bfd_get_machine(file->input_statement.the_bfd); | |
1700 | + | |
1701 | + info("%I: architecture %s", | |
1702 | + file, | |
1703 | + bfd_printable_arch_mach(this_architecture, this_machine)); | |
1704 | + info(" incompatible with output %s\n", | |
1705 | + bfd_printable_arch_mach(ldfile_output_architecture, | |
1706 | + ldfile_output_machine)); | |
1707 | + ldfile_output_architecture = this_architecture; | |
1708 | + ldfile_output_machine = this_machine; | |
1709 | + bfd_set_arch_mach(output_bfd, | |
1710 | + ldfile_output_architecture, | |
1711 | + ldfile_output_machine); | |
1712 | + | |
1713 | + | |
1714 | + } | |
1715 | + } | |
1716 | +} | |
1717 | + | |
1718 | + | |
1719 | +/* | |
1720 | + * run through all the global common symbols and tie them | |
1721 | + * to the output section requested. | |
1722 | + */ | |
1723 | + | |
1724 | +static void | |
1725 | +lang_common() | |
1726 | +{ | |
1727 | + ldsym_type *lgs; | |
1728 | + if (config.relocateable_output == false || | |
1729 | + command_line.force_common_definition== true) { | |
1730 | + for (lgs = symbol_head; | |
1731 | + lgs != (ldsym_type *)NULL; | |
1732 | + lgs=lgs->next) | |
1733 | + { | |
1734 | + asymbol *com ; | |
1735 | + size_t size; | |
1736 | + size_t align; | |
1737 | + if (lgs->scoms_chain != (asymbol **)NULL) { | |
1738 | + | |
1739 | + com = *(lgs->scoms_chain); | |
1740 | + size = com->value; | |
1741 | + align = sizeof(int); | |
1742 | + /* Round up size of object to nearest int */ | |
1743 | + size = ALIGN(size, sizeof(int)); | |
1744 | + /* Force alignment */ | |
1745 | + if (size) { | |
1746 | + while ((size & align)==0) align<<=1; | |
1747 | + if (align > 8) { | |
1748 | + align = 8; | |
1749 | + } | |
1750 | + } | |
1751 | + /* Change from a common symbol into a definition of | |
1752 | + a symbol */ | |
1753 | + lgs->sdefs_chain = lgs->scoms_chain; | |
1754 | + lgs->scoms_chain = (asymbol **)NULL; | |
1755 | + commons_pending--; | |
1756 | + /* Point to the correct common section */ | |
1757 | + com->section = | |
1758 | + ((lang_input_statement_type *) | |
1759 | + (com->the_bfd->usrdata))->common_section; | |
1760 | + /* Fix the size of the common section */ | |
1761 | + | |
1762 | + | |
1763 | + com->flags = BSF_EXPORT | BSF_GLOBAL; | |
1764 | + | |
1765 | + if (write_map) | |
1766 | + { | |
1767 | + printf ("Allocating common %s: %x at %x\n", | |
1768 | + lgs->name, | |
1769 | + (unsigned) size, | |
1770 | + (unsigned) com->section->size); | |
1771 | + } | |
1772 | + com->value = com->section->size; | |
1773 | + com->section->size += size; | |
1774 | + } | |
1775 | + } | |
1776 | + } | |
1777 | +} | |
1778 | + | |
1779 | +/* | |
1780 | +run through the input files and ensure that every input | |
1781 | +section has somewhere to go. If one is found without | |
1782 | +a destination then create an input request and place it | |
1783 | +into the statement tree. | |
1784 | +*/ | |
1785 | + | |
1786 | +static void lang_place_orphans() | |
1787 | +{ | |
1788 | + lang_input_statement_type *file; | |
1789 | + for (file = (lang_input_statement_type*)file_chain.head; | |
1790 | + file != (lang_input_statement_type*)NULL; | |
1791 | + file = (lang_input_statement_type*)file->next) { | |
1792 | + asection *s; | |
1793 | + for (s = file->the_bfd->sections; | |
1794 | + s != (asection *)NULL; | |
1795 | + s = s->next) { | |
1796 | + if ( s->output_section == (asection *)NULL) { | |
1797 | + /* This section of the file is not attatched, root | |
1798 | + around for a sensible place for it to go */ | |
1799 | + | |
1800 | + if (file->common_section == s) { | |
1801 | + /* This is a lonely common section which must | |
1802 | + have come from an archive. We attatch to the | |
1803 | + section with the wildcard */ | |
1804 | + wild_doit(&default_common_section->children, s, | |
1805 | + default_common_section, file); | |
1806 | + } | |
1807 | + else { | |
1808 | + lang_output_section_statement_type *os = | |
1809 | + lang_output_section_statement_lookup(s->name); | |
1810 | + | |
1811 | + wild_doit(&os->children, s, os, file); | |
1812 | + } | |
1813 | + } | |
1814 | + } | |
1815 | + | |
1816 | + } | |
1817 | +} | |
1818 | + | |
1819 | + | |
1820 | +/* | |
1821 | + * phase_2 | |
1822 | + * | |
1823 | + * peformed after every file has been opened and symbols read | |
1824 | + */ | |
1825 | +static void | |
1826 | +lang_phase_2() | |
1827 | +{ | |
1828 | + lang_init2(); | |
1829 | + | |
1830 | + lang_create_output_section_statements(); | |
1831 | + lang_open_input(statement_list.head, (char *)NULL, | |
1832 | + ( lang_output_section_statement_type *)NULL); | |
1833 | + lang_place_orphans(); | |
1834 | + lang_common(); | |
1835 | + | |
1836 | + ldemul_before_allocation(); | |
1837 | + | |
1838 | + lang_size_sections(statement_list.head, | |
1839 | + (lang_output_section_statement_type *)NULL, | |
1840 | + &(statement_list.head), 0, (bfd_vma)0); | |
1841 | + ldemul_after_allocation(); | |
1842 | + /* Do it once again now that we know the sizes of everything */ | |
1843 | + | |
1844 | + lang_do_assignments(statement_list.head, | |
1845 | + (lang_output_section_statement_type *)NULL, | |
1846 | + 0, (bfd_vma)0); | |
1847 | + | |
1848 | + | |
1849 | + | |
1850 | + lang_check(); | |
1851 | + | |
1852 | + lang_relocate_globals(); | |
1853 | + | |
1854 | + | |
1855 | + lang_finish(); | |
1856 | +} | |
1857 | + | |
1858 | + | |
1859 | + | |
1860 | + | |
1861 | +void | |
1862 | +lang_set_flags(ptr, flags) | |
1863 | +lang_section_flags_type *ptr; | |
1864 | +char *flags; | |
1865 | +{ | |
1866 | + boolean state = true; | |
1867 | + ptr->flag_read = false; | |
1868 | + ptr->flag_write = false; | |
1869 | + ptr->flag_executable = false; | |
1870 | + ptr->flag_loadable= false; | |
1871 | + while (*flags) | |
1872 | + { | |
1873 | + if (*flags == '!') { | |
1874 | + state = false; | |
1875 | + flags++; | |
1876 | + } | |
1877 | + else state = true; | |
1878 | + switch (*flags) { | |
1879 | + case 'R': | |
1880 | + ptr->flag_read = state; | |
1881 | + break; | |
1882 | + case 'W': | |
1883 | + ptr->flag_write = state; | |
1884 | + break; | |
1885 | + case 'X': | |
1886 | + ptr->flag_executable= state; | |
1887 | + break; | |
1888 | + case 'L': | |
1889 | + ptr->flag_loadable= state; | |
1890 | + break; | |
1891 | + default: | |
1892 | + info("%P%F illegal syntax in flags\n"); | |
1893 | + break; | |
1894 | + } | |
1895 | + flags++; | |
1896 | + } | |
1897 | +} | |
1898 | + | |
1899 | + | |
1900 | + | |
1901 | +void | |
1902 | +lang_for_each_file(func) | |
1903 | +void (*func)(); | |
1904 | +{ | |
1905 | + lang_input_statement_type *f; | |
1906 | + for (f = (lang_input_statement_type *)file_chain.head; | |
1907 | + f != (lang_input_statement_type *)NULL; | |
1908 | + f = (lang_input_statement_type *)f->next) | |
1909 | + { | |
1910 | + func(f); | |
1911 | + } | |
1912 | +} | |
1913 | + | |
1914 | + | |
1915 | +void | |
1916 | +lang_for_each_input_section(func) | |
1917 | +void (*func)(); | |
1918 | +{ | |
1919 | + lang_input_statement_type *f; | |
1920 | + for (f = (lang_input_statement_type *)file_chain.head; | |
1921 | + f != (lang_input_statement_type *)NULL; | |
1922 | + f = (lang_input_statement_type *)f->next) | |
1923 | + { | |
1924 | + asection *s; | |
1925 | + for (s = f->the_bfd->sections; | |
1926 | + s != (asection *)NULL; | |
1927 | + s = s->next) { | |
1928 | + func(f->the_bfd, s); | |
1929 | + } | |
1930 | + } | |
1931 | +} | |
1932 | + | |
1933 | + | |
1934 | + | |
1935 | +void | |
1936 | +ldlang_add_file(entry) | |
1937 | +lang_input_statement_type *entry; | |
1938 | +{ | |
1939 | + lang_has_input_file = true; | |
1940 | + lang_statement_append(&file_chain, | |
1941 | + (lang_statement_union_type *)entry, | |
1942 | + &entry->next); | |
1943 | +} | |
1944 | + | |
1945 | + | |
1946 | + | |
1947 | +void | |
1948 | +lang_add_output(name) | |
1949 | +char *name; | |
1950 | +{ | |
1951 | + lang_output_statement_type *new = new_stat(lang_output_statement, | |
1952 | + stat_ptr); | |
1953 | + new->name = name; | |
1954 | + had_output_filename = true; | |
1955 | +} | |
1956 | + | |
1957 | + | |
1958 | +static lang_output_section_statement_type *current_section; | |
1959 | + | |
1960 | +void | |
1961 | +lang_enter_output_section_statement(output_section_statement_name, | |
1962 | +address_exp, | |
1963 | +block_value) | |
1964 | +char *output_section_statement_name; | |
1965 | +etree_type *address_exp; | |
1966 | +bfd_vma block_value; | |
1967 | +{ | |
1968 | + lang_output_section_statement_type *os; | |
1969 | + current_section = | |
1970 | + os = | |
1971 | + lang_output_section_statement_lookup(output_section_statement_name); | |
1972 | + | |
1973 | + | |
1974 | + /* Add this statement to tree */ | |
1975 | + /* add_statement(lang_output_section_statement_enum, | |
1976 | + output_section_statement);*/ | |
1977 | + /* Make next things chain into subchain of this */ | |
1978 | + | |
1979 | + if (os->addr_tree == | |
1980 | + (etree_type *)NULL) { | |
1981 | + os->addr_tree = | |
1982 | + address_exp; | |
1983 | + } | |
1984 | + os->block_value = block_value; | |
1985 | + stat_ptr = & os->children; | |
1986 | + | |
1987 | +} | |
1988 | + | |
1989 | + | |
1990 | +void | |
1991 | +lang_final() | |
1992 | +{ | |
1993 | + if (had_output_filename == false) { | |
1994 | + lang_add_output("a.out"); | |
1995 | + } | |
1996 | + | |
1997 | + | |
1998 | +} | |
1999 | + | |
2000 | + | |
2001 | + | |
2002 | + | |
2003 | + | |
2004 | +asymbol *create_symbol(name, flags, section) | |
2005 | +char *name; | |
2006 | +flagword flags; | |
2007 | +asection *section; | |
2008 | +{ | |
2009 | + extern lang_input_statement_type *script_file; | |
2010 | + asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **)); | |
2011 | + /* Add this definition to script file */ | |
2012 | + asymbol *def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd); | |
2013 | + def->name = name; | |
2014 | + def->udata = 0; | |
2015 | + def->flags = flags; | |
2016 | + def->section = section; | |
2017 | + | |
2018 | + *def_ptr = def; | |
2019 | + Q_enter_global_ref(def_ptr); | |
2020 | + return def; | |
2021 | +} | |
2022 | + | |
2023 | + | |
2024 | +void | |
2025 | +lang_process() | |
2026 | +{ | |
2027 | + lang(); | |
2028 | + lang_phase_2(); | |
2029 | +} | |
2030 | + | |
2031 | + | |
2032 | +/* EXPORTED TO YACC */ | |
2033 | +void | |
2034 | +lang_section_start(name, address) | |
2035 | +char *name; | |
2036 | +etree_type *address; | |
2037 | +{ | |
2038 | + lang_address_statement_type *ad =new_stat(lang_address_statement, stat_ptr); | |
2039 | + ad->section_name = name; | |
2040 | + ad->address = address; | |
2041 | +} | |
2042 | +void lang_add_entry(name) | |
2043 | +char *name; | |
2044 | +{ | |
2045 | + entry_symbol = name; | |
2046 | +} | |
2047 | + | |
2048 | +void | |
2049 | +lang_add_target(name) | |
2050 | +char *name; | |
2051 | +{ | |
2052 | + lang_target_statement_type *new = new_stat(lang_target_statement, | |
2053 | + stat_ptr); | |
2054 | + new->target = name; | |
2055 | + | |
2056 | +} | |
2057 | +void | |
2058 | +lang_add_wild(section_name, filename) | |
2059 | +char *section_name; | |
2060 | +char *filename; | |
2061 | +{ | |
2062 | + lang_wild_statement_type *new = new_stat(lang_wild_statement, | |
2063 | + stat_ptr); | |
2064 | + | |
2065 | + if (section_name != (char *)NULL && strcmp(section_name,"COMMON") == 0) | |
2066 | + { | |
2067 | + placed_commons = true; | |
2068 | + } | |
2069 | + new->section_name = section_name; | |
2070 | + new->filename = filename; | |
2071 | + lang_list_init(&new->children); | |
2072 | +} | |
2073 | + | |
2074 | +void | |
2075 | +lang_add_map(name) | |
2076 | +char *name; | |
2077 | +{ | |
2078 | + while (*name) { | |
2079 | + switch (*name) { | |
2080 | + case 'F': | |
2081 | + map_option_f = true; | |
2082 | + break; | |
2083 | + } | |
2084 | + name++; | |
2085 | + } | |
2086 | +} | |
2087 | + | |
2088 | +void lang_add_fill(exp) | |
2089 | +int exp; | |
2090 | +{ | |
2091 | + lang_fill_statement_type *new = new_stat(lang_fill_statement, | |
2092 | + stat_ptr); | |
2093 | + new->fill = exp; | |
2094 | +} | |
2095 | + | |
2096 | +void lang_add_data(type, exp) | |
2097 | +int type; | |
2098 | +union etree_union *exp; | |
2099 | +{ | |
2100 | + | |
2101 | + lang_data_statement_type *new = new_stat(lang_data_statement, | |
2102 | + stat_ptr); | |
2103 | + new->exp = exp; | |
2104 | + new->type = type; | |
2105 | + | |
2106 | +} | |
2107 | +void | |
2108 | +lang_add_assignment(exp) | |
2109 | +etree_type *exp; | |
2110 | +{ | |
2111 | + lang_assignment_statement_type *new = new_stat(lang_assignment_statement, | |
2112 | + stat_ptr); | |
2113 | + new->exp = exp; | |
2114 | +} | |
2115 | + | |
2116 | +void | |
2117 | +lang_add_attribute(attribute) | |
2118 | +enum statement_enum attribute; | |
2119 | +{ | |
2120 | + new_statement(attribute, sizeof(lang_statement_union_type),stat_ptr); | |
2121 | +} | |
2122 | + | |
2123 | + | |
2124 | + | |
2125 | +void | |
2126 | +lang_startup(name) | |
2127 | +char *name; | |
2128 | +{ | |
2129 | + if (startup_file != (char *)NULL) { | |
2130 | + info("%P%FMultiple STARTUP files\n"); | |
2131 | + } | |
2132 | + first_file->filename = name; | |
2133 | + first_file->local_sym_name = name; | |
2134 | + | |
2135 | + startup_file= name; | |
2136 | +} | |
2137 | +void | |
2138 | +lang_float(maybe) | |
2139 | +boolean maybe; | |
2140 | +{ | |
2141 | + lang_float_flag = maybe; | |
2142 | +} | |
2143 | + | |
2144 | +void | |
2145 | +lang_leave_output_section_statement(fill, memspec) | |
2146 | +bfd_vma fill; | |
2147 | +char *memspec; | |
2148 | +{ | |
2149 | + current_section->fill = fill; | |
2150 | + current_section->region = lang_memory_region_lookup(memspec); | |
2151 | + stat_ptr = &statement_list; | |
2152 | +} | |
2153 | + | |
2154 | +void | |
2155 | +lang_abs_symbol_at_end_of(section, name) | |
2156 | +char *section; | |
2157 | +char *name; | |
2158 | +{ | |
2159 | + extern bfd *output_bfd; | |
2160 | + extern asymbol *create_symbol(); | |
2161 | + asection *s = bfd_get_section_by_name(output_bfd, section); | |
2162 | + /* Add a symbol called _end */ | |
2163 | + asymbol *def = create_symbol(name, | |
2164 | + BSF_GLOBAL | BSF_EXPORT | | |
2165 | + BSF_ABSOLUTE, | |
2166 | + (asection *)NULL); | |
2167 | + if (s != (asection *)NULL) { | |
2168 | + def->value = s->vma + s->size; | |
2169 | + } | |
2170 | + else { | |
2171 | + def->value = 0; | |
2172 | + } | |
2173 | +} | |
2174 | + | |
2175 | +void | |
2176 | +lang_statement_append(list, element, field) | |
2177 | +lang_statement_list_type *list; | |
2178 | +lang_statement_union_type *element; | |
2179 | +lang_statement_union_type **field; | |
2180 | +{ | |
2181 | + *(list->tail) = element; | |
2182 | + list->tail = field; | |
2183 | +} | |
2184 | + | |
2185 | + | |
2186 | +static void | |
2187 | +lang_for_each_statement_worker(func, s) | |
2188 | +void (*func)(); | |
2189 | +lang_statement_union_type *s; | |
2190 | +{ | |
2191 | + for (; s != (lang_statement_union_type *)NULL ; s = s->next) | |
2192 | + { | |
2193 | + func(s); | |
2194 | + | |
2195 | + switch (s->header.type) { | |
2196 | + case lang_output_section_statement_enum: | |
2197 | + lang_for_each_statement_worker | |
2198 | + (func, | |
2199 | + s->output_section_statement.children.head); | |
2200 | + break; | |
2201 | + case lang_wild_statement_enum: | |
2202 | + lang_for_each_statement_worker | |
2203 | + (func, | |
2204 | + s->wild_statement.children.head); | |
2205 | + break; | |
2206 | + case lang_data_statement_enum: | |
2207 | + case lang_object_symbols_statement_enum: | |
2208 | + case lang_output_statement_enum: | |
2209 | + case lang_target_statement_enum: | |
2210 | + case lang_common_statement_enum: | |
2211 | + case lang_input_section_enum: | |
2212 | + case lang_input_statement_enum: | |
2213 | + case lang_fill_statement_enum: | |
2214 | + case lang_assignment_statement_enum: | |
2215 | + case lang_padding_statement_enum: | |
2216 | + case lang_address_statement_enum: | |
2217 | + break; | |
2218 | + default: | |
2219 | + FAIL(); | |
2220 | + break; | |
2221 | + } | |
2222 | + } | |
2223 | +} | |
2224 | + | |
2225 | +void lang_for_each_statement(func) | |
2226 | +void (*func)(); | |
2227 | +{ | |
2228 | + lang_for_each_statement_worker(func, | |
2229 | + statement_list.head); | |
2230 | + | |
2231 | +} |
@@ -0,0 +1,347 @@ | ||
1 | +/* ldlang.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | +typedef enum { | |
23 | + lang_input_file_is_l_enum, | |
24 | + lang_input_file_is_symbols_only_enum, | |
25 | + lang_input_file_is_marker_enum, | |
26 | + lang_input_file_is_fake_enum, | |
27 | +lang_input_file_is_search_file_enum, | |
28 | + lang_input_file_is_file_enum } lang_input_file_enum_type; | |
29 | + | |
30 | +typedef unsigned short fill_type; | |
31 | +typedef struct statement_list { | |
32 | + union lang_statement_union *head; | |
33 | + union lang_statement_union **tail; | |
34 | +} lang_statement_list_type; | |
35 | + | |
36 | + | |
37 | +typedef struct { | |
38 | + boolean flag_read; | |
39 | + boolean flag_write; | |
40 | + boolean flag_executable; | |
41 | + boolean flag_loadable; | |
42 | +} lang_section_flags_type; | |
43 | + | |
44 | +typedef struct memory_region_struct { | |
45 | + char *name; | |
46 | + struct memory_region_struct *next; | |
47 | + bfd_vma origin; | |
48 | + bfd_offset length; | |
49 | + bfd_vma current; | |
50 | + lang_section_flags_type flags; | |
51 | +} lang_memory_region_type ; | |
52 | + | |
53 | +typedef struct lang_statement_header_struct | |
54 | +{ | |
55 | +union lang_statement_union *next; | |
56 | + enum statement_enum { | |
57 | + lang_output_section_statement_enum, | |
58 | + lang_assignment_statement_enum, | |
59 | + lang_input_statement_enum, | |
60 | + lang_address_statement_enum, | |
61 | + lang_wild_statement_enum, | |
62 | + lang_input_section_enum, | |
63 | + lang_common_statement_enum, | |
64 | + lang_object_symbols_statement_enum, | |
65 | + lang_fill_statement_enum, | |
66 | + lang_data_statement_enum, | |
67 | + lang_target_statement_enum, | |
68 | + lang_output_statement_enum, | |
69 | + lang_padding_statement_enum, | |
70 | + | |
71 | + lang_afile_asection_pair_statement_enum | |
72 | + } type; | |
73 | + | |
74 | +} lang_statement_header_type; | |
75 | + | |
76 | + | |
77 | +typedef struct | |
78 | +{ | |
79 | + lang_statement_header_type header; | |
80 | + union etree_union *exp; | |
81 | +} lang_assignment_statement_type; | |
82 | + | |
83 | + | |
84 | +typedef struct lang_target_statement_struct { | |
85 | + lang_statement_header_type header; | |
86 | + char *target; | |
87 | +} lang_target_statement_type; | |
88 | + | |
89 | + | |
90 | +typedef struct lang_output_statement_struct { | |
91 | + lang_statement_header_type header; | |
92 | + char *name; | |
93 | +} lang_output_statement_type; | |
94 | + | |
95 | + | |
96 | +typedef struct lang_output_section_statement_struct | |
97 | +{ | |
98 | + lang_statement_header_type header; | |
99 | + union etree_union *addr_tree; | |
100 | + lang_statement_list_type children; | |
101 | + char *memspec; | |
102 | + union lang_statement_union *next; | |
103 | + char *name; | |
104 | + unsigned long subsection_alignment; | |
105 | + boolean processed; | |
106 | + | |
107 | + asection *bfd_section; | |
108 | + lang_section_flags_type flags; | |
109 | + struct memory_region_struct *region; | |
110 | + size_t block_value; | |
111 | + fill_type fill; | |
112 | +} lang_output_section_statement_type; | |
113 | + | |
114 | + | |
115 | +typedef struct { | |
116 | + lang_statement_header_type header; | |
117 | +} lang_common_statement_type; | |
118 | + | |
119 | +typedef struct { | |
120 | + lang_statement_header_type header; | |
121 | +} lang_object_symbols_statement_type; | |
122 | + | |
123 | +typedef struct { | |
124 | + lang_statement_header_type header; | |
125 | +fill_type fill; | |
126 | +} lang_fill_statement_type; | |
127 | + | |
128 | +typedef struct { | |
129 | + lang_statement_header_type header; | |
130 | + unsigned int type; | |
131 | + union etree_union *exp; | |
132 | + bfd_vma value; | |
133 | + asection *output_section; | |
134 | + bfd_vma output_vma; | |
135 | +} lang_data_statement_type; | |
136 | + | |
137 | + | |
138 | + | |
139 | + | |
140 | +typedef struct lang_input_statement_struct | |
141 | + { | |
142 | + lang_statement_header_type header; | |
143 | + /* Name of this file. */ | |
144 | + char *filename; | |
145 | + /* Name to use for the symbol giving address of text start */ | |
146 | + /* Usually the same as filename, but for a file spec'd with -l | |
147 | + this is the -l switch itself rather than the filename. */ | |
148 | + char *local_sym_name; | |
149 | + | |
150 | + /* Describe the layout of the contents of the file */ | |
151 | + | |
152 | + /* The file's a.out header. */ | |
153 | + /* struct exec header;*/ | |
154 | + /* Offset in file of GDB symbol segment, or 0 if there is none. */ | |
155 | + int symseg_offset; | |
156 | + | |
157 | + /* Describe data from the file loaded into core */ | |
158 | + | |
159 | + bfd *the_bfd; | |
160 | + | |
161 | + boolean closed; | |
162 | + file_ptr passive_position; | |
163 | + | |
164 | + /* Symbol table of the file. */ | |
165 | + asymbol **asymbols; | |
166 | + unsigned int symbol_count; | |
167 | + | |
168 | + /* Next two used only if `relocatable_output' or if needed for */ | |
169 | + /* output of undefined reference line numbers. */ | |
170 | + /* Text reloc info saved by `write_text' for `coptxtrel'. */ | |
171 | + | |
172 | + | |
173 | + /* Offset in bytes in the output file symbol table | |
174 | + of the first local symbol for this file. Set by `write_file_symbols'. */ | |
175 | + int local_syms_offset; | |
176 | + | |
177 | + /* For library members only */ | |
178 | + | |
179 | + /* For a library, points to chain of entries for the library members. */ | |
180 | + struct lang_input_statement_struct *subfiles; | |
181 | + /* For a library member, offset of the member within the archive. | |
182 | + Zero for files that are not library members. */ | |
183 | + /* int starting_offset;*/ | |
184 | + /* Size of contents of this file, if library member. */ | |
185 | + int total_size; | |
186 | + /* For library member, points to the library's own entry. */ | |
187 | + struct lang_input_statement_struct *superfile; | |
188 | + /* For library member, points to next entry for next member. */ | |
189 | + struct lang_input_statement_struct *chain; | |
190 | + /* Point to the next file - whatever it is, wanders up and down archives */ | |
191 | + union lang_statement_union *next; | |
192 | + /* Point to the next file, but skips archive contents */ | |
193 | + union lang_statement_union *next_real_file; | |
194 | + | |
195 | + boolean is_archive; | |
196 | + | |
197 | + /* 1 if file's header has been read into this structure. */ | |
198 | + boolean header_read_flag; | |
199 | + | |
200 | + /* 1 means search a set of directories for this file. */ | |
201 | + boolean search_dirs_flag; | |
202 | + | |
203 | + /* 1 means this is base file of incremental load. | |
204 | + Do not load this file's text or data. | |
205 | + Also default text_start to after this file's bss. */ | |
206 | + boolean just_syms_flag; | |
207 | + | |
208 | + boolean loaded; | |
209 | + | |
210 | + | |
211 | + /* unsigned int globals_in_this_file;*/ | |
212 | + char *target; | |
213 | + boolean real; | |
214 | + | |
215 | + asection *common_section; | |
216 | + asection *common_output_section; | |
217 | + } lang_input_statement_type; | |
218 | + | |
219 | +typedef struct { | |
220 | + lang_statement_header_type header; | |
221 | + asection *section; | |
222 | + lang_input_statement_type *ifile; | |
223 | +} lang_input_section_type; | |
224 | + | |
225 | + | |
226 | +typedef struct { | |
227 | + lang_statement_header_type header; | |
228 | + asection *section; | |
229 | + union lang_statement_union *file; | |
230 | +} lang_afile_asection_pair_statement_type; | |
231 | + | |
232 | +typedef struct lang_wild_statement_struct { | |
233 | + lang_statement_header_type header; | |
234 | + char *section_name; | |
235 | + char *filename; | |
236 | + lang_statement_list_type children; | |
237 | +} lang_wild_statement_type; | |
238 | + | |
239 | +typedef struct lang_address_statement_struct { | |
240 | + lang_statement_header_type header; | |
241 | + char *section_name; | |
242 | + union etree_union *address; | |
243 | +} lang_address_statement_type; | |
244 | + | |
245 | +typedef struct { | |
246 | + lang_statement_header_type header; | |
247 | + bfd_vma output_offset; | |
248 | + size_t size; | |
249 | + asection *output_section; | |
250 | + fill_type fill; | |
251 | +} lang_padding_statement_type; | |
252 | + | |
253 | +typedef union lang_statement_union | |
254 | +{ | |
255 | + lang_statement_header_type header; | |
256 | + union lang_statement_union *next; | |
257 | + lang_wild_statement_type wild_statement; | |
258 | + lang_data_statement_type data_statement; | |
259 | + lang_address_statement_type address_statement; | |
260 | + lang_output_section_statement_type output_section_statement; | |
261 | + lang_afile_asection_pair_statement_type afile_asection_pair_statement; | |
262 | + lang_assignment_statement_type assignment_statement; | |
263 | + lang_input_statement_type input_statement; | |
264 | + lang_target_statement_type target_statement; | |
265 | + lang_output_statement_type output_statement; | |
266 | + lang_input_section_type input_section; | |
267 | + lang_common_statement_type common_statement; | |
268 | + lang_object_symbols_statement_type object_symbols_statement; | |
269 | + lang_fill_statement_type fill_statement; | |
270 | + lang_padding_statement_type padding_statement; | |
271 | +} lang_statement_union_type; | |
272 | + | |
273 | + | |
274 | + | |
275 | +PROTO(void,lang_init,(void)); | |
276 | +PROTO(struct memory_region_struct ,*lang_memory_region_lookup,(char *)); | |
277 | +PROTO(struct lang_output_section_statement_struct *,lang_output_section_find,(char *)); | |
278 | + | |
279 | +PROTO(void ,lang_map,(struct _iobuf *)); | |
280 | +PROTO(void,lang_set_flags,(lang_section_flags_type *, char *)); | |
281 | +PROTO(void,lang_add_output,(char *)); | |
282 | + | |
283 | +PROTO(void,lang_final,(void)); | |
284 | +PROTO(struct symbol_cache_entry *,create_symbol,(char *, unsigned int, struct sec_struct *)); | |
285 | +PROTO(void ,lang_process,(void)); | |
286 | +PROTO(void ,lang_section_start,(char *, union etree_union *)); | |
287 | +PROTO(void,lang_add_entry,(char *)); | |
288 | +PROTO(void,lang_add_target,(char *)); | |
289 | +PROTO(void,lang_add_wild,(char *, char *)); | |
290 | +PROTO(void,lang_add_map,(char *)); | |
291 | +PROTO(void,lang_add_fill,(int)); | |
292 | +PROTO(void,lang_add_assignment,(union etree_union *)); | |
293 | +PROTO(void,lang_add_attribute,(enum statement_enum)); | |
294 | +PROTO(void,lang_startup,(char *)); | |
295 | +PROTO(void,lang_float,(enum boolean)); | |
296 | +PROTO(void,lang_leave_output_section_statement,(bfd_vma, char *)); | |
297 | +PROTO(void,lang_abs_symbol_at_end_of,(char *, char *)); | |
298 | +PROTO(void,lang_statement_append,(struct statement_list *, union lang_statement_union *, union lang_statement_union **)); | |
299 | +PROTO(void, lang_for_each_file,(void (*dothis)(lang_input_statement_type *))); | |
300 | + | |
301 | +#define LANG_FOR_EACH_ASYMBOL(asymbol) \ | |
302 | + | |
303 | +#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \ | |
304 | + extern lang_statement_list_type file_chain; \ | |
305 | + lang_input_statement_type *statement; \ | |
306 | + for (statement = (lang_input_statement_type *)file_chain.head;\ | |
307 | + statement != (lang_input_statement_type *)NULL; \ | |
308 | + statement = (lang_input_statement_type *)statement->next)\ | |
309 | + | |
310 | +#define LANG_FOR_EACH_INPUT_SECTION(statement, abfd, section, x) \ | |
311 | +{ extern lang_statement_list_type file_chain; \ | |
312 | + lang_input_statement_type *statement; \ | |
313 | + for (statement = (lang_input_statement_type *)file_chain.head;\ | |
314 | + statement != (lang_input_statement_type *)NULL; \ | |
315 | + statement = (lang_input_statement_type *)statement->next)\ | |
316 | + { \ | |
317 | + asection *section; \ | |
318 | + bfd *abfd = statement->the_bfd; \ | |
319 | + for (section = abfd->sections; \ | |
320 | + section != (asection *)NULL; \ | |
321 | + section = section->next) { \ | |
322 | + x; \ | |
323 | + } \ | |
324 | + } \ | |
325 | + } | |
326 | + | |
327 | +#define LANG_FOR_EACH_OUTPUT_SECTION(section, x) \ | |
328 | + { extern bfd *output_bfd; \ | |
329 | + asection *section; \ | |
330 | + for (section = output_bfd->sections; \ | |
331 | + section != (asection *)NULL; \ | |
332 | + section = section->next) \ | |
333 | + { x; } \ | |
334 | + } | |
335 | + | |
336 | + | |
337 | +PROTO(void, lang_process,(void)); | |
338 | +PROTO(void, ldlang_add_file,(lang_input_statement_type *)); | |
339 | + | |
340 | +PROTO(lang_output_section_statement_type *,lang_output_section_find,()); | |
341 | + | |
342 | +PROTO(lang_input_statement_type *, | |
343 | + lang_add_input_file,(char *name, | |
344 | + lang_input_file_enum_type file_type, | |
345 | + char *target)); | |
346 | +PROTO(lang_output_section_statement_type *, | |
347 | +lang_output_section_statement_lookup,(char *name)); |
@@ -0,0 +1,26 @@ | ||
1 | +/* ldlex.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +PROTO(int, lex_input, (void)); | |
22 | +PROTO(void, lex_unput, (int)); | |
23 | +PROTO(int ,yywrap,(void)); | |
24 | +PROTO(void, parse_args,(int, char **)); | |
25 | +PROTO(void, parse_line,(char*)); | |
26 | + |
@@ -0,0 +1,490 @@ | ||
1 | +%{ | |
2 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
3 | + | |
4 | +This file is part of GLD, the Gnu Linker. | |
5 | + | |
6 | +GLD is free software; you can redistribute it and/or modify | |
7 | +it under the terms of the GNU General Public License as published by | |
8 | +the Free Software Foundation; either version 1, or (at your option) | |
9 | +any later version. | |
10 | + | |
11 | +GLD is distributed in the hope that it will be useful, | |
12 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | +GNU General Public License for more details. | |
15 | + | |
16 | +You should have received a copy of the GNU General Public License | |
17 | +along with GLD; see the file COPYING. If not, write to | |
18 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | + | |
20 | +/* | |
21 | + * $Id$ | |
22 | + * | |
23 | + * $Log$ | |
24 | + * Revision 1.1 1991/03/21 21:28:50 gumby | |
25 | + * Initial revision | |
26 | + * | |
27 | + * Revision 1.3 1991/03/16 22:27:24 rich | |
28 | + * fish | |
29 | + * | |
30 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
31 | + * foo | |
32 | + * | |
33 | + * Revision 1.1 1991/03/13 00:48:27 chrisb | |
34 | + * Initial revision | |
35 | + * | |
36 | + * Revision 1.6 1991/03/10 09:31:32 rich | |
37 | + * Modified Files: | |
38 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
39 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
40 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
41 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
42 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
43 | + * | |
44 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
45 | + * interest and copy passes my copy test on big endian hosts again. | |
46 | + * | |
47 | + * Revision 1.5 1991/03/09 03:25:49 sac | |
48 | + * Can now parse the -Ur flag | |
49 | + * | |
50 | + * Revision 1.4 1991/03/06 02:26:04 sac | |
51 | + * Added support for constructor sections. | |
52 | + * Remove parsing ambiguity. | |
53 | + * Lint | |
54 | + * | |
55 | + * Revision 1.3 1991/02/22 17:15:14 sac | |
56 | + * Added RCS keywords and copyrights | |
57 | + * | |
58 | +*/ | |
59 | + | |
60 | + | |
61 | + | |
62 | +/*SUPPRESS 529*/ | |
63 | +/*SUPPRESS 26*/ | |
64 | +/*SUPPRESS 29*/ | |
65 | +#define LEXDEBUG | |
66 | +#include "sysdep.h" | |
67 | +#include "bfd.h" | |
68 | + | |
69 | +#include <ctype.h> | |
70 | +#include "ldlex.h" | |
71 | + | |
72 | +#include "ld.h" | |
73 | +#include "ldexp.h" | |
74 | +#include "ldgram.tab.h" | |
75 | +#include "ldmisc.h" | |
76 | + | |
77 | +#undef input | |
78 | +#undef unput | |
79 | +#define input lex_input | |
80 | +#define unput lex_unput | |
81 | +int debug; | |
82 | +extern boolean ldgram_want_filename; | |
83 | +extern boolean ldgram_mustbe_filename; | |
84 | +extern boolean ldgram_mustbe_symbolname; | |
85 | +static char *command_line; | |
86 | + | |
87 | +extern int fgetc(); | |
88 | +extern int yyparse(); | |
89 | + | |
90 | +typedef struct { | |
91 | + char *name; | |
92 | +int value; | |
93 | +} keyword_type; | |
94 | +#define RTOKEN(x) { yylval.token = x; return x; } | |
95 | +keyword_type keywords[] = | |
96 | +{ | |
97 | +"MEMORY",MEMORY, | |
98 | +"ORIGIN",ORIGIN, | |
99 | +"BLOCK",BLOCK, | |
100 | +"LENGTH",LENGTH, | |
101 | +"ALIGN",ALIGN_K, | |
102 | +"SUBSECTION_ALIGN",SUBSECTION_ALIGN, | |
103 | +"ADDR",ADDR, | |
104 | +"ENTRY",ENTRY, | |
105 | +"NEXT",NEXT, | |
106 | +"MAP",MAP, | |
107 | +"SIZEOF",SIZEOF, | |
108 | +"TARGET",TARGET_K, | |
109 | +"SEARCH_DIR",SEARCH_DIR, | |
110 | +"OUTPUT",OUTPUT, | |
111 | +"INPUT",INPUT, | |
112 | +"DEFINED",DEFINED, | |
113 | +"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS, | |
114 | +"SECTIONS",SECTIONS, | |
115 | +"FILL",FILL, | |
116 | +"STARTUP",STARTUP, | |
117 | +"HLL",HLL, | |
118 | +"SYSLIB",SYSLIB, | |
119 | +"FLOAT",FLOAT, | |
120 | +"LONG", LONG, | |
121 | +"SHORT", SHORT, | |
122 | +"BYTE", BYTE, | |
123 | +"NOFLOAT",NOFLOAT, | |
124 | +"o",ORIGIN, | |
125 | +"org",ORIGIN, | |
126 | +"l", LENGTH, | |
127 | +"len", LENGTH, | |
128 | +0,0}; | |
129 | +unsigned int lineno; | |
130 | +extern boolean hex_mode; | |
131 | +FILE *ldlex_input_stack; | |
132 | +static unsigned int have_pushback; | |
133 | +#define NPUSHBACK 10 | |
134 | +int pushback[NPUSHBACK]; | |
135 | +int thischar; | |
136 | +extern char *ldfile_input_filename; | |
137 | + | |
138 | +int | |
139 | +lex_input() | |
140 | +{ | |
141 | + /* | |
142 | + When we know that the next token must be a filename we force the | |
143 | + input routine to return a '#' character, which will cause the special | |
144 | + filname regexp to match the following chars even if they don't look | |
145 | + much like a filename to any sane person. | |
146 | + */ | |
147 | + if (ldgram_mustbe_filename) { | |
148 | + ldgram_mustbe_filename = false; | |
149 | + return '#'; | |
150 | + } | |
151 | + | |
152 | + if (have_pushback > 0) | |
153 | + { | |
154 | + have_pushback --; | |
155 | + return thischar = pushback[have_pushback]; | |
156 | + } | |
157 | + if (ldlex_input_stack) { | |
158 | + thischar = fgetc(ldlex_input_stack); | |
159 | + | |
160 | + if (thischar == EOF) { | |
161 | + fclose(ldlex_input_stack); | |
162 | + ldlex_input_stack = (FILE *)NULL; | |
163 | + ldfile_input_filename = (char *)NULL; | |
164 | + thischar = lex_input(); | |
165 | + | |
166 | + } | |
167 | + } | |
168 | + else if (command_line && *command_line) { | |
169 | + thischar = *(command_line++); | |
170 | + } | |
171 | + else thischar = 0; | |
172 | + if(thischar == '\t') thischar = ' '; | |
173 | + return thischar ; | |
174 | +} | |
175 | + | |
176 | +void | |
177 | +lex_unput(c) | |
178 | +int c; | |
179 | +{ | |
180 | + if (have_pushback > NPUSHBACK) { | |
181 | + info("%F%P Too many pushbacks\n"); | |
182 | + } | |
183 | + | |
184 | + pushback[have_pushback] = c; | |
185 | + have_pushback ++; | |
186 | +} | |
187 | + | |
188 | + | |
189 | + int | |
190 | +yywrap() | |
191 | + { return 1; } | |
192 | +/*VARARGS*/ | |
193 | + | |
194 | +void | |
195 | +allprint(x) | |
196 | +int x; | |
197 | +{ | |
198 | +fprintf(yyout,"%d",x); | |
199 | +} | |
200 | + | |
201 | +void | |
202 | +sprint(x) | |
203 | +char *x; | |
204 | +{ | |
205 | +fprintf(yyout,"%s",x); | |
206 | +} | |
207 | + | |
208 | +int thischar; | |
209 | + | |
210 | +void parse_line(arg) | |
211 | +char *arg; | |
212 | +{ | |
213 | + command_line = arg; | |
214 | + have_pushback = 0; | |
215 | + yyparse(); | |
216 | +} | |
217 | + | |
218 | + | |
219 | + | |
220 | +void | |
221 | +parse_args(ac, av) | |
222 | +int ac; | |
223 | +char **av; | |
224 | +{ | |
225 | + char *p; | |
226 | + int i; | |
227 | + size_t size = 0; | |
228 | + char *dst; | |
229 | + debug = 1; | |
230 | + for (i= 1; i < ac; i++) { | |
231 | + size += strlen(av[i]) + 2; | |
232 | + } | |
233 | + dst = p = (char *)ldmalloc(size + 2); | |
234 | +/* Put a space arount each option */ | |
235 | + | |
236 | + | |
237 | + for (i =1; i < ac; i++) { | |
238 | + | |
239 | + unsigned int s = strlen(av[i]); | |
240 | + *dst++ = ' '; | |
241 | + memcpy(dst, av[i], s); | |
242 | + dst[s] = ' '; | |
243 | + dst += s + 1; | |
244 | + } | |
245 | + *dst = 0; | |
246 | + parse_line(p); | |
247 | + | |
248 | + free(p); | |
249 | + | |
250 | + | |
251 | +} | |
252 | + | |
253 | +long number(text, base) | |
254 | +char *text; | |
255 | +int base; | |
256 | +{ | |
257 | +unsigned long l = 0; | |
258 | + char *p; | |
259 | + for (p = text; *p != 0; p++) { | |
260 | + if (*p == 'K') { | |
261 | + l =l * 1024; | |
262 | + } | |
263 | + else if(*p== 'M') { | |
264 | + l =l * 1024 * 1024; | |
265 | + } | |
266 | + else { | |
267 | + l =l * base; | |
268 | + if (isdigit(*p)) { | |
269 | + l += *p - '0'; | |
270 | + } | |
271 | + else if (islower(*p)) { | |
272 | + l += *p - 'a' + 10; | |
273 | + } | |
274 | + else { | |
275 | + l += *p - 'A' + 10; | |
276 | + } | |
277 | + } | |
278 | + } | |
279 | + return l; | |
280 | +} | |
281 | +%} | |
282 | + | |
283 | +%a 4000 | |
284 | +%o 5000 | |
285 | +FILENAMECHAR [a-zA-Z0-9\/\.\-\_\+] | |
286 | +FILENAME {FILENAMECHAR}+ | |
287 | + | |
288 | + | |
289 | +WHITE [ \t]+ | |
290 | + | |
291 | +%% | |
292 | +"\n" { lineno++; } | |
293 | + | |
294 | + | |
295 | +"\ -defsym" { return OPTION_defsym; } | |
296 | +"\ -noinhibit_exec" { return OPTION_noinhibit_exec; } | |
297 | +"\ -format" { return OPTION_format; } | |
298 | +"\ -n" { return OPTION_n; } | |
299 | +"\ -r" { return OPTION_r; } | |
300 | +"\ -Ur" { return OPTION_Ur; } | |
301 | +"\ -o" { return OPTION_o; } | |
302 | +"\ -g" { return OPTION_g; } | |
303 | +"\ -e" { return OPTION_e; } | |
304 | +"\ -b" { return OPTION_b; } | |
305 | +"\ -dc" { return OPTION_dc; } | |
306 | +"\ -dp" { return OPTION_dp; } | |
307 | +"\ -d" { return OPTION_d; } | |
308 | +"\ -v" { return OPTION_v; } | |
309 | +"\ -M" { return OPTION_M; } | |
310 | +"\ -t" { return OPTION_t; } | |
311 | +"\ -X" { return OPTION_X; } | |
312 | +"\ -x" { return OPTION_x; } | |
313 | +"\ -c" { return OPTION_c; } | |
314 | +"\ -s" { return OPTION_s; } | |
315 | +"\ -S" { return OPTION_S; } | |
316 | +"\ -l"{FILENAME} { | |
317 | + yylval.name = buystring(yytext+3); | |
318 | + return OPTION_l; | |
319 | + } | |
320 | + | |
321 | +"\ -L"{FILENAME} { | |
322 | + yylval.name = buystring(yytext+3); | |
323 | + return OPTION_L; | |
324 | + } | |
325 | +"\ -Ttext" { | |
326 | + yylval.name = ".text"; | |
327 | + return OPTION_Texp; | |
328 | + } | |
329 | +"\ -Tdata" { | |
330 | + yylval.name = ".data"; | |
331 | + return OPTION_Texp; | |
332 | + } | |
333 | +"\ -Tbss" { | |
334 | + yylval.name = ".bss"; | |
335 | + return OPTION_Texp; | |
336 | + } | |
337 | + | |
338 | +"\ -T"{FILENAME} { | |
339 | + yylval.name = buystring(yytext+3); | |
340 | + return OPTION_Tfile; | |
341 | + } | |
342 | +"\ -T" { | |
343 | + return OPTION_T; | |
344 | + } | |
345 | + | |
346 | +"\ -A"{FILENAME} { | |
347 | + yylval.name = buystring(yytext+3); | |
348 | + return OPTION_Aarch; | |
349 | + } | |
350 | +" " { } | |
351 | +"<<=" { RTOKEN(LSHIFTEQ);} | |
352 | +">>=" { RTOKEN(RSHIFTEQ);} | |
353 | +"||" { RTOKEN(OROR);} | |
354 | +"==" { RTOKEN(EQ);} | |
355 | +"!=" { RTOKEN(NE);} | |
356 | +">=" { RTOKEN(GE);} | |
357 | +"<=" { RTOKEN(LE);} | |
358 | +"<<" { RTOKEN(LSHIFT);} | |
359 | +">>" { RTOKEN(RSHIFT);} | |
360 | +"+=" { RTOKEN(PLUSEQ);} | |
361 | +"-=" { RTOKEN(MINUSEQ);} | |
362 | +"*=" { RTOKEN(MULTEQ);} | |
363 | +"/=" { RTOKEN(DIVEQ);} | |
364 | +"&=" { RTOKEN(ANDEQ);} | |
365 | +"|=" { RTOKEN(OREQ);} | |
366 | + | |
367 | +"&&" { RTOKEN(ANDAND);} | |
368 | +">" { RTOKEN('>');} | |
369 | +"," { RTOKEN(',');} | |
370 | +"&" { RTOKEN('&');} | |
371 | +"|" { RTOKEN('|');} | |
372 | +"~" { RTOKEN('~');} | |
373 | +"!" { RTOKEN('!');} | |
374 | +"?" { RTOKEN('?');} | |
375 | +"*" { RTOKEN('*');} | |
376 | +"%" { RTOKEN('%');} | |
377 | +"<" { RTOKEN('<');} | |
378 | +"+" { RTOKEN('+');} | |
379 | +">" { RTOKEN('>');} | |
380 | +"}" { RTOKEN('}') ; } | |
381 | +"{" { RTOKEN('{'); } | |
382 | +")" { RTOKEN(')');} | |
383 | +"(" { RTOKEN('(');} | |
384 | +"]" { RTOKEN(']');} | |
385 | +"[" { RTOKEN('[');} | |
386 | +":" { RTOKEN(':'); } | |
387 | +";" { RTOKEN(';');} | |
388 | +"-" { RTOKEN('-');} | |
389 | +"=" { RTOKEN('=');} | |
390 | + | |
391 | + | |
392 | +"/*" { | |
393 | + while (1) { | |
394 | + int ch; | |
395 | + ch = input(); | |
396 | + while (ch != '*') { | |
397 | + if (ch == '\n') {lineno++; } | |
398 | + ch = input(); | |
399 | + } | |
400 | + | |
401 | + | |
402 | + | |
403 | + if (input() == '/') { | |
404 | + break; | |
405 | + } | |
406 | + unput(yytext[yyleng-1]); | |
407 | + } | |
408 | +} | |
409 | + | |
410 | +"\""[^\"]*"\"" { | |
411 | + | |
412 | + yylval.name = buystring(yytext+1); | |
413 | + yylval.name[yyleng-2] = 0; /* Fry final quote */ | |
414 | + return NAME; | |
415 | +} | |
416 | +[0][0-7KM]* { | |
417 | + | |
418 | + yylval.integer = number(yytext+1, 8); | |
419 | + return INT; | |
420 | +} | |
421 | + | |
422 | +[0-9]+[KM]? { | |
423 | + if (hex_mode == true) { | |
424 | + yylval.integer = number(yytext, 16); | |
425 | + } | |
426 | + else { | |
427 | + yylval.integer = number(yytext, 10); | |
428 | + } | |
429 | + return INT; | |
430 | +} | |
431 | + | |
432 | +0[Xx][0-9a-fA-FKM]+ { | |
433 | + | |
434 | + yylval.integer = number(yytext+2,16); | |
435 | + return INT; | |
436 | +} | |
437 | + | |
438 | +"\#"{WHITE}*{FILENAMECHAR}+ { | |
439 | + char *p = yytext+1; | |
440 | + while(*p ==' ' || *p == '\t') p++; | |
441 | + yylval.name = buystring(p); | |
442 | + return NAME; | |
443 | +} | |
444 | + | |
445 | + | |
446 | +{FILENAMECHAR} { | |
447 | + | |
448 | +int ch; | |
449 | + keyword_type *k; | |
450 | + if (yytext[0] == '/' && ldgram_mustbe_symbolname) | |
451 | + { RTOKEN('/');} | |
452 | + ch = input(); | |
453 | + while (true) { | |
454 | + if (isalpha(ch) || isdigit(ch) || ch == '.' || ch == '_') { | |
455 | + yytext[yyleng++] = ch; | |
456 | + } | |
457 | + else if (ch == '-' && ldgram_want_filename == true) { | |
458 | + yytext[yyleng++] = ch; | |
459 | + } | |
460 | + else if (ch == '+' && ldgram_want_filename == true) { | |
461 | + yytext[yyleng++] = ch; | |
462 | + } | |
463 | + | |
464 | + else if (ch == '/' && ldgram_want_filename == true) { | |
465 | + yytext[yyleng++] = ch; | |
466 | + } | |
467 | + | |
468 | + else break; | |
469 | + ch = input(); | |
470 | + } | |
471 | + | |
472 | + yytext[yyleng] = 0; | |
473 | + unput(ch); | |
474 | + | |
475 | + for(k = keywords; k ->name != (char *)NULL; k++) { | |
476 | + | |
477 | + if (strcmp(k->name, yytext)==0) { | |
478 | + yylval.token = k->value; | |
479 | + return k->value; | |
480 | + } | |
481 | + } | |
482 | + yylval.name = buystring(yytext); | |
483 | + return NAME; | |
484 | +} | |
485 | + | |
486 | + | |
487 | + | |
488 | + | |
489 | + | |
490 | +%% |
@@ -0,0 +1,806 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + * Written by Steve Chamberlain steve@cygnus.com | |
21 | + * | |
22 | + * $Id$ | |
23 | + * | |
24 | + * $Log$ | |
25 | + * Revision 1.1 1991/03/21 21:28:52 gumby | |
26 | + * Initial revision | |
27 | + * | |
28 | + * Revision 1.1 1991/03/13 00:48:27 chrisb | |
29 | + * Initial revision | |
30 | + * | |
31 | + * Revision 1.7 1991/03/10 19:15:45 sac | |
32 | + * Fixed a prototype problem | |
33 | + * | |
34 | + * Revision 1.6 1991/03/10 09:31:32 rich | |
35 | + * Modified Files: | |
36 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
37 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
38 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
39 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
40 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
41 | + * | |
42 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
43 | + * interest and copy passes my copy test on big endian hosts again. | |
44 | + * | |
45 | + * Revision 1.5 1991/03/09 03:31:02 sac | |
46 | + * After a fatal info message, the output file is deleted. | |
47 | + * | |
48 | + * Revision 1.4 1991/03/06 02:28:31 sac | |
49 | + * Fixed partial linking and error messages. | |
50 | + * | |
51 | + * Revision 1.3 1991/02/22 17:15:02 sac | |
52 | + * Added RCS keywords and copyrights | |
53 | + * | |
54 | + * | |
55 | + */ | |
56 | + | |
57 | + | |
58 | +#include "sysdep.h" | |
59 | +#include "bfd.h" | |
60 | + | |
61 | +#include "config.h" | |
62 | +#include "ld.h" | |
63 | +#include "ldmain.h" | |
64 | +#include "ldmisc.h" | |
65 | +#include "ldwrite.h" | |
66 | +#include "ldgram.h" | |
67 | +#include "ldsym.h" | |
68 | +#include "ldlang.h" | |
69 | +#include "ld-emul.h" | |
70 | +#include "ldlex.h" | |
71 | +#include "ldfile.h" | |
72 | + | |
73 | +/* IMPORTS */ | |
74 | +extern boolean lang_has_input_file; | |
75 | + | |
76 | +/* EXPORTS */ | |
77 | + | |
78 | +char *default_target; | |
79 | +char *output_filename = "a.out"; | |
80 | +/* Name this program was invoked by. */ | |
81 | +char *program_name; | |
82 | + | |
83 | +/* The file that we're creating */ | |
84 | +bfd *output_bfd; | |
85 | + | |
86 | +extern boolean option_v; | |
87 | + | |
88 | +/* The local symbol prefix */ | |
89 | +char lprefix = 'L'; | |
90 | + | |
91 | +/* Count the number of global symbols multiply defined. */ | |
92 | +int multiple_def_count; | |
93 | + | |
94 | + | |
95 | +/* Count the number of symbols defined through common declarations. | |
96 | + This count is referenced in symdef_library, linear_library, and | |
97 | + modified by enter_global_ref. | |
98 | + | |
99 | + It is incremented when a symbol is created as a common, and | |
100 | + decremented when the common declaration is overridden | |
101 | + | |
102 | + Another way of thinking of it is that this is a count of | |
103 | + all ldsym_types with a ->scoms field | |
104 | +*/ | |
105 | +unsigned int commons_pending; | |
106 | + | |
107 | + | |
108 | +/* Count the number of global symbols referenced and not defined. | |
109 | + common symbols are not included in this count. | |
110 | + */ | |
111 | + | |
112 | +unsigned int undefined_global_sym_count; | |
113 | + | |
114 | + | |
115 | + | |
116 | +/* Count the number of warning symbols encountered. */ | |
117 | +int warning_count; | |
118 | + | |
119 | +/* have we had a load script ? */ | |
120 | +extern boolean had_script; | |
121 | + | |
122 | + | |
123 | + | |
124 | +/* Nonzero means print names of input files as processed. */ | |
125 | +boolean trace_files; | |
126 | + | |
127 | + | |
128 | + | |
129 | +/* 1 => write load map. */ | |
130 | +boolean write_map; | |
131 | + | |
132 | + | |
133 | +int unix_relocate; | |
134 | + | |
135 | + | |
136 | + | |
137 | + | |
138 | + | |
139 | + | |
140 | + | |
141 | + | |
142 | +/* Force the make_executable to be output, even if there are non-fatal | |
143 | + errors */ | |
144 | +boolean force_make_executable; | |
145 | + | |
146 | + | |
147 | +/* A count of the total number of local symbols ever seen - by adding | |
148 | + the symbol_count field of each newly read afile.*/ | |
149 | + | |
150 | + | |
151 | +unsigned int total_symbols_seen; | |
152 | + | |
153 | +/* A count of the number of read files - the same as the number of elements | |
154 | + in file_chain | |
155 | + */ | |
156 | +unsigned int total_files_seen; | |
157 | + | |
158 | + | |
159 | +/* IMPORTS */ | |
160 | +args_type command_line; | |
161 | +ld_config_type config; | |
162 | +int | |
163 | +main (argc, argv) | |
164 | + char **argv; | |
165 | + int argc; | |
166 | +{ | |
167 | + char *emulation; | |
168 | + program_name = argv[0]; | |
169 | + output_filename = "a.out"; | |
170 | + | |
171 | + emulation = getenv(EMULATION_ENVIRON); | |
172 | + | |
173 | + /* Initialize the data about options. */ | |
174 | + strip_symbols = STRIP_NONE; | |
175 | + trace_files = false; | |
176 | + discard_locals = DISCARD_NONE; | |
177 | + | |
178 | + write_map = false; | |
179 | + config.relocateable_output = false; | |
180 | + unix_relocate = 0; | |
181 | + command_line.force_common_definition = false; | |
182 | + | |
183 | + ldfile_add_arch(""); | |
184 | + | |
185 | + config.make_executable = true; | |
186 | + force_make_executable = false; | |
187 | + | |
188 | + | |
189 | + /* Initialize the cumulative counts of symbols. */ | |
190 | + undefined_global_sym_count = 0; | |
191 | + warning_count = 0; | |
192 | + multiple_def_count = 0; | |
193 | + commons_pending = 0; | |
194 | + | |
195 | + config.magic_demand_paged = true ; | |
196 | + config.make_executable = true; | |
197 | + | |
198 | + if (emulation == (char *)NULL) { | |
199 | + emulation= DEFAULT_EMULATION; | |
200 | + } | |
201 | + ldemul_choose_mode(emulation); | |
202 | + | |
203 | + default_target = ldemul_choose_target(); | |
204 | + | |
205 | + lang_init(); | |
206 | + ldemul_before_parse(); | |
207 | + | |
208 | + lang_has_input_file = false; | |
209 | + parse_args(argc, argv); | |
210 | + | |
211 | + if (lang_has_input_file == false) { | |
212 | + info("%P%F: No input files\n"); | |
213 | + } | |
214 | + | |
215 | + ldemul_after_parse(); | |
216 | + | |
217 | + lang_process(); | |
218 | + | |
219 | + | |
220 | + | |
221 | + | |
222 | + /* Print error messages for any missing symbols, for any warning | |
223 | + symbols, and possibly multiple definitions */ | |
224 | + | |
225 | + /* Print a map, if requested. */ | |
226 | + | |
227 | + if (write_map) { | |
228 | + ldsym_print_symbol_table (); | |
229 | + lang_map(stdout); | |
230 | + } | |
231 | + | |
232 | + | |
233 | + if (config.relocateable_output) { | |
234 | + output_bfd->flags &= ~( D_PAGED); | |
235 | + output_bfd->flags |= EXEC_P; | |
236 | + ldwrite(); | |
237 | + bfd_close(output_bfd); | |
238 | + } | |
239 | + else { | |
240 | + output_bfd->flags |= EXEC_P; | |
241 | + | |
242 | + ldwrite(); | |
243 | + bfd_close(output_bfd); | |
244 | + if (config.make_executable == false && force_make_executable == false) { | |
245 | + unlink(output_filename); | |
246 | + } | |
247 | + return (!config.make_executable); | |
248 | + } | |
249 | + | |
250 | + return(0); | |
251 | +} /* main() */ | |
252 | + | |
253 | + | |
254 | +void | |
255 | +Q_read_entry_symbols (desc, entry) | |
256 | + bfd *desc; | |
257 | + struct lang_input_statement_struct *entry; | |
258 | +{ | |
259 | + if (entry->asymbols == (asymbol **)NULL) { | |
260 | + size_t table_size = get_symtab_upper_bound(desc); | |
261 | + entry->asymbols = (asymbol **)ldmalloc(table_size); | |
262 | + | |
263 | + entry->symbol_count = bfd_canonicalize_symtab(desc, entry->asymbols) ; | |
264 | + } | |
265 | +} | |
266 | + | |
267 | + | |
268 | +/* | |
269 | + * turn this item into a reference | |
270 | + */ | |
271 | +static void | |
272 | +refize(sp, nlist_p) | |
273 | +ldsym_type *sp; | |
274 | +asymbol **nlist_p; | |
275 | +{ | |
276 | + asymbol *sym = *nlist_p; | |
277 | + sym->value = 0; | |
278 | + sym->flags = BSF_UNDEFINED; | |
279 | + sym->section = (asection *)NULL; | |
280 | + sym->udata =(void *)( sp->srefs_chain); | |
281 | + sp->srefs_chain = nlist_p; | |
282 | +} | |
283 | +/* | |
284 | +This function is called for each name which is seen which has a global | |
285 | +scope. It enters the name into the global symbol table in the correct | |
286 | +symbol on the correct chain. Remember that each ldsym_type has three | |
287 | +chains attatched, one of all definitions of a symbol, one of all | |
288 | +references of a symbol and one of all common definitions of a symbol. | |
289 | + | |
290 | +When the function is over, the supplied is left connected to the bfd | |
291 | +to which is was born, with its udata field pointing to the next member | |
292 | +on the chain in which it has been inserted. | |
293 | + | |
294 | +A certain amount of jigery pokery is necessary since commons come | |
295 | +along and upset things, we only keep one item in the common chain; the | |
296 | +one with the biggest size seen sofar. When another common comes along | |
297 | +it either bumps the previous definition into the ref chain, since it | |
298 | +is bigger, or gets turned into a ref on the spot since the one on the | |
299 | +common chain is already bigger. If a real definition comes along then | |
300 | +the common gets bumped off anyway. | |
301 | + | |
302 | +Whilst all this is going on we keep a count of the number of multiple | |
303 | +definitions seen, undefined global symbols and pending commons. | |
304 | +*/ | |
305 | + | |
306 | + | |
307 | +void | |
308 | +Q_enter_global_ref (nlist_p) | |
309 | + asymbol **nlist_p; | |
310 | + | |
311 | +{ | |
312 | + asymbol *sym = *nlist_p; | |
313 | + char *name = sym->name; | |
314 | + ldsym_type *sp = ldsym_get (name); | |
315 | + | |
316 | + flagword this_symbol_flags = sym->flags; | |
317 | + | |
318 | + | |
319 | + ASSERT(sym->udata == 0); | |
320 | + | |
321 | + /* Just place onto correct chain */ | |
322 | + if (flag_is_common(this_symbol_flags)) { | |
323 | + /* If we have a definition of this symbol already then | |
324 | + * this common turns into a reference. Also we only | |
325 | + * ever point to the largest common, so if we | |
326 | + * have a common, but it's bigger that the new symbol | |
327 | + * the turn this into a reference too. | |
328 | + */ | |
329 | + if (sp->sdefs_chain) | |
330 | + { | |
331 | + /* This is a common symbol, but we already have a definition | |
332 | + for it, so just link it into the ref chain as if | |
333 | + it were a reference | |
334 | + */ | |
335 | + refize(sp, nlist_p); | |
336 | + } | |
337 | + else if (sp->scoms_chain) { | |
338 | + /* If we have a previous common, keep only the biggest */ | |
339 | + if ( (*(sp->scoms_chain))->value > sym->value) { | |
340 | + /* other common is bigger, throw this one away */ | |
341 | + refize(sp, nlist_p); | |
342 | + } | |
343 | + else if (sp->scoms_chain != nlist_p) { | |
344 | + /* other common is smaller, throw that away */ | |
345 | + refize(sp, sp->scoms_chain); | |
346 | + sp->scoms_chain = nlist_p; | |
347 | + } | |
348 | + } | |
349 | + else { | |
350 | + /* This is the first time we've seen a common, so | |
351 | + * remember it - if it was undefined before, we know it's defined now | |
352 | + */ | |
353 | + if (sp->srefs_chain) | |
354 | + undefined_global_sym_count--; | |
355 | + | |
356 | + commons_pending++; | |
357 | + sp->scoms_chain = nlist_p; | |
358 | + } | |
359 | + } | |
360 | + | |
361 | + else if (flag_is_defined(this_symbol_flags)) { | |
362 | + /* This is the definition of a symbol, add to def chain */ | |
363 | + if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) { | |
364 | + /* Multiple definition */ | |
365 | + asymbol *sy = *(sp->sdefs_chain); | |
366 | + lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata; | |
367 | + lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata; | |
368 | + asymbol ** stat1_symbols = stat1 ? stat1->asymbols: 0; | |
369 | + asymbol ** stat_symbols = stat ? stat->asymbols:0; | |
370 | + | |
371 | + multiple_def_count++; | |
372 | + info("%C: multiple definition of `%T'\n", | |
373 | + sym->the_bfd, | |
374 | + sym->section, | |
375 | + stat1_symbols, | |
376 | + sym->value, | |
377 | + sym); | |
378 | + | |
379 | + info("%C: first seen here\n", | |
380 | + sy->the_bfd, | |
381 | + sy->section, | |
382 | + stat_symbols, | |
383 | + sy->value); | |
384 | + } | |
385 | + else { | |
386 | + sym->udata =(void *)( sp->sdefs_chain); | |
387 | + sp->sdefs_chain = nlist_p; | |
388 | + } | |
389 | + /* A definition overrides a common symbol */ | |
390 | + if (sp->scoms_chain) { | |
391 | + refize(sp, sp->scoms_chain); | |
392 | + sp->scoms_chain = 0; | |
393 | + commons_pending--; | |
394 | + } | |
395 | + else if (sp->srefs_chain) { | |
396 | + /* If previously was undefined, then remember as defined */ | |
397 | + undefined_global_sym_count--; | |
398 | + } | |
399 | + } | |
400 | + else { | |
401 | + if (sp->scoms_chain == (asymbol **)NULL | |
402 | + && sp->srefs_chain == (asymbol **)NULL | |
403 | + && sp->sdefs_chain == (asymbol **)NULL) { | |
404 | + /* And it's the first time we've seen it */ | |
405 | + undefined_global_sym_count++; | |
406 | + | |
407 | + } | |
408 | + | |
409 | + refize(sp, nlist_p); | |
410 | + } | |
411 | + | |
412 | + ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0); | |
413 | + ASSERT(sp->scoms_chain ==0 || (*(sp->scoms_chain))->udata == 0); | |
414 | + | |
415 | + | |
416 | +} | |
417 | + | |
418 | +static void | |
419 | +Q_enter_file_symbols (entry) | |
420 | +lang_input_statement_type *entry; | |
421 | +{ | |
422 | + asymbol **q ; | |
423 | + entry->common_section = | |
424 | + bfd_make_section(entry->the_bfd, "COMMON"); | |
425 | + | |
426 | + ldlang_add_file(entry); | |
427 | + | |
428 | + | |
429 | + if (trace_files || option_v) { | |
430 | + info("%I\n", entry); | |
431 | + } | |
432 | + | |
433 | + total_symbols_seen += entry->symbol_count; | |
434 | + total_files_seen ++; | |
435 | + for (q = entry->asymbols; *q; q++) | |
436 | + { | |
437 | + asymbol *p = *q; | |
438 | + | |
439 | + if (flag_is_undefined_or_global_or_common(p->flags)) | |
440 | + { | |
441 | + | |
442 | + Q_enter_global_ref(q); | |
443 | + } | |
444 | + ASSERT(p->flags != 0); | |
445 | + } | |
446 | +} | |
447 | + | |
448 | + | |
449 | + | |
450 | +/* Searching libraries */ | |
451 | + | |
452 | +struct lang_input_statement_struct *decode_library_subfile (); | |
453 | +void linear_library (), symdef_library (); | |
454 | + | |
455 | +/* Search the library ENTRY, already open on descriptor DESC. | |
456 | + This means deciding which library members to load, | |
457 | + making a chain of `struct lang_input_statement_struct' for those members, | |
458 | + and entering their global symbols in the hash table. */ | |
459 | + | |
460 | +void | |
461 | +search_library (entry) | |
462 | + struct lang_input_statement_struct *entry; | |
463 | +{ | |
464 | + | |
465 | + /* No need to load a library if no undefined symbols */ | |
466 | + if (!undefined_global_sym_count) return; | |
467 | + | |
468 | + if (bfd_has_map(entry->the_bfd)) | |
469 | + symdef_library (entry); | |
470 | + else | |
471 | + linear_library (entry); | |
472 | + | |
473 | +} | |
474 | + | |
475 | + | |
476 | +void | |
477 | +Q_read_file_symbols (entry) | |
478 | +struct lang_input_statement_struct *entry; | |
479 | +{ | |
480 | + if (entry->asymbols == (asymbol **)NULL | |
481 | + &&entry->real == true | |
482 | + && entry->filename != (char *)NULL) | |
483 | + { | |
484 | + ldfile_open_file (entry); | |
485 | + | |
486 | + if (bfd_check_format(entry->the_bfd, bfd_object)) | |
487 | + { | |
488 | + entry->the_bfd->usrdata = (void*)entry; | |
489 | + | |
490 | + | |
491 | + Q_read_entry_symbols (entry->the_bfd, entry); | |
492 | + Q_enter_file_symbols (entry); | |
493 | + } | |
494 | + else if (bfd_check_format(entry->the_bfd, bfd_archive)) | |
495 | + { | |
496 | + entry->the_bfd->usrdata = (void *)entry; | |
497 | + | |
498 | + entry->subfiles = (lang_input_statement_type *)NULL; | |
499 | + search_library (entry); | |
500 | + } | |
501 | + else | |
502 | + { | |
503 | + info("%F%I: malformed input file (not rel or archive) \n", entry); | |
504 | + } | |
505 | + } | |
506 | + | |
507 | +} | |
508 | + | |
509 | + | |
510 | +/* Construct and return a lang_input_statement_struct for a library member. | |
511 | + The library's lang_input_statement_struct is library_entry, | |
512 | + and the library is open on DESC. | |
513 | + SUBFILE_OFFSET is the byte index in the library of this member's header. | |
514 | + We store the length of the member into *LENGTH_LOC. */ | |
515 | + | |
516 | +lang_input_statement_type * | |
517 | +decode_library_subfile (library_entry, subfile_offset) | |
518 | + struct lang_input_statement_struct *library_entry; | |
519 | + bfd *subfile_offset; | |
520 | +{ | |
521 | + register struct lang_input_statement_struct *subentry; | |
522 | + subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct)); | |
523 | + subentry->filename = subfile_offset -> filename; | |
524 | + subentry->local_sym_name = subfile_offset->filename; | |
525 | + subentry->asymbols = 0; | |
526 | + subentry->the_bfd = subfile_offset; | |
527 | + subentry->subfiles = 0; | |
528 | + subentry->next = 0; | |
529 | + subentry->superfile = library_entry; | |
530 | + subentry->is_archive = false; | |
531 | + subentry->header_read_flag = false; | |
532 | + subentry->just_syms_flag = false; | |
533 | + subentry->loaded = false; | |
534 | + subentry->chain = 0; | |
535 | + | |
536 | + return subentry; | |
537 | +} | |
538 | + | |
539 | +boolean subfile_wanted_p (); | |
540 | +void | |
541 | +clear_syms(entry, offset) | |
542 | +struct lang_input_statement_struct *entry; | |
543 | +file_ptr offset; | |
544 | +{ | |
545 | + carsym *car; | |
546 | + unsigned long indx = bfd_get_next_mapent(entry->the_bfd, | |
547 | + BFD_NO_MORE_SYMBOLS, | |
548 | + &car); | |
549 | + while (indx != BFD_NO_MORE_SYMBOLS) { | |
550 | + if (car->file_offset == offset) { | |
551 | + car->name = 0; | |
552 | + } | |
553 | + indx = bfd_get_next_mapent(entry->the_bfd, indx, &car); | |
554 | + } | |
555 | + | |
556 | +} | |
557 | + | |
558 | +/* Search a library that has a map | |
559 | + */ | |
560 | +void | |
561 | +symdef_library (entry) | |
562 | + struct lang_input_statement_struct *entry; | |
563 | + | |
564 | +{ | |
565 | + register struct lang_input_statement_struct *prev = 0; | |
566 | + | |
567 | + boolean not_finished = true; | |
568 | + | |
569 | + | |
570 | + while (not_finished == true) | |
571 | + { | |
572 | + carsym *exported_library_name; | |
573 | + bfd *prev_archive_member_bfd = 0; | |
574 | + | |
575 | + int idx = bfd_get_next_mapent(entry->the_bfd, | |
576 | + BFD_NO_MORE_SYMBOLS, | |
577 | + &exported_library_name); | |
578 | + | |
579 | + not_finished = false; | |
580 | + | |
581 | + while (idx != BFD_NO_MORE_SYMBOLS && undefined_global_sym_count) | |
582 | + { | |
583 | + | |
584 | + if (exported_library_name->name) | |
585 | + { | |
586 | + | |
587 | + ldsym_type *sp = ldsym_get_soft (exported_library_name->name); | |
588 | + | |
589 | + /* If we find a symbol that appears to be needed, think carefully | |
590 | + about the archive member that the symbol is in. */ | |
591 | + /* So - if it exists, and is referenced somewhere and is | |
592 | + undefined or */ | |
593 | + if (sp && sp->srefs_chain && !sp->sdefs_chain) | |
594 | + { | |
595 | + bfd *archive_member_bfd = bfd_get_elt_at_index(entry->the_bfd, idx); | |
596 | + struct lang_input_statement_struct *archive_member_lang_input_statement_struct; | |
597 | + | |
598 | + if (archive_member_bfd && bfd_check_format(archive_member_bfd, bfd_object)) | |
599 | + { | |
600 | + | |
601 | + /* Don't think carefully about any archive member | |
602 | + more than once in a given pass. */ | |
603 | + if (prev_archive_member_bfd != archive_member_bfd) | |
604 | + { | |
605 | + | |
606 | + prev_archive_member_bfd = archive_member_bfd; | |
607 | + | |
608 | + /* Read the symbol table of the archive member. */ | |
609 | + | |
610 | + if (archive_member_bfd->usrdata != (void *)NULL) { | |
611 | + | |
612 | + archive_member_lang_input_statement_struct =(lang_input_statement_type *) archive_member_bfd->usrdata; | |
613 | + } | |
614 | + else { | |
615 | + | |
616 | + archive_member_lang_input_statement_struct = | |
617 | + decode_library_subfile (entry, archive_member_bfd); | |
618 | + archive_member_bfd->usrdata = (void *) archive_member_lang_input_statement_struct; | |
619 | + | |
620 | + } | |
621 | + | |
622 | + if (archive_member_lang_input_statement_struct == 0) { | |
623 | + info ("%F%I contains invalid archive member %s\n", | |
624 | + entry, | |
625 | + sp->name); | |
626 | + } | |
627 | + | |
628 | + if (archive_member_lang_input_statement_struct->loaded == false) | |
629 | + { | |
630 | + | |
631 | + Q_read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct); | |
632 | + /* Now scan the symbol table and decide whether to load. */ | |
633 | + | |
634 | + | |
635 | + if (subfile_wanted_p (archive_member_lang_input_statement_struct) == true) | |
636 | + | |
637 | + { | |
638 | + /* This member is needed; load it. | |
639 | + Since we are loading something on this pass, | |
640 | + we must make another pass through the symdef data. */ | |
641 | + | |
642 | + not_finished = true; | |
643 | + | |
644 | + Q_enter_file_symbols (archive_member_lang_input_statement_struct); | |
645 | + | |
646 | + if (prev) | |
647 | + prev->chain = archive_member_lang_input_statement_struct; | |
648 | + else | |
649 | + entry->subfiles = archive_member_lang_input_statement_struct; | |
650 | + | |
651 | + | |
652 | + prev = archive_member_lang_input_statement_struct; | |
653 | + | |
654 | + | |
655 | + /* Clear out this member's symbols from the symdef data | |
656 | + so that following passes won't waste time on them. */ | |
657 | + clear_syms(entry, exported_library_name->file_offset); | |
658 | + archive_member_lang_input_statement_struct->loaded = true; | |
659 | + } | |
660 | + } | |
661 | + } | |
662 | + } | |
663 | + } | |
664 | + } | |
665 | + idx = bfd_get_next_mapent(entry->the_bfd, idx, &exported_library_name); | |
666 | + } | |
667 | + } | |
668 | +} | |
669 | + | |
670 | +void | |
671 | +linear_library (entry) | |
672 | +struct lang_input_statement_struct *entry; | |
673 | +{ | |
674 | + boolean more_to_do = true; | |
675 | + register struct lang_input_statement_struct *prev = 0; | |
676 | + | |
677 | + while (more_to_do) { | |
678 | + | |
679 | + bfd * archive = bfd_openr_next_archived_file(entry->the_bfd,0); | |
680 | + | |
681 | + more_to_do = false; | |
682 | + while (archive) { | |
683 | + if (bfd_check_format(archive, bfd_object)) | |
684 | + { | |
685 | + register struct lang_input_statement_struct *subentry; | |
686 | + | |
687 | + subentry = decode_library_subfile (entry, | |
688 | + archive); | |
689 | + | |
690 | + archive->usrdata = (void *) subentry; | |
691 | + if (!subentry) return; | |
692 | + if (subentry->loaded == false) { | |
693 | + Q_read_entry_symbols (archive, subentry); | |
694 | + | |
695 | + if (subfile_wanted_p (subentry) == true) | |
696 | + { | |
697 | + Q_enter_file_symbols (subentry); | |
698 | + | |
699 | + if (prev) | |
700 | + prev->chain = subentry; | |
701 | + else | |
702 | + entry->subfiles = subentry; | |
703 | + prev = subentry; | |
704 | + | |
705 | + more_to_do = true; | |
706 | + subentry->loaded = true; | |
707 | + } | |
708 | + } | |
709 | + } | |
710 | + archive = bfd_openr_next_archived_file(entry->the_bfd,archive); | |
711 | + | |
712 | + } | |
713 | + | |
714 | + } | |
715 | +} | |
716 | + | |
717 | + /* ENTRY is an entry for a library member. | |
718 | + Its symbols have been read into core, but not entered. | |
719 | + Return nonzero if we ought to load this member. */ | |
720 | + | |
721 | +boolean | |
722 | +subfile_wanted_p (entry) | |
723 | +struct lang_input_statement_struct *entry; | |
724 | +{ | |
725 | + asymbol **q; | |
726 | + | |
727 | + for (q = entry->asymbols; *q; q++) | |
728 | + { | |
729 | + asymbol *p = *q; | |
730 | + | |
731 | + /* If the symbol has an interesting definition, we could | |
732 | + potentially want it. */ | |
733 | + | |
734 | + if (p->flags & BSF_FORT_COMM | |
735 | + || p->flags & BSF_GLOBAL) | |
736 | + { | |
737 | + register ldsym_type *sp = ldsym_get_soft (p->name); | |
738 | + | |
739 | + | |
740 | + /* If this symbol has not been hashed, | |
741 | + we can't be looking for it. */ | |
742 | + if (sp != (ldsym_type *)NULL | |
743 | + && sp->sdefs_chain == (asymbol **)NULL) { | |
744 | + if (sp->srefs_chain != (asymbol **)NULL | |
745 | + || sp->scoms_chain != (asymbol **)NULL) | |
746 | + { | |
747 | + /* This is a symbol we are looking for. It is either | |
748 | + not yet defined or common. */ | |
749 | + | |
750 | + if (flag_is_common(p->flags)) | |
751 | + { | |
752 | + /* This libary member has something to | |
753 | + say about this element. We should | |
754 | + remember if its a new size */ | |
755 | + /* Move something from the ref list to the com list */ | |
756 | + if(sp->scoms_chain) { | |
757 | + /* Already a common symbol, maybe update it */ | |
758 | + if (p->value > (*(sp->scoms_chain))->value) { | |
759 | + (*(sp->scoms_chain))->value = p->value; | |
760 | + } | |
761 | + } | |
762 | + else { | |
763 | + /* Take a value from the ref chain | |
764 | + Here we are moving a symbol from the owning bfd | |
765 | + to another bfd. We must set up the | |
766 | + common_section portion of the bfd thing */ | |
767 | + | |
768 | + | |
769 | + | |
770 | + sp->scoms_chain = sp->srefs_chain; | |
771 | + sp->srefs_chain = | |
772 | + (asymbol **)((*(sp->srefs_chain))->udata); | |
773 | + (*(sp->scoms_chain))->udata = (void*)NULL; | |
774 | + | |
775 | + (*( sp->scoms_chain))->flags = BSF_FORT_COMM; | |
776 | + commons_pending++; | |
777 | + undefined_global_sym_count--; | |
778 | + } { | |
779 | + asymbol *com = *(sp->scoms_chain); | |
780 | + if (((lang_input_statement_type *) | |
781 | + (com->the_bfd->usrdata))->common_section == | |
782 | + (asection *)NULL) { | |
783 | + ((lang_input_statement_type *) | |
784 | + (com->the_bfd->usrdata))->common_section = | |
785 | + bfd_make_section(com->the_bfd, "COMMON"); | |
786 | + } | |
787 | + } | |
788 | + ASSERT(p->udata == 0); | |
789 | + } | |
790 | + | |
791 | + else { | |
792 | + if (write_map) | |
793 | + { | |
794 | + info("%I needed due to %s\n",entry, sp->name); | |
795 | + } | |
796 | + return true; | |
797 | + } | |
798 | + } | |
799 | + } | |
800 | + } | |
801 | + } | |
802 | + | |
803 | + return false; | |
804 | +} | |
805 | + | |
806 | + |
@@ -0,0 +1,23 @@ | ||
1 | +/* ldmain.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | +PROTO(void, Q_enter_global_ref,(asymbol **)); | |
22 | +PROTO(void, Q_read_file_symbols,(struct lang_input_statement_struct *)); | |
23 | + |
@@ -0,0 +1,303 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + * $Id$ | |
21 | + * | |
22 | + * $Log$ | |
23 | + * Revision 1.1 1991/03/21 21:28:55 gumby | |
24 | + * Initial revision | |
25 | + * | |
26 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
27 | + * foo | |
28 | + * | |
29 | + * Revision 1.1 1991/03/13 00:48:30 chrisb | |
30 | + * Initial revision | |
31 | + * | |
32 | + * Revision 1.7 1991/03/10 09:31:34 rich | |
33 | + * Modified Files: | |
34 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
35 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
36 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
37 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
38 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
39 | + * | |
40 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
41 | + * interest and copy passes my copy test on big endian hosts again. | |
42 | + * | |
43 | + * Revision 1.6 1991/03/09 03:31:01 sac | |
44 | + * After a fatal info message, the output file is deleted. | |
45 | + * | |
46 | + * Revision 1.5 1991/03/06 21:59:54 sac | |
47 | + * Made %C print function name if available | |
48 | + * | |
49 | + * Revision 1.4 1991/03/06 02:27:45 sac | |
50 | + * Added support for linenumber printing via %C | |
51 | + * | |
52 | + * Revision 1.3 1991/02/22 17:15:03 sac | |
53 | + * Added RCS keywords and copyrights | |
54 | + * | |
55 | + */ | |
56 | + | |
57 | +/* | |
58 | + ldmisc.c | |
59 | + | |
60 | +*/ | |
61 | + | |
62 | +#include "sysdep.h" | |
63 | +#include <varargs.h> | |
64 | +#include "bfd.h" | |
65 | + | |
66 | +#include "ld.h" | |
67 | +#include "ldmisc.h" | |
68 | +#include "ldlang.h" | |
69 | + | |
70 | +/* IMPORTS */ | |
71 | + | |
72 | +extern char *program_name; | |
73 | + | |
74 | +extern FILE *ldlex_input_stack; | |
75 | +extern char *ldfile_input_filename; | |
76 | +extern ld_config_type config; | |
77 | + | |
78 | +void | |
79 | +yyerror(arg) | |
80 | +char *arg; | |
81 | +{ | |
82 | + info("%P%F: %S %s\n",arg); | |
83 | +} | |
84 | + | |
85 | +extern int errno; | |
86 | +extern int sys_nerr; | |
87 | +extern char *sys_errlist[]; | |
88 | + | |
89 | +/* | |
90 | + %F error is fatal | |
91 | + %P print progam name | |
92 | + %S print script file and linenumber | |
93 | + %E current bfd error or errno | |
94 | + %I filename from a lang_input_statement_type | |
95 | + %B filename from a bfd | |
96 | + %T symbol table entry | |
97 | + %X no object output, fail return | |
98 | + %V hex bfd_vma | |
99 | + %C Clever filename:linenumber | |
100 | + % | |
101 | +*/ | |
102 | +void info(va_alist) | |
103 | +va_dcl | |
104 | +{ | |
105 | + char *fmt; | |
106 | + boolean fatal = false; | |
107 | + va_list arg; | |
108 | + va_start(arg); | |
109 | + fmt = va_arg(arg, char *); | |
110 | + while (*fmt) { | |
111 | + while (*fmt != '%' && *fmt != '\0') { | |
112 | + fputc(*fmt, stderr); | |
113 | + fmt++; | |
114 | + } | |
115 | + if (*fmt == '%') { | |
116 | + fmt ++; | |
117 | + switch (*fmt++) { | |
118 | + case 'X': | |
119 | + config.make_executable = false; | |
120 | + break; | |
121 | + case 'V': | |
122 | + fprintf(stderr,"%08lx", va_arg(arg, bfd_vma)); | |
123 | + break; | |
124 | + case 'T': | |
125 | + { | |
126 | + asymbol *symbol = va_arg(arg, asymbol *); | |
127 | + if (symbol) { | |
128 | + asection *section = symbol->section; | |
129 | + if ((symbol->flags & BSF_UNDEFINED) == 0) { | |
130 | + char *section_name = section == (asection *)NULL ? | |
131 | + "absolute" : section->name; | |
132 | + fprintf(stderr,"%s (%s)", symbol->name, section_name); | |
133 | + } | |
134 | + else { | |
135 | + fprintf(stderr,"%s", symbol->name); | |
136 | + } | |
137 | + } | |
138 | + else { | |
139 | + fprintf(stderr,"no symbol"); | |
140 | + } | |
141 | + } | |
142 | + break; | |
143 | + case 'B': | |
144 | + { | |
145 | + bfd *abfd = va_arg(arg, bfd *); | |
146 | + if (abfd->my_archive) { | |
147 | + fprintf(stderr,"%s(%s)", abfd->my_archive->filename, | |
148 | + abfd->filename); | |
149 | + } | |
150 | + else { | |
151 | + fprintf(stderr,"%s", abfd->filename); | |
152 | + | |
153 | + } | |
154 | + } | |
155 | + break; | |
156 | + case 'F': | |
157 | + fatal = true; | |
158 | + break; | |
159 | + case 'P': | |
160 | + fprintf(stderr,"%s", program_name); | |
161 | + break; | |
162 | + case 'E': | |
163 | + /* Replace with the most recent errno explanation */ | |
164 | + | |
165 | + | |
166 | + fprintf(stderr, bfd_errmsg(bfd_error)); | |
167 | + | |
168 | + | |
169 | + break; | |
170 | + case 'I': | |
171 | + { | |
172 | + lang_input_statement_type *i = | |
173 | + va_arg(arg,lang_input_statement_type *); | |
174 | + | |
175 | + fprintf(stderr,"%s", i->local_sym_name); | |
176 | + } | |
177 | + break; | |
178 | + case 'S': | |
179 | + /* Print source script file and line number */ | |
180 | + | |
181 | + if (ldlex_input_stack) { | |
182 | + extern unsigned int lineno; | |
183 | + if (ldfile_input_filename == (char *)NULL) { | |
184 | + fprintf(stderr,"command line"); | |
185 | + } | |
186 | + else { | |
187 | + fprintf(stderr,"%s:%u", ldfile_input_filename, lineno + 1); | |
188 | + } | |
189 | + } | |
190 | + else { | |
191 | + fprintf(stderr,"command line "); | |
192 | + } | |
193 | + break; | |
194 | + case 'C': | |
195 | + { | |
196 | + char *filename; | |
197 | + char *functionname; | |
198 | + unsigned int linenumber; | |
199 | + bfd *abfd = va_arg(arg, bfd *); | |
200 | + asection *section = va_arg(arg, asection *); | |
201 | + asymbol **symbols = va_arg(arg, asymbol **); | |
202 | + bfd_vma offset = va_arg(arg, bfd_vma); | |
203 | + | |
204 | + if (bfd_find_nearest_line(abfd, | |
205 | + section, | |
206 | + symbols, | |
207 | + offset, | |
208 | + &filename, | |
209 | + &functionname, | |
210 | + &linenumber)) | |
211 | + { | |
212 | + if (filename == (char *)NULL) | |
213 | + filename = abfd->filename; | |
214 | + if (functionname != (char *)NULL) | |
215 | + fprintf(stderr,"%s:%u: (%s)", filename, linenumber, functionname); | |
216 | + else if (linenumber != 0) | |
217 | + fprintf(stderr,"%s:%u", filename, linenumber); | |
218 | + else | |
219 | + fprintf(stderr,"%s", filename); | |
220 | + | |
221 | + } | |
222 | + else { | |
223 | + fprintf(stderr,"%s", abfd->filename); | |
224 | + } | |
225 | + } | |
226 | + break; | |
227 | + | |
228 | + case 's': | |
229 | + fprintf(stderr,"%s", va_arg(arg, char *)); | |
230 | + break; | |
231 | + case 'd': | |
232 | + fprintf(stderr,"%d", va_arg(arg, int)); | |
233 | + break; | |
234 | + default: | |
235 | + fprintf(stderr,"%s", va_arg(arg, char *)); | |
236 | + break; | |
237 | + } | |
238 | + } | |
239 | + } | |
240 | + if (fatal == true) { | |
241 | + extern char *output_filename; | |
242 | + if (output_filename) | |
243 | + unlink(output_filename); | |
244 | + exit(1); | |
245 | + } | |
246 | + va_end(arg); | |
247 | +} | |
248 | + | |
249 | + | |
250 | +void | |
251 | +info_assert(file, line) | |
252 | +char *file; | |
253 | +unsigned int line; | |
254 | +{ | |
255 | + info("%F%P internal error %s %d\n", file,line); | |
256 | +} | |
257 | + | |
258 | +/* Return a newly-allocated string | |
259 | + whose contents concatenate those of S1, S2, S3. */ | |
260 | + | |
261 | +char * | |
262 | +concat (s1, s2, s3) | |
263 | + char *s1, *s2, *s3; | |
264 | +{ | |
265 | + size_t len1 = strlen (s1); | |
266 | + size_t len2 = strlen (s2); | |
267 | + size_t len3 = strlen (s3); | |
268 | + char *result = ldmalloc (len1 + len2 + len3 + 1); | |
269 | + | |
270 | + if (len1 != 0) | |
271 | + memcpy(result, s1, len1); | |
272 | + if (len2 != 0) | |
273 | + memcpy(result+len1, s2, len2); | |
274 | + if (len3 != 0) | |
275 | + memcpy(result+len1+len2, s2, len3); | |
276 | + *(result + len1 + len2 + len3) = 0; | |
277 | + | |
278 | + return result; | |
279 | +} | |
280 | + | |
281 | + | |
282 | + | |
283 | +char *ldmalloc (size) | |
284 | +size_t size; | |
285 | +{ | |
286 | + char * result = malloc (size); | |
287 | + | |
288 | + if (result == (char *)NULL && size != 0) | |
289 | + info("%F%P virtual memory exhausted\n"); | |
290 | + | |
291 | + return result; | |
292 | +} | |
293 | + | |
294 | + | |
295 | + | |
296 | +char *buystring(x) | |
297 | +char *x; | |
298 | +{ | |
299 | + size_t l = strlen(x)+1; | |
300 | + char *r = ldmalloc(l); | |
301 | + memcpy(r, x,l); | |
302 | + return r; | |
303 | +} |
@@ -0,0 +1,34 @@ | ||
1 | +/* ldmisc.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | + | |
23 | +/* VARARGS*/ | |
24 | +PROTO(void,info,()); | |
25 | +PROTO(void,info_assert,(char *, unsigned int)); | |
26 | +PROTO(void,yyerror,(char *)); | |
27 | +PROTO(char *,concat,(char *, char *, char *)); | |
28 | +PROTO(char *, ldmalloc,(size_t)); | |
29 | +PROTO(char *,buystring,(char *)); | |
30 | +#define ASSERT(x) \ | |
31 | +{ if (!(x)) info_assert(__FILE__,__LINE__); } | |
32 | + | |
33 | +#define FAIL() \ | |
34 | +{ info_assert(__FILE__,__LINE__); } |
@@ -0,0 +1,452 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + * $Id$ | |
21 | + * | |
22 | + * $Log$ | |
23 | + * Revision 1.1 1991/03/21 21:28:58 gumby | |
24 | + * Initial revision | |
25 | + * | |
26 | + * Revision 1.1 1991/03/13 00:48:32 chrisb | |
27 | + * Initial revision | |
28 | + * | |
29 | + * Revision 1.4 1991/03/10 09:31:36 rich | |
30 | + * Modified Files: | |
31 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
32 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
33 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
34 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
35 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
36 | + * | |
37 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
38 | + * interest and copy passes my copy test on big endian hosts again. | |
39 | + * | |
40 | + * Revision 1.3 1991/03/06 02:28:56 sac | |
41 | + * Cleaned up | |
42 | + * | |
43 | + * Revision 1.2 1991/02/22 17:15:06 sac | |
44 | + * Added RCS keywords and copyrights | |
45 | + * | |
46 | +*/ | |
47 | + | |
48 | +/* | |
49 | + Written by Steve Chamberlain steve@cygnus.com | |
50 | + | |
51 | + All symbol handling for the linker | |
52 | + */ | |
53 | + | |
54 | + | |
55 | +#include "sysdep.h" | |
56 | +#include "bfd.h" | |
57 | + | |
58 | +#include "ld.h" | |
59 | +#include "ldsym.h" | |
60 | +#include "ldmisc.h" | |
61 | +#include "ldlang.h" | |
62 | +/* IMPORT */ | |
63 | + | |
64 | +extern bfd *output_bfd; | |
65 | +/* Head and tail of global symbol table chronological list */ | |
66 | + | |
67 | +ldsym_type *symbol_head = (ldsym_type *)NULL; | |
68 | +ldsym_type **symbol_tail_ptr = &symbol_head; | |
69 | + | |
70 | +/* | |
71 | + incremented for each symbol in the ldsym_type table | |
72 | + no matter what flavour it is | |
73 | +*/ | |
74 | +unsigned int global_symbol_count; | |
75 | + | |
76 | +/* IMPORTS */ | |
77 | + | |
78 | +extern boolean option_longmap ; | |
79 | + | |
80 | +/* LOCALS */ | |
81 | +#define TABSIZE 1009 | |
82 | +static ldsym_type *global_symbol_hash_table[TABSIZE]; | |
83 | + | |
84 | +/* Compute the hash code for symbol name KEY. */ | |
85 | + | |
86 | +int | |
87 | +hash_string (key) | |
88 | + char *key; | |
89 | +{ | |
90 | + register char *cp; | |
91 | + register int k; | |
92 | + | |
93 | + cp = key; | |
94 | + k = 0; | |
95 | + while (*cp) | |
96 | + k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; | |
97 | + | |
98 | + return k; | |
99 | +} | |
100 | + | |
101 | +/* Get the symbol table entry for the global symbol named KEY. | |
102 | + Create one if there is none. */ | |
103 | +ldsym_type * | |
104 | +ldsym_get (key) | |
105 | + char *key; | |
106 | +{ | |
107 | + register int hashval; | |
108 | + register ldsym_type *bp; | |
109 | + | |
110 | + /* Determine the proper bucket. */ | |
111 | + | |
112 | + hashval = hash_string (key) % TABSIZE; | |
113 | + | |
114 | + /* Search the bucket. */ | |
115 | + | |
116 | + for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link) | |
117 | + if (! strcmp (key, bp->name)) | |
118 | + return bp; | |
119 | + | |
120 | + /* Nothing was found; create a new symbol table entry. */ | |
121 | + | |
122 | + bp = (ldsym_type *) ldmalloc (sizeof (ldsym_type)); | |
123 | + bp->srefs_chain = (asymbol **)NULL; | |
124 | + bp->sdefs_chain = (asymbol **)NULL; | |
125 | + bp->scoms_chain = (asymbol **)NULL; | |
126 | + bp->name = (char *) ldmalloc (strlen (key) + 1); | |
127 | + strcpy (bp->name, key); | |
128 | + | |
129 | + | |
130 | + | |
131 | + | |
132 | + /* Add the entry to the bucket. */ | |
133 | + | |
134 | + bp->link = global_symbol_hash_table[hashval]; | |
135 | + global_symbol_hash_table[hashval] = bp; | |
136 | + | |
137 | + /* Keep the chronological list up to date too */ | |
138 | + *symbol_tail_ptr = bp; | |
139 | + symbol_tail_ptr = &bp->next; | |
140 | + bp->next = 0; | |
141 | + global_symbol_count++; | |
142 | + | |
143 | + return bp; | |
144 | +} | |
145 | + | |
146 | +/* Like `ldsym_get' but return 0 if the symbol is not already known. */ | |
147 | + | |
148 | +ldsym_type * | |
149 | +ldsym_get_soft (key) | |
150 | + char *key; | |
151 | +{ | |
152 | + register int hashval; | |
153 | + register ldsym_type *bp; | |
154 | + | |
155 | + /* Determine which bucket. */ | |
156 | + | |
157 | + hashval = hash_string (key) % TABSIZE; | |
158 | + | |
159 | + /* Search the bucket. */ | |
160 | + | |
161 | + for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link) | |
162 | + if (! strcmp (key, bp->name)) | |
163 | + return bp; | |
164 | + | |
165 | + return 0; | |
166 | +} | |
167 | + | |
168 | + | |
169 | + | |
170 | + | |
171 | + | |
172 | +static void | |
173 | +list_file_locals (entry) | |
174 | +lang_input_statement_type *entry; | |
175 | +{ | |
176 | + asymbol **q; | |
177 | + fprintf (stderr, "\nLocal symbols of "); | |
178 | + info("%I", entry); | |
179 | + fprintf (stderr, ":\n\n"); | |
180 | + if (entry->asymbols) { | |
181 | + for (q = entry->asymbols; *q; q++) | |
182 | + { | |
183 | + asymbol *p = *q; | |
184 | + /* If this is a definition, | |
185 | + update it if necessary by this file's start address. */ | |
186 | + if (p->flags & BSF_LOCAL) | |
187 | + info(" %V %s\n",p->value, p->name); | |
188 | + } | |
189 | + } | |
190 | +} | |
191 | + | |
192 | + | |
193 | +static void | |
194 | +print_file_stuff(f) | |
195 | +lang_input_statement_type *f; | |
196 | +{ | |
197 | + fprintf (stderr, " %s", f->filename); | |
198 | + fprintf (stderr, " "); | |
199 | + if (f->just_syms_flag) | |
200 | + { | |
201 | + fprintf (stderr, " symbols only\n"); | |
202 | + } | |
203 | + else | |
204 | + { | |
205 | + asection *s; | |
206 | + if (option_longmap) { | |
207 | + for (s = f->the_bfd->sections; | |
208 | + s != (asection *)NULL; | |
209 | + s = s->next) { | |
210 | + fprintf (stderr, "%08lx %08x 2**%2ud %s\n", | |
211 | + s->output_offset, | |
212 | + (unsigned)s->size, s->alignment_power, s->name); | |
213 | + } | |
214 | + } | |
215 | + else { | |
216 | + for (s = f->the_bfd->sections; | |
217 | + s != (asection *)NULL; | |
218 | + s = s->next) { | |
219 | + fprintf (stderr, "%s %lx(%x) ", | |
220 | + s->name, | |
221 | + s->output_offset, | |
222 | + (unsigned) s->size); | |
223 | + } | |
224 | + fprintf (stderr, "hex \n"); | |
225 | + } | |
226 | + } | |
227 | +} | |
228 | + | |
229 | +void | |
230 | +ldsym_print_symbol_table () | |
231 | +{ | |
232 | + fprintf (stderr, "\nFiles:\n\n"); | |
233 | + | |
234 | + lang_for_each_file(print_file_stuff); | |
235 | + | |
236 | + fprintf (stderr, "\nGlobal symbols:\n\n"); | |
237 | + { | |
238 | + register ldsym_type *sp; | |
239 | + | |
240 | + for (sp = symbol_head; sp; sp = sp->next) | |
241 | + { | |
242 | + if (sp->sdefs_chain) | |
243 | + { | |
244 | + asymbol *defsym = *(sp->sdefs_chain); | |
245 | + asection *defsec = bfd_get_section(defsym); | |
246 | + fprintf(stderr,"%08lx ",defsym->value); | |
247 | + if (defsec) | |
248 | + { | |
249 | + fprintf(stderr,"%08lx ",defsym->value+defsec->vma); | |
250 | + fprintf(stderr, | |
251 | + "%7s", | |
252 | + bfd_section_name(output_bfd, | |
253 | + defsec)); | |
254 | + | |
255 | + } | |
256 | + else | |
257 | + { | |
258 | + fprintf(stderr," ......."); | |
259 | + } | |
260 | + | |
261 | + } | |
262 | + else { | |
263 | + fprintf(stderr,"undefined"); | |
264 | + } | |
265 | + | |
266 | + | |
267 | + if (sp->scoms_chain) { | |
268 | + fprintf(stderr, " common size %5lu %s", | |
269 | + (*(sp->scoms_chain))->value, sp->name); | |
270 | + } | |
271 | + if (sp->sdefs_chain) { | |
272 | + fprintf(stderr, " symbol def %08lx %s", | |
273 | + (*(sp->sdefs_chain))->value, | |
274 | + sp->name); | |
275 | + } | |
276 | + else { | |
277 | + fprintf(stderr, " undefined %s", | |
278 | + sp->name); | |
279 | + } | |
280 | + fprintf(stderr, "\n"); | |
281 | + | |
282 | + } | |
283 | + } | |
284 | + lang_for_each_file(list_file_locals); | |
285 | +} | |
286 | + | |
287 | +extern lang_output_section_statement_type *create_object_symbols; | |
288 | +extern char lprefix; | |
289 | +static asymbol ** | |
290 | +write_file_locals(output_buffer) | |
291 | +asymbol **output_buffer; | |
292 | +{ | |
293 | +LANG_FOR_EACH_INPUT_STATEMENT(entry) | |
294 | + { | |
295 | + /* Run trough the symbols and work out what to do with them */ | |
296 | + unsigned int i; | |
297 | + | |
298 | + /* Add one for the filename symbol if needed */ | |
299 | + if (create_object_symbols | |
300 | + != (lang_output_section_statement_type *)NULL) { | |
301 | + asection *s; | |
302 | + for (s = entry->the_bfd->sections; | |
303 | + s != (asection *)NULL; | |
304 | + s = s->next) { | |
305 | + if (s->output_section == create_object_symbols->bfd_section) { | |
306 | + /* Add symbol to this section */ | |
307 | + asymbol * newsym = | |
308 | + (asymbol *)bfd_make_empty_symbol(entry->the_bfd); | |
309 | + newsym->name = entry->local_sym_name; | |
310 | + /* The symbol belongs to the output file's text section */ | |
311 | + | |
312 | + /* The value is the start of this section in the output file*/ | |
313 | + newsym->value = 0; | |
314 | + newsym->flags = BSF_LOCAL; | |
315 | + newsym->section = s; | |
316 | + *output_buffer++ = newsym; | |
317 | + break; | |
318 | + } | |
319 | + } | |
320 | + } | |
321 | + for (i = 0; i < entry->symbol_count; i++) | |
322 | + { | |
323 | + asymbol *p = entry->asymbols[i]; | |
324 | + | |
325 | + if (flag_is_global(p->flags) || flag_is_absolute(p->flags)) | |
326 | + { | |
327 | + /* We are only interested in outputting | |
328 | + globals at this stage in special circumstances */ | |
329 | + if (p->the_bfd == entry->the_bfd | |
330 | + && flag_is_not_at_end(p->flags)) { | |
331 | + /* And this is one of them */ | |
332 | + *(output_buffer++) = p; | |
333 | + p->flags |= BSF_KEEP; | |
334 | + } | |
335 | + } | |
336 | + else { | |
337 | + if (flag_is_ordinary_local(p->flags)) | |
338 | + { | |
339 | + if (discard_locals == DISCARD_ALL) | |
340 | + { } | |
341 | + else if (discard_locals == DISCARD_L && | |
342 | + (p->name[0] == lprefix)) | |
343 | + { } | |
344 | + else if (p->flags == BSF_WARNING) | |
345 | + { } | |
346 | + else | |
347 | + { *output_buffer++ = p; } | |
348 | + } | |
349 | + else if (flag_is_debugger(p->flags)) | |
350 | + { | |
351 | + /* Only keep the debugger symbols if no stripping required */ | |
352 | + if (strip_symbols == STRIP_NONE) { | |
353 | + *output_buffer++ = p; | |
354 | + } | |
355 | + } | |
356 | + else if (flag_is_undefined(p->flags)) | |
357 | + { /* This must be global */ | |
358 | + } | |
359 | + else if (flag_is_common(p->flags)) { | |
360 | + /* And so must this */ | |
361 | + } | |
362 | + else if (p->flags & BSF_CTOR) { | |
363 | + /* Throw it away */ | |
364 | + } | |
365 | +else | |
366 | + { | |
367 | + FAIL(); | |
368 | + } | |
369 | + } | |
370 | + } | |
371 | + | |
372 | + | |
373 | + } | |
374 | + return output_buffer; | |
375 | +} | |
376 | + | |
377 | + | |
378 | +static asymbol ** | |
379 | +write_file_globals(symbol_table) | |
380 | +asymbol **symbol_table; | |
381 | +{ | |
382 | + FOR_EACH_LDSYM(sp) | |
383 | + { | |
384 | + if (sp->sdefs_chain != (asymbol **)NULL) { | |
385 | + asymbol *bufp = (*(sp->sdefs_chain)); | |
386 | + | |
387 | + if ((bufp->flags & BSF_KEEP) ==0) { | |
388 | + ASSERT(bufp != (asymbol *)NULL); | |
389 | + | |
390 | + bufp->name = sp->name; | |
391 | + | |
392 | + if (sp->scoms_chain != (asymbol **)NULL) | |
393 | + | |
394 | + { | |
395 | + /* | |
396 | + defined as common but not allocated, this happens | |
397 | + only with -r and not -d, write out a common | |
398 | + definition | |
399 | + */ | |
400 | + bufp = *(sp->scoms_chain); | |
401 | + } | |
402 | + *symbol_table++ = bufp; | |
403 | + } | |
404 | + } | |
405 | + else if (sp->scoms_chain != (asymbol **)NULL) { | |
406 | + /* This symbol is a common - just output */ | |
407 | + asymbol *bufp = (*(sp->scoms_chain)); | |
408 | + *symbol_table++ = bufp; | |
409 | + } | |
410 | + else if (sp->srefs_chain != (asymbol **)NULL) { | |
411 | + /* This symbol is undefined but has a reference */ | |
412 | + asymbol *bufp = (*(sp->srefs_chain)); | |
413 | + *symbol_table++ = bufp; | |
414 | + } | |
415 | + else { | |
416 | + /* | |
417 | + This symbol has neither defs nor refs, it must have come | |
418 | + from the command line, since noone has used it it has no | |
419 | + data attatched, so we'll ignore it | |
420 | + */ | |
421 | + } | |
422 | + } | |
423 | + return symbol_table; | |
424 | +} | |
425 | + | |
426 | + | |
427 | + | |
428 | +void | |
429 | +ldsym_write() | |
430 | +{ | |
431 | + if (strip_symbols != STRIP_ALL) { | |
432 | + /* We know the maximum size of the symbol table - | |
433 | + it's the size of all the global symbols ever seen + | |
434 | + the size of all the symbols from all the files + | |
435 | + the number of files (for the per file symbols) | |
436 | + +1 (for the null at the end) | |
437 | + */ | |
438 | + extern unsigned int total_files_seen; | |
439 | + extern unsigned int total_symbols_seen; | |
440 | + | |
441 | + asymbol ** symbol_table = (asymbol **) | |
442 | + ldmalloc ((size_t)(global_symbol_count + | |
443 | + total_files_seen + | |
444 | + total_symbols_seen + 1) * sizeof (asymbol *)); | |
445 | + asymbol ** tablep = write_file_locals(symbol_table); | |
446 | + | |
447 | + tablep = write_file_globals(tablep); | |
448 | + | |
449 | + *tablep = (asymbol *)NULL; | |
450 | + bfd_set_symtab(output_bfd, symbol_table, (unsigned)( tablep - symbol_table)); | |
451 | + } | |
452 | +} |
@@ -0,0 +1,441 @@ | ||
1 | +/* Copyright (C) 1991 Free Software Foundation, Inc. | |
2 | + | |
3 | +This file is part of GLD, the Gnu Linker. | |
4 | + | |
5 | +GLD is free software; you can redistribute it and/or modify | |
6 | +it under the terms of the GNU General Public License as published by | |
7 | +the Free Software Foundation; either version 1, or (at your option) | |
8 | +any later version. | |
9 | + | |
10 | +GLD is distributed in the hope that it will be useful, | |
11 | +but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | +GNU General Public License for more details. | |
14 | + | |
15 | +You should have received a copy of the GNU General Public License | |
16 | +along with GLD; see the file COPYING. If not, write to | |
17 | +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
18 | + | |
19 | +/* | |
20 | + * $Id$ | |
21 | + * | |
22 | + * $Log$ | |
23 | + * Revision 1.1 1991/03/21 21:29:04 gumby | |
24 | + * Initial revision | |
25 | + * | |
26 | + * Revision 1.2 1991/03/15 18:45:55 rich | |
27 | + * foo | |
28 | + * | |
29 | + * Revision 1.1 1991/03/13 00:48:37 chrisb | |
30 | + * Initial revision | |
31 | + * | |
32 | + * Revision 1.7 1991/03/10 19:15:03 sac | |
33 | + * Took out the abort() which had been put in the wrong place | |
34 | + * Updated the version #. | |
35 | + * | |
36 | + * Revision 1.6 1991/03/10 09:31:41 rich | |
37 | + * Modified Files: | |
38 | + * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c | |
39 | + * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h | |
40 | + * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c | |
41 | + * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c | |
42 | + * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h | |
43 | + * | |
44 | + * As of this round of changes, ld now builds on all hosts of (Intel960) | |
45 | + * interest and copy passes my copy test on big endian hosts again. | |
46 | + * | |
47 | + * Revision 1.5 1991/03/09 03:25:08 sac | |
48 | + * Added support for LONG, SHORT and BYTE keywords in scripts | |
49 | + * | |
50 | + * Revision 1.4 1991/03/06 21:59:34 sac | |
51 | + * Completed G++ support | |
52 | + * | |
53 | + * Revision 1.3 1991/03/06 02:29:52 sac | |
54 | + * Added support for partial linking. | |
55 | + * | |
56 | + * Revision 1.2 1991/02/22 17:15:11 sac | |
57 | + * Added RCS keywords and copyrights | |
58 | + * | |
59 | +*/ | |
60 | + | |
61 | +/* | |
62 | + This module writes out the final image by reading sections from the | |
63 | + input files, relocating them and writing them out | |
64 | + | |
65 | + There are two main paths through this module, one for normal | |
66 | + operation and one for partial linking. | |
67 | + | |
68 | + During normal operation, raw section data is read along with the | |
69 | + associated relocation information, the relocation info applied and | |
70 | + the section data written out on a section by section basis. | |
71 | + | |
72 | + When partially linking, all the relocation records are read to work | |
73 | + out how big the output relocation vector will be. Then raw data is | |
74 | + read, relocated and written section by section. | |
75 | + | |
76 | + Written by Steve Chamberlain steve@cygnus.com | |
77 | + | |
78 | +*/ | |
79 | + | |
80 | + | |
81 | +#include "sysdep.h" | |
82 | +#include "bfd.h" | |
83 | + | |
84 | +#include "ldlang.h" | |
85 | +#include "ld.h" | |
86 | +#include "ldwrite.h" | |
87 | +#include "ldmisc.h" | |
88 | +#include "ldsym.h" | |
89 | +#include "ldgram.tab.h" | |
90 | + | |
91 | + | |
92 | + | |
93 | +char *ldmalloc(); | |
94 | +/* Static vars for do_warnings and subroutines of it */ | |
95 | +int list_unresolved_refs; /* List unresolved refs */ | |
96 | +int list_warning_symbols; /* List warning syms */ | |
97 | +int list_multiple_defs; /* List multiple definitions */ | |
98 | +extern int errno; | |
99 | +extern char *sys_errlist[]; | |
100 | + | |
101 | +extern unsigned int undefined_global_sym_count; | |
102 | + | |
103 | +extern bfd *output_bfd; | |
104 | + | |
105 | +extern struct lang_output_section_statement_struct * create_object_symbols; | |
106 | + | |
107 | +extern char lprefix; | |
108 | + | |
109 | +#ifdef __STDC__ | |
110 | +void lang_for_each_statement(void (*func)()); | |
111 | +#else /* __STDC__ */ | |
112 | +void lang_for_each_statement(); | |
113 | +#endif /* __STDC__ */ | |
114 | + | |
115 | +extern size_t largest_section; | |
116 | +ld_config_type config; | |
117 | + | |
118 | +extern unsigned int global_symbol_count; | |
119 | + | |
120 | +boolean trace_files; | |
121 | + | |
122 | +static void perform_relocation(input_bfd, | |
123 | + input_section, | |
124 | + data, | |
125 | + symbols) | |
126 | +bfd *input_bfd; | |
127 | +asection *input_section; | |
128 | +void *data; | |
129 | +asymbol **symbols; | |
130 | +{ | |
131 | + static asymbol *error_symbol = (asymbol *)NULL; | |
132 | + static unsigned int error_count = 0; | |
133 | +#define MAX_ERRORS_IN_A_ROW 5 | |
134 | + size_t reloc_size = get_reloc_upper_bound(input_bfd, input_section); | |
135 | + | |
136 | + arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); | |
137 | + arelent **parent; | |
138 | + bfd *ob = output_bfd; | |
139 | + asection *os = input_section->output_section; | |
140 | + if (config.relocateable_output == false) ob = (bfd *)NULL; | |
141 | + | |
142 | + if (bfd_canonicalize_reloc(input_bfd, | |
143 | + input_section, | |
144 | + reloc_vector, | |
145 | + symbols) ) | |
146 | + { | |
147 | + for (parent = reloc_vector; *parent; parent++) | |
148 | + { | |
149 | + | |
150 | + bfd_reloc_status_enum_type r= | |
151 | + bfd_perform_relocation(input_bfd, | |
152 | + *parent, | |
153 | + data, | |
154 | + input_section, | |
155 | + ob); | |
156 | + | |
157 | + if (r == bfd_reloc_ok) { | |
158 | + if (ob != (bfd *)NULL) { | |
159 | + /* A parital link, so keep the relocs */ | |
160 | + os->orelocation[os->reloc_count] = *parent; | |
161 | + os->reloc_count++; | |
162 | + } | |
163 | + } | |
164 | + else | |
165 | + { | |
166 | + asymbol *s; | |
167 | + arelent *p = *parent; | |
168 | + | |
169 | + if (ob != (bfd *)NULL) { | |
170 | + /* A parital link, so keep the relocs */ | |
171 | + os->orelocation[os->reloc_count] = *parent; | |
172 | + os->reloc_count++; | |
173 | + } | |
174 | + | |
175 | + if (p->sym_ptr_ptr != (asymbol **)NULL) { | |
176 | + s = *(p->sym_ptr_ptr); | |
177 | + } | |
178 | + else { | |
179 | + s = (asymbol *)NULL; | |
180 | + } | |
181 | + switch (r) | |
182 | + { | |
183 | + case bfd_reloc_undefined: | |
184 | + /* We remember the symbol, and never print more than | |
185 | + a reasonable number of them in a row */ | |
186 | + if (s == error_symbol) { | |
187 | + error_count++; | |
188 | + } | |
189 | + else { | |
190 | + error_count = 0; | |
191 | + error_symbol = s; | |
192 | + } | |
193 | + if (error_count < MAX_ERRORS_IN_A_ROW) { | |
194 | + info("%C: undefined reference to `%T'\n", | |
195 | + input_bfd, | |
196 | + input_section, | |
197 | + symbols, | |
198 | + (*parent)->address, | |
199 | + s); | |
200 | + config.make_executable = false; | |
201 | + } | |
202 | + else if (error_count == MAX_ERRORS_IN_A_ROW) { | |
203 | + info("%C: more undefined references to `%T' follow\n", | |
204 | + input_bfd, | |
205 | + input_section, | |
206 | + symbols, | |
207 | + (*parent)->address, | |
208 | + s); | |
209 | + } | |
210 | + else { | |
211 | + /* Don't print any more */ | |
212 | + } | |
213 | + break; | |
214 | + case bfd_reloc_dangerous: | |
215 | + info("%B: relocation may be wrong `%T'\n", | |
216 | + input_bfd, | |
217 | + s); | |
218 | + break; | |
219 | + case bfd_reloc_outofrange: | |
220 | + info("%B:%s relocation address out of range %T (%x)\n", | |
221 | + input_bfd, | |
222 | + input_section->name, | |
223 | + s, | |
224 | + p->address); | |
225 | + break; | |
226 | + case bfd_reloc_overflow: | |
227 | + info("%B:%s relocation overflow in %T reloc type %d\n", | |
228 | + input_bfd, | |
229 | + input_section->name, | |
230 | + s, | |
231 | + p->howto->type); | |
232 | + break; | |
233 | + default: | |
234 | + info("%F%B: relocation error, symbol `%T'\n", | |
235 | + input_bfd, | |
236 | + s); | |
237 | + break; | |
238 | + } | |
239 | + } | |
240 | + } | |
241 | + } | |
242 | + free((char *)reloc_vector); | |
243 | +} | |
244 | + | |
245 | + | |
246 | + | |
247 | + | |
248 | + | |
249 | + | |
250 | +void *data_area; | |
251 | + | |
252 | +static void | |
253 | +copy_and_relocate(statement) | |
254 | +lang_statement_union_type *statement; | |
255 | +{ | |
256 | + switch (statement->header.type) { | |
257 | + case lang_fill_statement_enum: | |
258 | + { | |
259 | +#if 0 | |
260 | + bfd_byte play_area[SHORT_SIZE]; | |
261 | + unsigned int i; | |
262 | + bfd_putshort(output_bfd, statement->fill_statement.fill, play_area); | |
263 | + /* Write out all entire shorts */ | |
264 | + for (i = 0; | |
265 | + i < statement->fill_statement.size - SHORT_SIZE + 1; | |
266 | + i+= SHORT_SIZE) | |
267 | + { | |
268 | + bfd_set_section_contents(output_bfd, | |
269 | + statement->fill_statement.output_section, | |
270 | + play_area, | |
271 | + statement->data_statement.output_offset +i, | |
272 | + SHORT_SIZE); | |
273 | + | |
274 | + } | |
275 | + | |
276 | + /* Now write any remaining byte */ | |
277 | + if (i < statement->fill_statement.size) | |
278 | + { | |
279 | + bfd_set_section_contents(output_bfd, | |
280 | + statement->fill_statement.output_section, | |
281 | + play_area, | |
282 | + statement->data_statement.output_offset +i, | |
283 | + 1); | |
284 | + | |
285 | + } | |
286 | +#endif | |
287 | + } | |
288 | + break; | |
289 | + case lang_data_statement_enum: | |
290 | + { | |
291 | + bfd_vma value = statement->data_statement.value; | |
292 | + bfd_byte play_area[LONG_SIZE]; | |
293 | + unsigned int size; | |
294 | + switch (statement->data_statement.type) { | |
295 | + case LONG: | |
296 | + bfd_putlong(output_bfd, value, play_area); | |
297 | + size = LONG_SIZE; | |
298 | + break; | |
299 | + case SHORT: | |
300 | + bfd_putshort(output_bfd, value, play_area); | |
301 | + size = SHORT_SIZE; | |
302 | + break; | |
303 | + case BYTE: | |
304 | + bfd_putchar(output_bfd, value, play_area); | |
305 | + size = BYTE_SIZE; | |
306 | + break; | |
307 | + } | |
308 | + | |
309 | + bfd_set_section_contents(output_bfd, | |
310 | + statement->data_statement.output_section, | |
311 | + play_area, | |
312 | + statement->data_statement.output_vma, | |
313 | + size); | |
314 | + | |
315 | + | |
316 | + | |
317 | + | |
318 | + } | |
319 | + break; | |
320 | + case lang_input_section_enum: | |
321 | + { | |
322 | + | |
323 | + asection *i = statement->input_section.section; | |
324 | + asection *output_section = i->output_section; | |
325 | + lang_input_statement_type *ifile = statement->input_section.ifile; | |
326 | + bfd *inbfd = ifile->the_bfd; | |
327 | + if (output_section->flags & SEC_LOAD && i->size != 0) | |
328 | + { | |
329 | + if(bfd_get_section_contents(inbfd, | |
330 | + i, | |
331 | + data_area, | |
332 | + 0L, | |
333 | + i->size) == false) | |
334 | + { | |
335 | + info("%F%B error reading section contents %E\n", | |
336 | + inbfd); | |
337 | + } | |
338 | + perform_relocation (inbfd, i, data_area, ifile->asymbols); | |
339 | + | |
340 | + | |
341 | + if(bfd_set_section_contents(output_bfd, | |
342 | + output_section, | |
343 | + data_area, | |
344 | + (file_ptr)i->output_offset, | |
345 | + i->size) == false) | |
346 | + { | |
347 | + info("%F%B error writing section contents of %E\n", | |
348 | + output_bfd); | |
349 | + } | |
350 | + | |
351 | + } | |
352 | + } | |
353 | + break; | |
354 | + | |
355 | + default: | |
356 | + /* All the other ones fall through */ | |
357 | + ; | |
358 | + | |
359 | + } | |
360 | +} | |
361 | + | |
362 | +void | |
363 | +write_norel() | |
364 | +{ | |
365 | + /* Output the text and data segments, relocating as we go. */ | |
366 | + lang_for_each_statement(copy_and_relocate); | |
367 | +} | |
368 | + | |
369 | + | |
370 | +static void read_relocs(abfd, section, symbols) | |
371 | +bfd *abfd; | |
372 | +asection *section; | |
373 | +asymbol **symbols; | |
374 | +{ | |
375 | + /* Work out the output section ascociated with this input section */ | |
376 | + asection *output_section = section->output_section; | |
377 | + | |
378 | + size_t reloc_size = get_reloc_upper_bound(abfd, section); | |
379 | + arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); | |
380 | + | |
381 | + if (bfd_canonicalize_reloc(abfd, | |
382 | + section, | |
383 | + reloc_vector, | |
384 | + symbols)) { | |
385 | + output_section->reloc_count += section->reloc_count; | |
386 | + } | |
387 | +} | |
388 | + | |
389 | + | |
390 | +static void | |
391 | +write_rel() | |
392 | +{ | |
393 | + /* | |
394 | + Run through each section of each file and work work out the total | |
395 | + number of relocation records which will finally be in each output | |
396 | + section | |
397 | + */ | |
398 | + | |
399 | + LANG_FOR_EACH_INPUT_SECTION | |
400 | + (statement, abfd, section, | |
401 | + (read_relocs(abfd, section, statement->asymbols))); | |
402 | + | |
403 | + | |
404 | + | |
405 | + /* | |
406 | + Now run though all the output sections and allocate the space for | |
407 | + all the relocations | |
408 | + */ | |
409 | + LANG_FOR_EACH_OUTPUT_SECTION | |
410 | + (section, | |
411 | + (section->orelocation = | |
412 | + (arelent **)ldmalloc((size_t)(sizeof(arelent **)* | |
413 | + section->reloc_count)), | |
414 | + section->reloc_count = 0, | |
415 | + section->flags |= SEC_HAS_CONTENTS)); | |
416 | + | |
417 | + | |
418 | + /* | |
419 | + Copy the data, relocating as we go | |
420 | + */ | |
421 | + lang_for_each_statement(copy_and_relocate); | |
422 | +} | |
423 | + | |
424 | +void | |
425 | +ldwrite () | |
426 | +{ | |
427 | + data_area = (void*) ldmalloc(largest_section); | |
428 | + if (config.relocateable_output == true) | |
429 | + { | |
430 | + write_rel(); | |
431 | + } | |
432 | + else | |
433 | + { | |
434 | + write_norel(); | |
435 | + } | |
436 | + free(data_area); | |
437 | + /* Output the symbol table (both globals and locals). */ | |
438 | + ldsym_write (); | |
439 | + | |
440 | +} | |
441 | + |
@@ -0,0 +1,24 @@ | ||
1 | +/* ldwrite.h - | |
2 | + | |
3 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GLD, the Gnu Linker. | |
6 | + | |
7 | + GLD is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 1, or (at your option) | |
10 | + any later version. | |
11 | + | |
12 | + GLD is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with GLD; see the file COPYING. If not, write to | |
19 | + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | + | |
21 | + | |
22 | + | |
23 | + | |
24 | +PROTO(void, ldwrite, (void)); |