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