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