Write out all the header information, except the SHARELIB stuff which
[deliverable/binutils-gdb.git] / binutils / nlmconv.c
1 /* nlmconv.c -- NLM conversion program
2 Copyright (C) 1993 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 /* Written by Ian Lance Taylor <ian@cygnus.com>.
21
22 This program can be used to convert any appropriate object file
23 into a NetWare Loadable Module (an NLM). It will accept a linker
24 specification file which is identical to that accepted by the
25 NetWare linker, NLMLINK, except that the INPUT command, normally
26 used to give a list of object files to link together, is not used.
27 This program will convert only a single object file. */
28
29 #include <ansidecl.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <assert.h>
34 #include <getopt.h>
35 #include <bfd.h>
36 #include "sysdep.h"
37 #include "bucomm.h"
38 /* Internal BFD NLM header. */
39 #include "libnlm.h"
40 #include "nlmconv.h"
41
42 /* If strerror is just a macro, we want to use the one from libiberty
43 since it will handle undefined values. */
44 #undef strerror
45 extern char *strerror ();
46 \f
47 /* Global variables. */
48
49 /* The name used to invoke the program. */
50 char *program_name;
51
52 /* The version number. */
53 extern char *program_version;
54
55 /* The symbols table. */
56 static asymbol **symbols;
57
58 /* Local variables. */
59
60 /* The list of long options. */
61 static struct option long_options[] =
62 {
63 { "header-info", required_argument, 0, 'T' },
64 { "help", no_argument, 0, 'H' },
65 { "input-format", required_argument, 0, 'I' },
66 { "output-format", required_argument, 0, 'O' },
67 { "version", no_argument, 0, 'v' },
68 { NULL, no_argument, 0, 0 }
69 };
70
71 /* Local routines. */
72
73 static void show_help PARAMS ((void));
74 static void show_usage PARAMS ((FILE *, int));
75 static const char *select_output_format PARAMS ((enum bfd_architecture,
76 long, boolean));
77 static void setup_sections PARAMS ((bfd *, asection *, PTR));
78 static void copy_sections PARAMS ((bfd *, asection *, PTR));
79 static void mangle_relocs PARAMS ((bfd *, arelent **,
80 bfd_size_type, char *,
81 bfd_size_type));
82 static void i386_mangle_relocs PARAMS ((bfd *, arelent **, bfd_size_type,
83 char *, bfd_size_type));
84 \f
85 /* The main routine. */
86
87 int
88 main (argc, argv)
89 int argc;
90 char **argv;
91 {
92 int opt;
93 const char *input_format = NULL;
94 const char *output_format = NULL;
95 const char *header_file = NULL;
96 bfd *inbfd;
97 bfd *outbfd;
98 unsigned int symcount;
99 unsigned int i;
100 char inlead, outlead;
101 boolean gotstart, gotexit, gotcheck;
102 struct stat st;
103 FILE *custom_data, *help_data, *message_data, *rpc_data;
104 bfd_size_type custom_size, help_size, message_size, module_size, rpc_size;
105 asection *custom_section, *help_section, *message_section, *module_section;
106 asection *rpc_section;
107 int len;
108
109 program_name = argv[0];
110
111 bfd_init ();
112
113 while ((opt = getopt_long (argc, argv, "HI:O:T:v", long_options, (int *) 0))
114 != EOF)
115 {
116 switch (opt)
117 {
118 case 'H':
119 show_help ();
120 /*NOTREACHED*/
121 case 'I':
122 input_format = optarg;
123 break;
124 case 'O':
125 output_format = optarg;
126 break;
127 case 'T':
128 header_file = optarg;
129 break;
130 case 'v':
131 printf ("GNU %s version %s\n", program_name, program_version);
132 exit (0);
133 /*NOTREACHED*/
134 case 0:
135 break;
136 default:
137 show_usage (stderr, 1);
138 /*NOTREACHED*/
139 }
140 }
141
142 if (optind + 2 != argc)
143 show_usage (stderr, 1);
144
145 if (strcmp (argv[optind], argv[optind + 1]) == 0)
146 {
147 fprintf (stderr, "%s: input and output files must be different\n",
148 program_name);
149 exit (1);
150 }
151
152 inbfd = bfd_openr (argv[optind], input_format);
153 if (inbfd == NULL)
154 bfd_fatal (argv[optind]);
155
156 if (! bfd_check_format (inbfd, bfd_object))
157 bfd_fatal (argv[optind]);
158
159 if (output_format == NULL)
160 output_format = select_output_format (bfd_get_arch (inbfd),
161 bfd_get_mach (inbfd),
162 inbfd->xvec->byteorder_big_p);
163
164 assert (output_format != NULL);
165 outbfd = bfd_openw (argv[optind + 1], output_format);
166 if (outbfd == NULL)
167 bfd_fatal (argv[optind + 1]);
168 if (! bfd_set_format (outbfd, bfd_object))
169 bfd_fatal (argv[optind + 1]);
170
171 assert (outbfd->xvec->flavour == bfd_target_nlm_flavour);
172
173 if (bfd_arch_get_compatible (inbfd, outbfd) == NULL)
174 fprintf (stderr,
175 "%s: warning:input and output formats are not compatible\n",
176 program_name);
177
178 /* Initialize the header information to default values. */
179 fixed_hdr = nlm_fixed_header (outbfd);
180 var_hdr = nlm_variable_header (outbfd);
181 version_hdr = nlm_version_header (outbfd);
182 copyright_hdr = nlm_copyright_header (outbfd);
183 extended_hdr = nlm_extended_header (outbfd);
184 check_procedure = NULL;
185 custom_file = NULL;
186 debug_info = false;
187 exit_procedure = "_Stop";
188 export_symbols = NULL;
189 map_file = NULL;
190 full_map = false;
191 help_file = NULL;
192 import_symbols = NULL;
193 message_file = NULL;
194 modules = NULL;
195 sharelib_file = NULL;
196 start_procedure = "_Prelude";
197 verbose = false;
198 rpc_file = NULL;
199
200 parse_errors = 0;
201
202 /* Parse the header file (if there is one). */
203 if (header_file != NULL)
204 {
205 if (! nlmlex_file (header_file)
206 || yyparse () != 0
207 || parse_errors != 0)
208 exit (1);
209 }
210
211 /* Start copying the input BFD to the output BFD. */
212 if (! bfd_set_file_flags (outbfd, bfd_get_file_flags (inbfd)))
213 bfd_fatal (bfd_get_filename (outbfd));
214
215 symbols = (asymbol **) xmalloc (get_symtab_upper_bound (inbfd));
216 symcount = bfd_canonicalize_symtab (inbfd, symbols);
217
218 /* Adjust symbol information. */
219 inlead = bfd_get_symbol_leading_char (inbfd);
220 outlead = bfd_get_symbol_leading_char (outbfd);
221 gotstart = false;
222 gotexit = false;
223 gotcheck = false;
224 for (i = 0; i < symcount; i++)
225 {
226 register asymbol *sym;
227
228 sym = symbols[i];
229
230 /* Add or remove a leading underscore. */
231 if (inlead != outlead)
232 {
233 if (inlead != '\0')
234 {
235 if (bfd_asymbol_name (sym)[0] == inlead)
236 {
237 if (outlead == '\0')
238 ++sym->name;
239 else
240 {
241 char *new;
242
243 new = xmalloc (strlen (bfd_asymbol_name (sym)) + 1);
244 new[0] = outlead;
245 strcpy (new + 1, bfd_asymbol_name (sym) + 1);
246 sym->name = new;
247 }
248 }
249 }
250 else
251 {
252 char *new;
253
254 new = xmalloc (strlen (bfd_asymbol_name (sym)) + 2);
255 new[0] = outlead;
256 strcpy (new + 1, bfd_asymbol_name (sym));
257 sym->name = new;
258 }
259 }
260
261 /* If this is a global symbol, see if it's in the export list.
262 Change the prefix if necessary. */
263 if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) != 0
264 && export_symbols != NULL)
265 {
266 register struct string_list *l;
267
268 for (l = export_symbols; l != NULL; l = l->next)
269 {
270 if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
271 break;
272 else
273 {
274 char *zbase;
275
276 zbase = strchr (l->string, '@');
277 if (zbase != NULL
278 && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
279 {
280 sym->name = l->string;
281 break;
282 }
283 }
284 }
285 if (l == NULL)
286 fprintf (stderr,
287 "%s: warning: symbol %s exported but not in export list\n",
288 program_name, bfd_asymbol_name (sym));
289 }
290
291 /* If it's an undefined symbol, see if it's on the import list.
292 Change the prefix if necessary. */
293 if (bfd_get_section (sym) == &bfd_und_section
294 && import_symbols != NULL)
295 {
296 register struct string_list *l;
297
298 for (l = import_symbols; l != NULL; l = l->next)
299 {
300 if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
301 break;
302 else
303 {
304 char *zbase;
305
306 zbase = strchr (l->string, '@');
307 if (zbase != NULL
308 && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
309 {
310 sym->name = l->string;
311 break;
312 }
313 }
314 }
315 if (l == NULL)
316 fprintf (stderr,
317 "%s: warning: symbol %s imported but not in import list\n",
318 program_name, bfd_asymbol_name (sym));
319 }
320
321 /* See if it's one of the special named symbols. */
322 if (strcmp (bfd_asymbol_name (sym), start_procedure) == 0)
323 {
324 if (! bfd_set_start_address (outbfd, bfd_asymbol_value (sym)))
325 bfd_fatal ("set start address");
326 gotstart = true;
327 }
328 if (strcmp (bfd_asymbol_name (sym), exit_procedure) == 0)
329 {
330 nlm_fixed_header (outbfd)->exitProcedureOffset =
331 bfd_asymbol_value (sym);
332 gotexit = true;
333 }
334 if (check_procedure != NULL
335 && strcmp (bfd_asymbol_name (sym), check_procedure) == 0)
336 {
337 nlm_fixed_header (outbfd)->checkUnloadProcedureOffset =
338 bfd_asymbol_value (sym);
339 gotcheck = true;
340 }
341 }
342
343 bfd_set_symtab (outbfd, symbols, symcount);
344
345 if (! gotstart)
346 fprintf (stderr, "%s: warning: START procedure %s not defined\n",
347 program_name, start_procedure);
348 if (! gotexit)
349 fprintf (stderr, "%s: warning: EXIT procedure %s not defined\n",
350 program_name, exit_procedure);
351 if (check_procedure != NULL
352 && ! gotcheck)
353 fprintf (stderr, "%s: warning: CHECK procedure %s not defined\n",
354 program_name, check_procedure);
355
356 /* Set up the sections. */
357 bfd_map_over_sections (inbfd, setup_sections, (PTR) outbfd);
358
359 /* Add additional sections required for the header information. */
360 if (custom_file != NULL)
361 {
362 custom_data = fopen (custom_file, "r");
363 if (custom_data == NULL
364 || fstat (fileno (custom_data), &st) < 0)
365 {
366 fprintf (stderr, "%s:%s: %s\n", program_name, custom_file,
367 strerror (errno));
368 custom_file = NULL;
369 }
370 else
371 {
372 custom_size = st.st_size;
373 custom_section = bfd_make_section (outbfd, ".nlmcustom");
374 if (custom_section == NULL
375 || ! bfd_set_section_size (outbfd, custom_section, custom_size)
376 || ! bfd_set_section_flags (outbfd, custom_section,
377 SEC_HAS_CONTENTS))
378 bfd_fatal ("custom section");
379 }
380 }
381 if (help_file != NULL)
382 {
383 help_data = fopen (help_file, "r");
384 if (help_data == NULL
385 || fstat (fileno (help_data), &st) < 0)
386 {
387 fprintf (stderr, "%s:%s: %s\n", program_name, help_file,
388 strerror (errno));
389 help_file = NULL;
390 }
391 else
392 {
393 help_size = st.st_size;
394 help_section = bfd_make_section (outbfd, ".nlmhelp");
395 if (help_section == NULL
396 || ! bfd_set_section_size (outbfd, help_section, help_size)
397 || ! bfd_set_section_flags (outbfd, help_section,
398 SEC_HAS_CONTENTS))
399 bfd_fatal ("help section");
400 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
401 }
402 }
403 if (message_file != NULL)
404 {
405 message_data = fopen (message_file, "r");
406 if (message_data == NULL
407 || fstat (fileno (message_data), &st) < 0)
408 {
409 fprintf (stderr, "%s:%s: %s\n", program_name, message_file,
410 strerror (errno));
411 message_file = NULL;
412 }
413 else
414 {
415 message_size = st.st_size;
416 message_section = bfd_make_section (outbfd, ".nlmmessages");
417 if (message_section == NULL
418 || ! bfd_set_section_size (outbfd, message_section, message_size)
419 || ! bfd_set_section_flags (outbfd, message_section,
420 SEC_HAS_CONTENTS))
421 bfd_fatal ("message section");
422 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
423 }
424 }
425 if (modules != NULL)
426 {
427 struct string_list *l;
428
429 module_size = 0;
430 for (l = modules; l != NULL; l = l->next)
431 module_size += strlen (l->string) + 1;
432 module_section = bfd_make_section (outbfd, ".nlmmodules");
433 if (module_section == NULL
434 || ! bfd_set_section_size (outbfd, module_section, module_size)
435 || ! bfd_set_section_flags (outbfd, module_section,
436 SEC_HAS_CONTENTS))
437 bfd_fatal ("module section");
438 }
439 if (rpc_file != NULL)
440 {
441 rpc_data = fopen (rpc_file, "r");
442 if (rpc_data == NULL
443 || fstat (fileno (rpc_data), &st) < 0)
444 {
445 fprintf (stderr, "%s:%s: %s\n", program_name, rpc_file,
446 strerror (errno));
447 rpc_file = NULL;
448 }
449 else
450 {
451 rpc_size = st.st_size;
452 rpc_section = bfd_make_section (outbfd, ".nlmrpc");
453 if (rpc_section == NULL
454 || ! bfd_set_section_size (outbfd, rpc_section, rpc_size)
455 || ! bfd_set_section_flags (outbfd, rpc_section,
456 SEC_HAS_CONTENTS))
457 bfd_fatal ("rpc section");
458 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
459 }
460 }
461
462 /* Copy over the sections. */
463 bfd_map_over_sections (inbfd, copy_sections, (PTR) outbfd);
464
465 /* Finish up the header information. */
466 if (custom_file != NULL)
467 {
468 PTR data;
469
470 data = xmalloc (custom_size);
471 if (fread (data, 1, custom_size, custom_data) != custom_size)
472 fprintf (stderr, "%s:%s: read: %s\n", program_name, custom_file,
473 strerror (errno));
474 else
475 {
476 if (! bfd_set_section_contents (outbfd, custom_section, data,
477 (file_ptr) 0, custom_size))
478 bfd_fatal ("custom section");
479 nlm_fixed_header (outbfd)->customDataOffset =
480 custom_section->filepos;
481 nlm_fixed_header (outbfd)->customDataSize = custom_size;
482 }
483 free (data);
484 }
485 if (! debug_info)
486 {
487 /* As a special hack, the backend recognizes a debugInfoOffset
488 of -1 to mean that it should not output any debugging
489 information. This can not be handling by fiddling with the
490 symbol table because exported symbols appear in both the
491 export information and the debugging information. */
492 nlm_fixed_header (outbfd)->debugInfoOffset = (file_ptr) -1;
493 }
494 if (map_file != NULL)
495 fprintf (stderr,
496 "%s: MAP and FULLMAP are not supported; try ld -M\n",
497 program_name);
498 if (help_file != NULL)
499 {
500 PTR data;
501
502 data = xmalloc (help_size);
503 if (fread (data, 1, help_size, help_data) != help_size)
504 fprintf (stderr, "%s:%s: read: %s\n", program_name, help_file,
505 strerror (errno));
506 else
507 {
508 if (! bfd_set_section_contents (outbfd, help_section, data,
509 (file_ptr) 0, help_size))
510 bfd_fatal ("help section");
511 nlm_extended_header (outbfd)->helpFileOffset =
512 help_section->filepos;
513 nlm_extended_header (outbfd)->helpFileLength = help_size;
514 }
515 free (data);
516 }
517 if (message_file != NULL)
518 {
519 PTR data;
520
521 data = xmalloc (message_size);
522 if (fread (data, 1, message_size, message_data) != message_size)
523 fprintf (stderr, "%s:%s: read: %s\n", program_name, message_file,
524 strerror (errno));
525 else
526 {
527 if (! bfd_set_section_contents (outbfd, message_section, data,
528 (file_ptr) 0, message_size))
529 bfd_fatal ("message section");
530 nlm_extended_header (outbfd)->messageFileOffset =
531 message_section->filepos;
532 nlm_extended_header (outbfd)->messageFileLength = message_size;
533
534 /* FIXME: Are these offsets correct on all platforms? Are
535 they 32 bits on all platforms? What endianness? */
536 nlm_extended_header (outbfd)->languageID =
537 bfd_h_get_32 (outbfd, (bfd_byte *) data + 106);
538 nlm_extended_header (outbfd)->messageCount =
539 bfd_h_get_32 (outbfd, (bfd_byte *) data + 110);
540 }
541 free (data);
542 }
543 if (modules != NULL)
544 {
545 PTR data;
546 char *set;
547 struct string_list *l;
548 bfd_size_type c;
549
550 data = xmalloc (module_size);
551 c = 0;
552 set = (char *) data;
553 for (l = modules; l != NULL; l = l->next)
554 {
555 *set = strlen (l->string);
556 strncpy (set + 1, l->string, *set);
557 set += *set + 1;
558 ++c;
559 }
560 if (! bfd_set_section_contents (outbfd, module_section, data,
561 (file_ptr) 0, module_size))
562 bfd_fatal ("module section");
563 nlm_fixed_header (outbfd)->moduleDependencyOffset =
564 module_section->filepos;
565 nlm_fixed_header (outbfd)->numberOfModuleDependencies = c;
566 }
567 if (rpc_file != NULL)
568 {
569 PTR data;
570
571 data = xmalloc (rpc_size);
572 if (fread (data, 1, rpc_size, rpc_data) != rpc_size)
573 fprintf (stderr, "%s:%s: read: %s\n", program_name, rpc_file,
574 strerror (errno));
575 else
576 {
577 if (! bfd_set_section_contents (outbfd, rpc_section, data,
578 (file_ptr) 0, rpc_size))
579 bfd_fatal ("rpc section");
580 nlm_extended_header (outbfd)->RPCDataOffset =
581 rpc_section->filepos;
582 nlm_extended_header (outbfd)->RPCDataLength = rpc_size;
583 }
584 free (data);
585 }
586 len = strlen (argv[optind + 1]);
587 if (len > NLM_MODULE_NAME_SIZE - 2)
588 len = NLM_MODULE_NAME_SIZE - 2;
589 nlm_fixed_header (outbfd)->moduleName[0] = len;
590 strncpy (nlm_fixed_header (outbfd)->moduleName + 1, argv[optind + 1],
591 NLM_MODULE_NAME_SIZE - 2);
592 nlm_fixed_header (outbfd)->moduleName[NLM_MODULE_NAME_SIZE - 1] = '\0';
593 strncpy (nlm_variable_header (outbfd)->oldThreadName, " LONG",
594 NLM_OLD_THREAD_NAME_LENGTH);
595
596 if (! bfd_close (outbfd))
597 bfd_fatal (argv[optind + 1]);
598 if (! bfd_close (inbfd))
599 bfd_fatal (argv[optind]);
600
601 return 0;
602 }
603 \f
604 /* Display a help message and exit. */
605
606 static void
607 show_help ()
608 {
609 printf ("%s: Convert an object file into a NetWare Loadable Module\n",
610 program_name);
611 show_usage (stdout, 0);
612 }
613
614 /* Show a usage message and exit. */
615
616 static void
617 show_usage (file, status)
618 FILE *file;
619 int status;
620 {
621 fprintf (file, "\
622 Usage: %s [-Hv] [-I format] [-O format] [-T header-file]\n\
623 [--input-format=format] [--output-format=format]\n\
624 [--header-file=file] [--help] [--version]\n\
625 in-file out-file\n",
626 program_name);
627 exit (status);
628 }
629 \f
630 /* Select the output format based on the input architecture, machine,
631 and endianness. This chooses the appropriate NLM target. */
632
633 static const char *
634 select_output_format (arch, mach, bigendian)
635 enum bfd_architecture arch;
636 long mach;
637 boolean bigendian;
638 {
639 switch (arch)
640 {
641 case bfd_arch_i386:
642 return "nlm32-i386";
643 default:
644 fprintf (stderr, "%s: no default NLM format for %s\n",
645 program_name, bfd_printable_arch_mach (arch, mach));
646 exit (1);
647 /* Avoid warning. */
648 return NULL;
649 }
650 /*NOTREACHED*/
651 }
652 \f
653 /* The BFD sections are copied in two passes. This function sets up
654 the section name, size, etc. */
655
656 static void
657 setup_sections (inbfd, insec, data_ptr)
658 bfd *inbfd;
659 asection *insec;
660 PTR data_ptr;
661 {
662 bfd *outbfd = (bfd *) data_ptr;
663 asection *outsec;
664
665 outsec = bfd_get_section_by_name (outbfd, bfd_section_name (inbfd, insec));
666 if (outsec == NULL)
667 {
668 outsec = bfd_make_section (outbfd, bfd_section_name (inbfd, insec));
669 if (outsec == NULL)
670 bfd_fatal ("make section");
671 }
672
673 insec->output_section = outsec;
674 insec->output_offset = 0;
675
676 if (! bfd_set_section_size (outbfd, outsec,
677 bfd_section_size (inbfd, insec)))
678 bfd_fatal ("set section size");
679
680 if (! bfd_set_section_vma (outbfd, outsec,
681 bfd_section_vma (inbfd, insec)))
682 bfd_fatal ("set section vma");
683
684 if (! bfd_set_section_alignment (outbfd, outsec,
685 bfd_section_alignment (inbfd, insec)))
686 bfd_fatal ("set section alignment");
687
688 if (! bfd_set_section_flags (outbfd, outsec,
689 bfd_get_section_flags (inbfd, insec)))
690 bfd_fatal ("set section flags");
691 }
692
693 /* Copy the section contents. */
694
695 static void
696 copy_sections (inbfd, insec, data_ptr)
697 bfd *inbfd;
698 asection *insec;
699 PTR data_ptr;
700 {
701 bfd *outbfd = (bfd *) data_ptr;
702 asection *outsec;
703 bfd_size_type size;
704 PTR contents;
705 bfd_size_type reloc_size;
706
707 outsec = bfd_get_section_by_name (outbfd, bfd_section_name (inbfd, insec));
708 assert (outsec != NULL);
709
710 size = bfd_get_section_size_before_reloc (insec);
711 if (size == 0)
712 return;
713
714 /* FIXME: Why are these necessary? */
715 insec->_cooked_size = insec->_raw_size;
716 insec->reloc_done = true;
717
718 if ((bfd_get_section_flags (inbfd, insec) & SEC_HAS_CONTENTS) == 0)
719 contents = NULL;
720 else
721 {
722 contents = xmalloc (size);
723 if (! bfd_get_section_contents (inbfd, insec, contents,
724 (file_ptr) 0, size))
725 bfd_fatal (bfd_get_filename (inbfd));
726 }
727
728 reloc_size = bfd_get_reloc_upper_bound (inbfd, insec);
729 if (reloc_size == 0)
730 bfd_set_reloc (outbfd, outsec, (arelent **) NULL, 0);
731 else
732 {
733 arelent **relocs;
734 bfd_size_type reloc_count;
735
736 relocs = (arelent **) xmalloc (reloc_size);
737 reloc_count = bfd_canonicalize_reloc (inbfd, insec, relocs, symbols);
738 mangle_relocs (outbfd, relocs, reloc_count, (char *) contents, size);
739 bfd_set_reloc (outbfd, outsec, relocs, reloc_count);
740 }
741
742 if (contents != NULL)
743 {
744 if (! bfd_set_section_contents (outbfd, outsec, contents,
745 (file_ptr) 0, size))
746 bfd_fatal (bfd_get_filename (outbfd));
747 free (contents);
748 }
749 }
750
751 /* Some, perhaps all, NetWare targets require changing the relocs used
752 by the input formats. */
753
754 static void
755 mangle_relocs (outbfd, relocs, reloc_count, contents, contents_size)
756 bfd *outbfd;
757 arelent **relocs;
758 bfd_size_type reloc_count;
759 char *contents;
760 bfd_size_type contents_size;
761 {
762 switch (bfd_get_arch (outbfd))
763 {
764 case bfd_arch_i386:
765 i386_mangle_relocs (outbfd, relocs, reloc_count, contents,
766 contents_size);
767 break;
768 default:
769 break;
770 }
771 }
772
773 /* NetWare on the i386 supports a restricted set of relocs, which are
774 different from those used on other i386 targets. This routine
775 converts the relocs. It is, obviously, very target dependent. At
776 the moment, the nlm32-i386 backend performs similar translations;
777 however, it is more reliable and efficient to do them here. */
778
779 static reloc_howto_type nlm_i386_pcrel_howto =
780 HOWTO (1, /* type */
781 0, /* rightshift */
782 2, /* size (0 = byte, 1 = short, 2 = long) */
783 32, /* bitsize */
784 true, /* pc_relative */
785 0, /* bitpos */
786 complain_overflow_signed, /* complain_on_overflow */
787 0, /* special_function */
788 "DISP32", /* name */
789 true, /* partial_inplace */
790 0xffffffff, /* src_mask */
791 0xffffffff, /* dst_mask */
792 true); /* pcrel_offset */
793
794 static void
795 i386_mangle_relocs (outbfd, relocs, reloc_count, contents, contents_size)
796 bfd *outbfd;
797 arelent **relocs;
798 bfd_size_type reloc_count;
799 char *contents;
800 bfd_size_type contents_size;
801 {
802 while (reloc_count-- != 0)
803 {
804 arelent *rel;
805 asymbol *sym;
806 bfd_vma addend;
807
808 rel = *relocs++;
809 sym = *rel->sym_ptr_ptr;
810
811 /* Note that no serious harm will ensue if we fail to change a
812 reloc. The backend will fail when writing out the reloc. */
813
814 /* Make sure this reloc is within the data we have. We use only
815 4 byte relocs here, so we insist on having 4 bytes. */
816 if (rel->address + 4 > contents_size)
817 continue;
818
819 /* NetWare doesn't support reloc addends, so we get rid of them
820 here by simply adding them into the object data. We handle
821 the symbol value, if any, the same way. */
822 addend = rel->addend;
823 if (! bfd_is_com_section (bfd_get_section (sym)))
824 addend += sym->value;
825
826 if (addend != 0
827 && rel->howto != NULL
828 && rel->howto->rightshift == 0
829 && rel->howto->size == 2
830 && rel->howto->bitsize == 32
831 && rel->howto->bitpos == 0
832 && rel->howto->src_mask == 0xffffffff
833 && rel->howto->dst_mask == 0xffffffff)
834 {
835 bfd_vma val;
836
837 val = bfd_get_32 (outbfd, contents + rel->address);
838 val += addend;
839 bfd_put_32 (outbfd, val, contents + rel->address);
840
841 /* Adjust the reloc for the changes we just made. */
842 rel->addend = 0;
843 if (! bfd_is_com_section (bfd_get_section (sym))
844 && sym->value != 0)
845 rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
846 }
847
848 /* NetWare uses a reloc with pcrel_offset set. We adjust
849 pc_relative relocs accordingly. We are going to change the
850 howto field, so we can only do this if the current one is
851 compatible. We should check that special_function is NULL
852 here, but at the moment coff-i386 uses a special_function
853 which does not affect what we are doing here. */
854 if (rel->howto != NULL
855 && rel->howto->pc_relative
856 && ! rel->howto->pcrel_offset
857 && rel->howto->rightshift == 0
858 && rel->howto->size == 2
859 && rel->howto->bitsize == 32
860 && rel->howto->bitpos == 0
861 && rel->howto->src_mask == 0xffffffff
862 && rel->howto->dst_mask == 0xffffffff)
863 {
864 bfd_vma val;
865
866 /* When pcrel_offset is not set, it means that the negative
867 of the address of the memory location is stored in the
868 memory location. We must add it back in. */
869 val = bfd_get_32 (outbfd, contents + rel->address);
870 val += rel->address;
871 bfd_put_32 (outbfd, val, contents + rel->address);
872
873 /* We must change to a new howto. */
874 rel->howto = &nlm_i386_pcrel_howto;
875 }
876 }
877 }
This page took 0.047442 seconds and 4 git commands to generate.