* Makefile.in: Let's call it version 2.0.
[deliverable/binutils-gdb.git] / binutils / copy.c
1 /* copy.c -- copy object file from input to output, optionally massaging it.
2 Copyright (C) 1991 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program 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 2 of the License, or
9 (at your option) any later version.
10
11 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "bucomm.h"
23
24 asymbol **sympp;
25 char *input_target = NULL;
26 char *output_target = NULL;
27 char *input_filename = NULL;
28 char *output_filename = NULL;
29
30
31 static void setup_sections();
32 static void copy_sections();
33 static boolean verbose;
34
35 /* This flag distinguishes between strip and copy:
36 1 means this is 'strip'; 0 means this is 'copy'.
37 -1 means if we should use argv[0] to decide. */
38 extern int is_strip;
39
40 /* IMPORTS */
41 extern char *program_name;
42 extern char *program_version;
43
44
45 static
46 void
47 usage()
48 {
49 fprintf(stderr,
50 "Usage %s [-S][-s srcfmt] [-d dtfmt] [-b bothfmts] infile [outfile] [-vV]\n",
51 program_name);
52 exit(1);
53 }
54
55 static
56 void
57 strip_usage()
58 {
59 fprintf(stderr, "Usage %s [-vV] filename ...\n", program_name);
60 exit(1);
61 }
62
63
64 /* Create a temp file in the same directory as supplied */
65 static
66 char *
67 make_tempname(filename)
68 char *filename;
69 {
70 static char template[] = "stXXXXXX";
71 char *tmpname;
72 char * slash = strrchr( filename, '/' );
73 if (slash != (char *)NULL){
74 *slash = 0;
75 tmpname = xmalloc(strlen(filename) + sizeof(template) + 1 );
76 strcpy(tmpname, filename);
77 strcat(tmpname, "/" );
78 strcat(tmpname, template);
79 mktemp(tmpname );
80 *slash = '/';
81 } else {
82 tmpname = xmalloc(sizeof(template));
83 strcpy(tmpname, template);
84 mktemp(tmpname);
85 }
86 return tmpname;
87 }
88
89 /*
90 All the symbols have been read in and point to their owning input section.
91 They have been relocated to that they are all relative to the base of
92 their owning section. On the way out, all the symbols will be relocated to
93 their new location in the output file, through some complex sums.
94
95 */
96 static void
97 mangle_sections(ibfd, obfd)
98 bfd *ibfd;
99 bfd *obfd;
100 {
101 asection *current = ibfd->sections;
102 for (; current != NULL; current = current->next) {
103 current->output_section = bfd_get_section_by_name(obfd, current->name);
104 current->output_offset = 0;
105 }
106 }
107
108 static
109 void
110 copy_object(ibfd, obfd)
111 bfd *ibfd;
112 bfd *obfd;
113 {
114
115 unsigned int symcount;
116
117
118 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
119 bfd_fatal(output_filename);
120
121
122 if (verbose)
123 printf("copy from %s(%s) to %s(%s)\n",
124 ibfd->filename, ibfd->xvec->name,
125 obfd->filename, obfd->xvec->name);
126
127 if ((bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false)
128 ||
129 (bfd_set_file_flags(obfd, (bfd_get_file_flags(ibfd) &
130 (HAS_LINENO | HAS_DEBUG |
131 HAS_RELOC | HAS_SYMS | D_PAGED |
132 HAS_LOCALS))) == false)) {
133 bfd_fatal(bfd_get_filename(ibfd));
134 }
135
136 /* Copy architecture of input file to output file */
137 if (!bfd_set_arch_mach(obfd, bfd_get_arch(ibfd),
138 bfd_get_mach(ibfd))) {
139 fprintf(stderr, "Output file cannot represent architecture %s\n",
140 bfd_printable_arch_mach(bfd_get_arch(ibfd),
141 bfd_get_mach(ibfd)));
142 }
143 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
144 {
145 bfd_fatal(ibfd->filename);
146 }
147
148 sympp = (asymbol **) xmalloc(get_symtab_upper_bound(ibfd));
149 symcount = bfd_canonicalize_symtab(ibfd, sympp);
150
151 bfd_set_symtab(obfd, sympp, is_strip ? 0 : symcount);
152
153 /*
154 bfd mandates that all output sections be created and sizes set before
155 any output is done. Thus, we traverse all sections twice.
156 */
157 bfd_map_over_sections(ibfd, setup_sections, (void *) obfd);
158 bfd_map_over_sections(ibfd, copy_sections, (void *) obfd);
159 mangle_sections(ibfd, obfd);
160 }
161 static
162 char *
163 cat(a,b,c)
164 char *a;
165 char *b;
166 char *c;
167 {
168 int size = strlen(a) + strlen(b) + strlen(c);
169 char *r = xmalloc(size+1);
170 strcpy(r,a);
171 strcat(r,b);
172 strcat(r,c);
173 return r;
174 }
175
176 static void
177 copy_archive(ibfd, obfd)
178 bfd *ibfd;
179 bfd *obfd;
180 {
181 bfd **ptr = &obfd->archive_head;
182 bfd *this_element;
183 /* Read each archive element in turn from the input, copy the
184 contents to a temp file, and keep the temp file handle */
185 char *dir = cat("./#",make_tempname(""),"cd");
186
187 /* Make a temp directory to hold the contents */
188 mkdir(dir,0777);
189 obfd->has_armap = ibfd->has_armap;
190 this_element = bfd_openr_next_archived_file(ibfd, NULL);
191 ibfd->archive_head = this_element;
192 while (this_element != (bfd *)NULL) {
193
194 /* Create an output file for this member */
195 char *output_name = cat(dir, "/",this_element->filename);
196 bfd *output_bfd = bfd_openw(output_name, output_target);
197
198 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
199 bfd_fatal(output_filename);
200
201 if (output_bfd == (bfd *)NULL) {
202 bfd_fatal(output_name);
203 }
204 if (bfd_check_format(this_element, bfd_object) == true) {
205 copy_object(this_element, output_bfd);
206 }
207
208 bfd_close(output_bfd);
209 /* Now open the newly output file and attatch to our list */
210 output_bfd = bfd_openr(output_name, output_target);
211 /* Mark it for deletion */
212
213 *ptr = output_bfd;
214
215 ptr = &output_bfd->next;
216 this_element->next = bfd_openr_next_archived_file(ibfd, this_element);
217 this_element = this_element->next;
218
219 }
220 *ptr = (bfd *)NULL;
221
222 if (!bfd_close(obfd))
223 bfd_fatal(output_filename);
224
225 /* Now delete all the files that we opened.
226 Construct their names again, unfortunately, but so what;
227 we're about to exit anyway. */
228 for (this_element = ibfd->archive_head;
229 this_element != (bfd *)NULL;
230 this_element = this_element->next)
231 {
232 unlink(cat(dir,"/",this_element->filename));
233 }
234 rmdir(dir);
235 if (!bfd_close(ibfd))
236 bfd_fatal(input_filename);
237
238 }
239
240 static
241 void
242 copy_file(input_filename, output_filename)
243 char *input_filename;
244 char *output_filename;
245 {
246 bfd *ibfd;
247
248 ibfd = bfd_openr(input_filename, input_target);
249 if (ibfd == NULL)
250 bfd_fatal(input_filename);
251
252 if (bfd_check_format(ibfd, bfd_object)) {
253 bfd * obfd = bfd_openw(output_filename, output_target);
254 if (obfd == NULL)
255 bfd_fatal(output_filename);
256
257 copy_object(ibfd, obfd);
258
259 if (ibfd->flags & EXEC_P)
260 obfd->flags |= EXEC_P;
261 if (!bfd_close(obfd))
262 bfd_fatal(output_filename);
263
264 if (!bfd_close(ibfd))
265 bfd_fatal(input_filename);
266 }
267 else if (bfd_check_format(ibfd, bfd_archive)) {
268 bfd * obfd = bfd_openw(output_filename, output_target);
269 if (obfd == NULL)
270 bfd_fatal(output_filename);
271 copy_archive(ibfd, obfd);
272 }
273 }
274
275
276
277 /** Actually do the work */
278 static void
279 setup_sections(ibfd, isection, obfd)
280 bfd *ibfd;
281 sec_ptr isection;
282 bfd *obfd;
283 {
284 sec_ptr osection;
285 char *err;
286
287 osection = bfd_get_section_by_name(obfd, bfd_section_name(ibfd, isection));
288 if (osection == NULL) {
289 osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
290 if (osection == NULL) {
291 err = "making";
292 goto loser;
293 }
294 }
295
296 if (!bfd_set_section_size(obfd,
297 osection,
298 bfd_section_size(ibfd, isection))) {
299 err = "size";
300 goto loser;
301 }
302
303 if (bfd_set_section_vma(obfd,
304 osection,
305 bfd_section_vma(ibfd, isection))
306 == false) {
307 err = "vma";
308 goto loser;
309 } /* on error */
310
311 if (bfd_set_section_alignment(obfd,
312 osection,
313 bfd_section_alignment(ibfd, isection))
314 == false) {
315 err = "alignment";
316 goto loser;
317 } /* on error */
318
319 if (!bfd_set_section_flags(obfd, osection,
320 bfd_get_section_flags(ibfd, isection))) {
321 err = "flags";
322 goto loser;
323 }
324
325 /* All went well */
326 return;
327
328 loser:
329 fprintf(stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
330 program_name,
331 bfd_get_filename(ibfd), bfd_section_name(ibfd, isection),
332 err, bfd_errmsg(bfd_error));
333 exit(1);
334 } /* setup_sections() */
335
336 /*
337 Copy all the section related data from an input section
338 to an output section
339
340 If stripping then don't copy any relocation info
341 */
342 static void
343 copy_sections(ibfd, isection, obfd)
344 bfd *ibfd;
345 sec_ptr isection;
346 bfd *obfd;
347 {
348
349 arelent **relpp;
350 int relcount;
351 sec_ptr osection;
352 bfd_size_type size;
353 osection = bfd_get_section_by_name(obfd,
354 bfd_section_name(ibfd, isection));
355
356 size = bfd_get_section_size_before_reloc(isection);
357
358 if (size == 0)
359 return;
360
361 if (is_strip || bfd_get_reloc_upper_bound(ibfd, isection) == 0)
362 {
363 bfd_set_reloc(obfd, osection, (arelent **)NULL, 0);
364 }
365 else
366 {
367 relpp = (arelent **) xmalloc(bfd_get_reloc_upper_bound(ibfd, isection));
368 relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, sympp);
369 bfd_set_reloc(obfd, osection, relpp, relcount);
370 }
371
372 isection->_cooked_size = isection->_raw_size;
373 isection->reloc_done =true;
374
375
376 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS)
377 {
378 PTR memhunk = (PTR) xmalloc((unsigned)size);
379
380 if (!bfd_get_section_contents(ibfd, isection, memhunk, (file_ptr) 0, size))
381 bfd_fatal(bfd_get_filename(ibfd));
382
383 if (!bfd_set_section_contents(obfd, osection, memhunk, (file_ptr)0, size))
384 bfd_fatal(bfd_get_filename(obfd));
385 free(memhunk);
386 }
387
388
389 }
390 int
391 main(argc, argv)
392 int argc;
393 char *argv[];
394 {
395 int i;
396 int show_version = 0;
397 program_name = argv[0];
398
399 bfd_init();
400
401 if (is_strip < 0) {
402 i = strlen (program_name);
403 is_strip = (i >= 5 && strcmp(program_name+i-5,"strip"));
404 }
405
406 if (is_strip)
407 {
408 for (i = 1; i < argc; i++)
409 {
410 if (argv[i][0] != '-')
411 break;
412 if (argv[i][1] == '-') {
413 i++;
414 break;
415 }
416 switch (argv[i][1]) {
417 case 'V':
418 show_version = true;
419 break;
420 case 'v':
421 verbose = true;
422 show_version = true;
423 break;
424 default:
425 strip_usage();
426 }
427 }
428 if (show_version)
429 printf ("%s version %s\n", program_name, program_version);
430 for ( ; i < argc; i++) {
431 char *tmpname = make_tempname(argv[i]);
432 copy_file(argv[i], tmpname);
433 rename(tmpname, argv[i]);
434 }
435 return 0;
436 }
437
438 for (i = 1; i < argc; i++)
439 {
440 if (argv[i][0] == '-') {
441 switch (argv[i][1]) {
442 case 'V':
443 show_version = true;
444 break;
445 case 'v':
446 show_version = true;
447 verbose = true;
448 break;
449 case 'b':
450 i++;
451 input_target = output_target = argv[i];
452 break;
453 case 'S':
454 is_strip = 1;
455 break;
456 case 's':
457 i++;
458 input_target = argv[i];
459 break;
460 case 'd':
461 i++;
462 output_target = argv[i];
463 break;
464 default:
465 usage();
466 }
467 }
468 else {
469 if (input_filename) {
470 output_filename = argv[i];
471 }
472 else {
473 input_filename = argv[i];
474 }
475 }
476 }
477
478 if (show_version)
479 printf ("%s version %s\n", program_name, program_version);
480
481 if (input_filename == (char *) NULL)
482 usage();
483
484 if (output_target == (char *) NULL)
485 output_target = input_target;
486
487 /* If there is no destination file then create a temp and rename
488 the result into the input */
489
490 if (output_filename == (char *)NULL) {
491 char * tmpname = make_tempname(input_filename);
492 copy_file(input_filename, tmpname);
493 output_filename = input_filename;
494 rename(tmpname, input_filename);
495 }
496 else {
497 copy_file(input_filename, output_filename);
498 }
499 return 0;
500 }
This page took 0.040999 seconds and 4 git commands to generate.