Write out all the header information, except the SHARELIB stuff which
[external/binutils.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 }