* nlmconv.c (main): Force creation of .bss section. Set up the
[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 <time.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <assert.h>
35 #include <getopt.h>
36 #include <bfd.h>
37 #include "sysdep.h"
38 #include "bucomm.h"
39 /* Internal BFD NLM header.  */
40 #include "libnlm.h"
41 #include "nlmconv.h"
42
43 /* If strerror is just a macro, we want to use the one from libiberty
44    since it will handle undefined values.  */
45 #undef strerror
46 extern char *strerror ();
47
48 #ifndef localtime
49 extern struct tm *localtime ();
50 #endif
51
52 #ifndef SEEK_SET
53 #define SEEK_SET 0
54 #endif
55 \f
56 /* Global variables.  */
57
58 /* The name used to invoke the program.  */
59 char *program_name;
60
61 /* The version number.  */
62 extern char *program_version;
63
64 /* Local variables.  */
65
66 /* The symbol table.  */
67 static asymbol **symbols;
68
69 /* The total amount of bss space.  */
70 static bfd_size_type total_bss_size;
71
72 /* The list of long options.  */
73 static struct option long_options[] =
74 {
75   { "header-info", required_argument, 0, 'T' },
76   { "help", no_argument, 0, 'h' },
77   { "input-format", required_argument, 0, 'I' },
78   { "output-format", required_argument, 0, 'O' },
79   { "version", no_argument, 0, 'V' },
80   { NULL, no_argument, 0, 0 }
81 };
82
83 /* Local routines.  */
84
85 static void show_help PARAMS ((void));
86 static void show_usage PARAMS ((FILE *, int));
87 static const char *select_output_format PARAMS ((enum bfd_architecture,
88                                                  long, boolean));
89 static void setup_sections PARAMS ((bfd *, asection *, PTR));
90 static void copy_sections PARAMS ((bfd *, asection *, PTR));
91 static void mangle_relocs PARAMS ((bfd *, asection *, arelent **,
92                                    bfd_size_type *, char *,
93                                    bfd_size_type));
94 static void i386_mangle_relocs PARAMS ((bfd *, asection *, arelent **,
95                                         bfd_size_type *, char *,
96                                         bfd_size_type));
97 \f
98 /* The main routine.  */
99
100 int
101 main (argc, argv)
102      int argc;
103      char **argv;
104 {
105   int opt;
106   const char *input_format = NULL;
107   const char *output_format = NULL;
108   const char *header_file = NULL;
109   bfd *inbfd;
110   bfd *outbfd;
111   asymbol **newsyms, **outsyms;
112   unsigned int symcount, newsymalloc, newsymcount;
113   asection *bss_sec;
114   asymbol *endsym;
115   unsigned int i;
116   char inlead, outlead;
117   boolean gotstart, gotexit, gotcheck;
118   struct stat st;
119   FILE *custom_data, *help_data, *message_data, *rpc_data, *shared_data;
120   bfd_size_type custom_size, help_size, message_size, module_size, rpc_size;
121   asection *custom_section, *help_section, *message_section, *module_section;
122   asection *rpc_section, *shared_section;
123   bfd *sharedbfd;
124   bfd_size_type shared_offset, shared_size;
125   Nlm_Internal_Fixed_Header sharedhdr;
126   int len;
127
128   program_name = argv[0];
129
130   bfd_init ();
131
132   while ((opt = getopt_long (argc, argv, "hI:O:T:V", long_options, (int *) 0))
133          != EOF)
134     {
135       switch (opt)
136         {
137         case 'h':
138           show_help ();
139           /*NOTREACHED*/
140         case 'I':
141           input_format = optarg;
142           break;
143         case 'O':
144           output_format = optarg;
145           break;
146         case 'T':
147           header_file = optarg;
148           break;
149         case 'V':
150           printf ("GNU %s version %s\n", program_name, program_version);
151           exit (0);
152           /*NOTREACHED*/
153         case 0:
154           break;
155         default:
156           show_usage (stderr, 1);
157           /*NOTREACHED*/
158         }
159     }
160
161   if (optind + 2 != argc)
162     show_usage (stderr, 1);
163
164   if (strcmp (argv[optind], argv[optind + 1]) == 0)
165     {
166       fprintf (stderr, "%s: input and output files must be different\n",
167                program_name);
168       exit (1);
169     }
170
171   inbfd = bfd_openr (argv[optind], input_format);
172   if (inbfd == NULL)
173     bfd_fatal (argv[optind]);
174
175   if (! bfd_check_format (inbfd, bfd_object))
176     bfd_fatal (argv[optind]);
177
178   if (output_format == NULL)
179     output_format = select_output_format (bfd_get_arch (inbfd),
180                                           bfd_get_mach (inbfd),
181                                           inbfd->xvec->byteorder_big_p);
182
183   assert (output_format != NULL);
184   outbfd = bfd_openw (argv[optind + 1], output_format);
185   if (outbfd == NULL)
186     bfd_fatal (argv[optind + 1]);
187   if (! bfd_set_format (outbfd, bfd_object))
188     bfd_fatal (argv[optind + 1]);
189
190   assert (outbfd->xvec->flavour == bfd_target_nlm_flavour);
191
192   if (bfd_arch_get_compatible (inbfd, outbfd) == NULL)
193     fprintf (stderr,
194              "%s: warning:input and output formats are not compatible\n",
195              program_name);
196
197   /* Initialize the header information to default values.  */
198   fixed_hdr = nlm_fixed_header (outbfd);
199   var_hdr = nlm_variable_header (outbfd);
200   version_hdr = nlm_version_header (outbfd);
201   copyright_hdr = nlm_copyright_header (outbfd);
202   extended_hdr = nlm_extended_header (outbfd);
203   check_procedure = NULL;
204   custom_file = NULL;
205   debug_info = false;
206   exit_procedure = "_Stop";
207   export_symbols = NULL;
208   map_file = NULL;
209   full_map = false;
210   help_file = NULL;
211   import_symbols = NULL;
212   message_file = NULL;
213   modules = NULL;
214   sharelib_file = NULL;
215   start_procedure = "_Prelude";
216   verbose = false;
217   rpc_file = NULL;
218
219   parse_errors = 0;
220
221   /* Parse the header file (if there is one).  */
222   if (header_file != NULL)
223     {
224       if (! nlmlex_file (header_file)
225           || yyparse () != 0
226           || parse_errors != 0)
227         exit (1);
228     }
229
230   /* Start copying the input BFD to the output BFD.  */
231   if (! bfd_set_file_flags (outbfd, bfd_get_file_flags (inbfd)))
232     bfd_fatal (bfd_get_filename (outbfd));
233
234   symbols = (asymbol **) xmalloc (get_symtab_upper_bound (inbfd));
235   symcount = bfd_canonicalize_symtab (inbfd, symbols);
236
237   /* Make sure we have a .bss section.  Doing this first is an attempt
238      to ensure that it will be the first bss section.  */
239   bss_sec = bfd_get_section_by_name (outbfd, NLM_UNINITIALIZED_DATA_NAME);
240   if (bss_sec == NULL)
241     {
242       bss_sec = bfd_make_section (outbfd, NLM_UNINITIALIZED_DATA_NAME);
243       if (bss_sec == NULL)
244         bfd_fatal ("make .bss section");
245       bss_sec->flags = SEC_ALLOC;
246       bss_sec->alignment_power = bfd_log2 (0); /* FIXME */
247     }
248
249   /* Set up the sections.  */
250   bfd_map_over_sections (inbfd, setup_sections, (PTR) outbfd);
251
252   /* Adjust symbol information.  */
253   inlead = bfd_get_symbol_leading_char (inbfd);
254   outlead = bfd_get_symbol_leading_char (outbfd);
255   gotstart = false;
256   gotexit = false;
257   gotcheck = false;
258   newsymalloc = 10;
259   newsyms = (asymbol **) xmalloc (newsymalloc * sizeof (asymbol *));
260   newsymcount = 0;
261   endsym = NULL;
262   for (i = 0; i < symcount; i++)
263     {
264       register asymbol *sym;
265
266       sym = symbols[i];
267
268       /* Add or remove a leading underscore.  */
269       if (inlead != outlead)
270         {
271           if (inlead != '\0')
272             {
273               if (bfd_asymbol_name (sym)[0] == inlead)
274                 {
275                   if (outlead == '\0')
276                     ++sym->name;
277                   else
278                     {
279                       char *new;
280
281                       new = xmalloc (strlen (bfd_asymbol_name (sym)) + 1);
282                       new[0] = outlead;
283                       strcpy (new + 1, bfd_asymbol_name (sym) + 1);
284                       sym->name = new;
285                     }
286                 }
287             }
288           else
289             {
290               char *new;
291
292               new = xmalloc (strlen (bfd_asymbol_name (sym)) + 2);
293               new[0] = outlead;
294               strcpy (new + 1, bfd_asymbol_name (sym));
295               sym->name = new;
296             }
297         }
298
299       /* NLM's have an uninitialized data section, but they do not
300          have a common section in the Unix sense.  Move all common
301          symbols into the .bss section, and mark them as exported.  */
302       if (bfd_is_com_section (bfd_get_section (sym)))
303         {
304           bfd_vma size;
305           bfd_size_type align;
306
307           sym->section = bss_sec;
308           size = sym->value;
309           sym->value = bss_sec->_raw_size;
310           bss_sec->_raw_size += size;
311           align = 1 << bss_sec->alignment_power;
312           bss_sec->_raw_size = (bss_sec->_raw_size + align - 1) &~ (align - 1);
313           total_bss_size += bss_sec->_raw_size - sym->value;
314           sym->flags |= BSF_EXPORT | BSF_GLOBAL;
315         }
316
317       /* Force _edata and _end to be defined.  This would normally be
318          done by the linker, but the manipulation of the common
319          symbols will confuse it.  */
320       if (bfd_asymbol_name (sym)[0] == '_'
321           && bfd_get_section (sym) == &bfd_und_section)
322         {
323           if (strcmp (bfd_asymbol_name (sym), "_edata") == 0)
324             {
325               sym->section = bss_sec;
326               sym->value = 0;
327             }
328           if (strcmp (bfd_asymbol_name (sym), "_end") == 0)
329             {
330               sym->section = bss_sec;
331               endsym = sym;
332             }
333         }
334
335       /* If this is a global symbol, check the export list.  */
336       if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) != 0)
337         {
338           register struct string_list *l;
339           int found_simple;
340
341           /* Unfortunately, a symbol can appear multiple times on the
342              export list, with and without prefixes.  */
343           found_simple = 0;
344           for (l = export_symbols; l != NULL; l = l->next)
345             {
346               if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
347                 found_simple = 1;
348               else
349                 {
350                   char *zbase;
351
352                   zbase = strchr (l->string, '@');
353                   if (zbase != NULL
354                       && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
355                     {
356                       /* We must add a symbol with this prefix.  */
357                       if (newsymcount >= newsymalloc)
358                         {
359                           newsymalloc += 10;
360                           newsyms = ((asymbol **)
361                                      xrealloc (newsyms,
362                                                (newsymalloc
363                                                 * sizeof (asymbol *))));
364                         }
365                       newsyms[newsymcount] =
366                         (asymbol *) xmalloc (sizeof (asymbol));
367                       *newsyms[newsymcount] = *sym;
368                       newsyms[newsymcount]->name = l->string;
369                       ++newsymcount;
370                     }
371                 }
372             }
373           if (! found_simple)
374             {
375               /* The unmodified symbol is actually not exported at
376                  all.  */
377               sym->flags &=~ (BSF_GLOBAL | BSF_EXPORT);
378               sym->flags |= BSF_LOCAL;
379             }
380         }
381
382       /* If it's an undefined symbol, see if it's on the import list.
383          Change the prefix if necessary.  */
384       if (bfd_get_section (sym) == &bfd_und_section
385           && import_symbols != NULL)
386         {
387           register struct string_list *l;
388
389           for (l = import_symbols; l != NULL; l = l->next)
390             {
391               if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
392                 break;
393               else
394                 {
395                   char *zbase;
396
397                   zbase = strchr (l->string, '@');
398                   if (zbase != NULL
399                       && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
400                     {
401                       sym->name = l->string;
402                       break;
403                     }
404                 }
405             }
406           if (l == NULL)
407             fprintf (stderr,
408                      "%s: warning: symbol %s imported but not in import list\n",
409                      program_name, bfd_asymbol_name (sym));
410         }
411         
412       /* See if it's one of the special named symbols.  */
413       if (strcmp (bfd_asymbol_name (sym), start_procedure) == 0)
414         {
415           if (! bfd_set_start_address (outbfd, bfd_asymbol_value (sym)))
416             bfd_fatal ("set start address");
417           gotstart = true;
418         }
419       if (strcmp (bfd_asymbol_name (sym), exit_procedure) == 0)
420         {
421           nlm_fixed_header (outbfd)->exitProcedureOffset =
422             bfd_asymbol_value (sym);
423           gotexit = true;
424         }
425       if (check_procedure != NULL
426           && strcmp (bfd_asymbol_name (sym), check_procedure) == 0)
427         {
428           nlm_fixed_header (outbfd)->checkUnloadProcedureOffset =
429             bfd_asymbol_value (sym);
430           gotcheck = true;
431         }
432     }
433
434   if (endsym != NULL)
435     endsym->value = total_bss_size;
436
437   if (newsymcount == 0)
438     outsyms = symbols;
439   else
440     {
441       outsyms = (asymbol **) xmalloc ((symcount + newsymcount + 1)
442                                       * sizeof (asymbol *));
443       memcpy (outsyms, symbols, symcount * sizeof (asymbol *));
444       memcpy (outsyms + symcount, newsyms, newsymcount * sizeof (asymbol *));
445       outsyms[symcount + newsymcount] = NULL;
446     }
447
448   bfd_set_symtab (outbfd, outsyms, symcount + newsymcount);
449     
450   if (! gotstart)
451     fprintf (stderr, "%s: warning: START procedure %s not defined\n",
452              program_name, start_procedure);
453   if (! gotexit)
454     fprintf (stderr, "%s: warning: EXIT procedure %s not defined\n",
455              program_name, exit_procedure);
456   if (check_procedure != NULL
457       && ! gotcheck)
458     fprintf (stderr, "%s: warning: CHECK procedure %s not defined\n",
459              program_name, check_procedure);
460
461   /* Add additional sections required for the header information.  */
462   if (custom_file != NULL)
463     {
464       custom_data = fopen (custom_file, "r");
465       if (custom_data == NULL
466           || fstat (fileno (custom_data), &st) < 0)
467         {
468           fprintf (stderr, "%s:%s: %s\n", program_name, custom_file,
469                    strerror (errno));
470           custom_file = NULL;
471         }
472       else
473         {
474           custom_size = st.st_size;
475           custom_section = bfd_make_section (outbfd, ".nlmcustom");
476           if (custom_section == NULL
477               || ! bfd_set_section_size (outbfd, custom_section, custom_size)
478               || ! bfd_set_section_flags (outbfd, custom_section,
479                                           SEC_HAS_CONTENTS))
480             bfd_fatal ("custom section");
481         }
482     }
483   if (help_file != NULL)
484     {
485       help_data = fopen (help_file, "r");
486       if (help_data == NULL
487           || fstat (fileno (help_data), &st) < 0)
488         {
489           fprintf (stderr, "%s:%s: %s\n", program_name, help_file,
490                    strerror (errno));
491           help_file = NULL;
492         }
493       else
494         {
495           help_size = st.st_size;
496           help_section = bfd_make_section (outbfd, ".nlmhelp");
497           if (help_section == NULL
498               || ! bfd_set_section_size (outbfd, help_section, help_size)
499               || ! bfd_set_section_flags (outbfd, help_section,
500                                           SEC_HAS_CONTENTS))
501             bfd_fatal ("help section");
502           strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
503         }
504     }
505   if (message_file != NULL)
506     {
507       message_data = fopen (message_file, "r");
508       if (message_data == NULL
509           || fstat (fileno (message_data), &st) < 0)
510         {
511           fprintf (stderr, "%s:%s: %s\n", program_name, message_file,
512                    strerror (errno));
513           message_file = NULL;
514         }
515       else
516         {
517           message_size = st.st_size;
518           message_section = bfd_make_section (outbfd, ".nlmmessages");
519           if (message_section == NULL
520               || ! bfd_set_section_size (outbfd, message_section, message_size)
521               || ! bfd_set_section_flags (outbfd, message_section,
522                                           SEC_HAS_CONTENTS))
523             bfd_fatal ("message section");
524           strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
525         }
526     }
527   if (modules != NULL)
528     {
529       struct string_list *l;
530
531       module_size = 0;
532       for (l = modules; l != NULL; l = l->next)
533         module_size += strlen (l->string) + 1;
534       module_section = bfd_make_section (outbfd, ".nlmmodules");
535       if (module_section == NULL
536           || ! bfd_set_section_size (outbfd, module_section, module_size)
537           || ! bfd_set_section_flags (outbfd, module_section,
538                                       SEC_HAS_CONTENTS))
539         bfd_fatal ("module section");
540     }
541   if (rpc_file != NULL)
542     {
543       rpc_data = fopen (rpc_file, "r");
544       if (rpc_data == NULL
545           || fstat (fileno (rpc_data), &st) < 0)
546         {
547           fprintf (stderr, "%s:%s: %s\n", program_name, rpc_file,
548                    strerror (errno));
549           rpc_file = NULL;
550         }
551       else
552         {
553           rpc_size = st.st_size;
554           rpc_section = bfd_make_section (outbfd, ".nlmrpc");
555           if (rpc_section == NULL
556               || ! bfd_set_section_size (outbfd, rpc_section, rpc_size)
557               || ! bfd_set_section_flags (outbfd, rpc_section,
558                                           SEC_HAS_CONTENTS))
559             bfd_fatal ("rpc section");
560           strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
561         }
562     }
563   if (sharelib_file != NULL)
564     {
565       sharedbfd = bfd_openr (sharelib_file, output_format);
566       if (sharedbfd == NULL
567           || ! bfd_check_format (sharedbfd, bfd_object))
568         {
569           fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
570                    bfd_errmsg (bfd_error));
571           sharelib_file = NULL;
572         }
573       else
574         {
575           sharedhdr = *nlm_fixed_header (sharedbfd);
576           bfd_close (sharedbfd);
577           shared_data = fopen (sharelib_file, "r");
578           if (shared_data == NULL
579               || (fstat (fileno (shared_data), &st) < 0))
580             {
581               fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
582                        strerror (errno));
583               sharelib_file = NULL;
584             }
585           else
586             {
587               /* If we were clever, we could just copy out the
588                  sections of the shared library which we actually
589                  need.  However, we would have to figure out the sizes
590                  of the external and public information, and that can
591                  not be done without reading through them.  */
592               shared_offset = st.st_size;
593               if (shared_offset > sharedhdr.codeImageOffset)
594                 shared_offset = sharedhdr.codeImageOffset;
595               if (shared_offset > sharedhdr.dataImageOffset)
596                 shared_offset = sharedhdr.dataImageOffset;
597               if (shared_offset > sharedhdr.relocationFixupOffset)
598                 shared_offset = sharedhdr.relocationFixupOffset;
599               if (shared_offset > sharedhdr.externalReferencesOffset)
600                 shared_offset = sharedhdr.externalReferencesOffset;
601               if (shared_offset > sharedhdr.publicsOffset)
602                 shared_offset = sharedhdr.publicsOffset;
603               shared_size = st.st_size - shared_offset;
604               shared_section = bfd_make_section (outbfd, ".nlmshared");
605               if (shared_section == NULL
606                   || ! bfd_set_section_size (outbfd, shared_section,
607                                              shared_size)
608                   || ! bfd_set_section_flags (outbfd, shared_section,
609                                               SEC_HAS_CONTENTS))
610                 bfd_fatal ("shared section");
611               strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
612             }
613         }
614     }
615
616   /* Check whether a version was given.  */
617   if (strncmp (version_hdr->stamp, "VeRsIoN#", 8) != 0)
618     fprintf (stderr, "%s: warning: No version number given\n",
619              program_name);
620
621   /* At least for now, always create an extended header, because that
622      is what NLMLINK does.  */
623   strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
624
625   /* If the date was not given, force it in.  */
626   if (nlm_version_header (outbfd)->month == 0
627       && nlm_version_header (outbfd)->day == 0
628       && nlm_version_header (outbfd)->year == 0)
629     {
630       unsigned long now;        /* FIXME: should be time_t.  */
631       struct tm *ptm;
632
633       time (&now);
634       ptm = localtime (&now);
635       nlm_version_header (outbfd)->month = ptm->tm_mon + 1;
636       nlm_version_header (outbfd)->day = ptm->tm_mday;
637       nlm_version_header (outbfd)->year = ptm->tm_year + 1900;
638       strncpy (version_hdr->stamp, "VeRsIoN#", 8);
639     }
640
641   /* Copy over the sections.  */
642   bfd_map_over_sections (inbfd, copy_sections, (PTR) outbfd);
643
644   /* Finish up the header information.  */
645   if (custom_file != NULL)
646     {
647       PTR data;
648
649       data = xmalloc (custom_size);
650       if (fread (data, 1, custom_size, custom_data) != custom_size)
651         fprintf (stderr, "%s:%s: read: %s\n", program_name, custom_file,
652                  strerror (errno));
653       else
654         {
655           if (! bfd_set_section_contents (outbfd, custom_section, data,
656                                           (file_ptr) 0, custom_size))
657             bfd_fatal ("custom section");
658           nlm_fixed_header (outbfd)->customDataOffset =
659             custom_section->filepos;
660           nlm_fixed_header (outbfd)->customDataSize = custom_size;
661         }
662       free (data);
663     }
664   if (! debug_info)
665     {
666       /* As a special hack, the backend recognizes a debugInfoOffset
667          of -1 to mean that it should not output any debugging
668          information.  This can not be handling by fiddling with the
669          symbol table because exported symbols appear in both the
670          export information and the debugging information.  */
671       nlm_fixed_header (outbfd)->debugInfoOffset = (file_ptr) -1;
672     }
673   if (map_file != NULL)
674     fprintf (stderr,
675              "%s: MAP and FULLMAP are not supported; try ld -M\n",
676              program_name);
677   if (help_file != NULL)
678     {
679       PTR data;
680
681       data = xmalloc (help_size);
682       if (fread (data, 1, help_size, help_data) != help_size)
683         fprintf (stderr, "%s:%s: read: %s\n", program_name, help_file,
684                  strerror (errno));
685       else
686         {
687           if (! bfd_set_section_contents (outbfd, help_section, data,
688                                           (file_ptr) 0, help_size))
689             bfd_fatal ("help section");
690           nlm_extended_header (outbfd)->helpFileOffset =
691             help_section->filepos;
692           nlm_extended_header (outbfd)->helpFileLength = help_size;
693         }
694       free (data);
695     }
696   if (message_file != NULL)
697     {
698       PTR data;
699
700       data = xmalloc (message_size);
701       if (fread (data, 1, message_size, message_data) != message_size)
702         fprintf (stderr, "%s:%s: read: %s\n", program_name, message_file,
703                  strerror (errno));
704       else
705         {
706           if (! bfd_set_section_contents (outbfd, message_section, data,
707                                           (file_ptr) 0, message_size))
708             bfd_fatal ("message section");
709           nlm_extended_header (outbfd)->messageFileOffset =
710             message_section->filepos;
711           nlm_extended_header (outbfd)->messageFileLength = message_size;
712
713           /* FIXME: Are these offsets correct on all platforms?  Are
714              they 32 bits on all platforms?  What endianness?  */
715           nlm_extended_header (outbfd)->languageID =
716             bfd_h_get_32 (outbfd, (bfd_byte *) data + 106);
717           nlm_extended_header (outbfd)->messageCount =
718             bfd_h_get_32 (outbfd, (bfd_byte *) data + 110);
719         }
720       free (data);
721     }
722   if (modules != NULL)
723     {
724       PTR data;
725       char *set;
726       struct string_list *l;
727       bfd_size_type c;
728
729       data = xmalloc (module_size);
730       c = 0;
731       set = (char *) data;
732       for (l = modules; l != NULL; l = l->next)
733         {
734           *set = strlen (l->string);
735           strncpy (set + 1, l->string, *set);
736           set += *set + 1;
737           ++c;
738         }
739       if (! bfd_set_section_contents (outbfd, module_section, data,
740                                       (file_ptr) 0, module_size))
741         bfd_fatal ("module section");
742       nlm_fixed_header (outbfd)->moduleDependencyOffset =
743         module_section->filepos;
744       nlm_fixed_header (outbfd)->numberOfModuleDependencies = c;
745     }
746   if (rpc_file != NULL)
747     {
748       PTR data;
749
750       data = xmalloc (rpc_size);
751       if (fread (data, 1, rpc_size, rpc_data) != rpc_size)
752         fprintf (stderr, "%s:%s: read: %s\n", program_name, rpc_file,
753                  strerror (errno));
754       else
755         {
756           if (! bfd_set_section_contents (outbfd, rpc_section, data,
757                                           (file_ptr) 0, rpc_size))
758             bfd_fatal ("rpc section");
759           nlm_extended_header (outbfd)->RPCDataOffset =
760             rpc_section->filepos;
761           nlm_extended_header (outbfd)->RPCDataLength = rpc_size;
762         }
763       free (data);
764     }
765   if (sharelib_file != NULL)
766     {
767       PTR data;
768
769       data = xmalloc (shared_size);
770       if (fseek (shared_data, shared_offset, SEEK_SET) != 0
771           || fread (data, 1, shared_size, shared_data) != shared_size)
772         fprintf (stderr, "%s:%s: read: %s\n", program_name, sharelib_file,
773                  strerror (errno));
774       else
775         {
776           if (! bfd_set_section_contents (outbfd, shared_section, data,
777                                           (file_ptr) 0, shared_size))
778             bfd_fatal ("shared section");
779         }
780       nlm_extended_header (outbfd)->sharedCodeOffset =
781         sharedhdr.codeImageOffset - shared_offset + shared_section->filepos;
782       nlm_extended_header (outbfd)->sharedCodeLength =
783         sharedhdr.codeImageSize;
784       nlm_extended_header (outbfd)->sharedDataOffset =
785         sharedhdr.dataImageOffset - shared_offset + shared_section->filepos;
786       nlm_extended_header (outbfd)->sharedDataLength =
787         sharedhdr.dataImageSize;
788       nlm_extended_header (outbfd)->sharedRelocationFixupOffset =
789         (sharedhdr.relocationFixupOffset
790          - shared_offset
791          + shared_section->filepos);
792       nlm_extended_header (outbfd)->sharedRelocationFixupCount =
793         sharedhdr.numberOfRelocationFixups;
794       nlm_extended_header (outbfd)->sharedExternalReferenceOffset =
795         (sharedhdr.externalReferencesOffset
796          - shared_offset
797          + shared_section->filepos);
798       nlm_extended_header (outbfd)->sharedExternalReferenceCount =
799         sharedhdr.numberOfExternalReferences;
800       nlm_extended_header (outbfd)->sharedPublicsOffset =
801         sharedhdr.publicsOffset - shared_offset + shared_section->filepos;
802       nlm_extended_header (outbfd)->sharedPublicsCount =
803         sharedhdr.numberOfPublics;
804       nlm_extended_header (outbfd)->SharedInitializationOffset =
805         sharedhdr.codeStartOffset;
806       nlm_extended_header (outbfd)->SharedExitProcedureOffset =
807         sharedhdr.exitProcedureOffset;
808       free (data);
809     }
810   len = strlen (argv[optind + 1]);
811   if (len > NLM_MODULE_NAME_SIZE - 2)
812     len = NLM_MODULE_NAME_SIZE - 2;
813   nlm_fixed_header (outbfd)->moduleName[0] = len;
814   strncpy (nlm_fixed_header (outbfd)->moduleName + 1, argv[optind + 1],
815            NLM_MODULE_NAME_SIZE - 2);
816   nlm_fixed_header (outbfd)->moduleName[NLM_MODULE_NAME_SIZE - 1] = '\0';
817   strncpy (nlm_variable_header (outbfd)->oldThreadName, " LONG",
818            NLM_OLD_THREAD_NAME_LENGTH);
819
820   if (! bfd_close (outbfd))
821     bfd_fatal (argv[optind + 1]);
822   if (! bfd_close (inbfd))
823     bfd_fatal (argv[optind]);
824
825   return 0;
826 }
827 \f
828 /* Display a help message and exit.  */
829
830 static void
831 show_help ()
832 {
833   printf ("%s: Convert an object file into a NetWare Loadable Module\n",
834           program_name);
835   show_usage (stdout, 0);
836 }
837
838 /* Show a usage message and exit.  */
839
840 static void
841 show_usage (file, status)
842      FILE *file;
843      int status;
844 {
845   fprintf (file, "\
846 Usage: %s [-hV] [-I format] [-O format] [-T header-file]\n\
847        [--input-format=format] [--output-format=format]\n\
848        [--header-file=file] [--help] [--version]\n\
849        in-file out-file\n",
850            program_name);
851   exit (status);
852 }
853 \f
854 /* Select the output format based on the input architecture, machine,
855    and endianness.  This chooses the appropriate NLM target.  */
856
857 static const char *
858 select_output_format (arch, mach, bigendian)
859      enum bfd_architecture arch;
860      long mach;
861      boolean bigendian;
862 {
863   switch (arch)
864     {
865     case bfd_arch_i386:
866       return "nlm32-i386";
867     default:
868       fprintf (stderr, "%s: no default NLM format for %s\n",
869                program_name, bfd_printable_arch_mach (arch, mach));
870       exit (1);
871       /* Avoid warning.  */
872       return NULL;
873     }
874   /*NOTREACHED*/
875 }
876 \f
877 /* The BFD sections are copied in two passes.  This function sets up
878    the section name, size, etc.  */
879
880 static void
881 setup_sections (inbfd, insec, data_ptr)
882      bfd *inbfd;
883      asection *insec;
884      PTR data_ptr;
885 {
886   bfd *outbfd = (bfd *) data_ptr;
887   asection *outsec;
888   flagword f;
889
890   outsec = bfd_get_section_by_name (outbfd, bfd_section_name (inbfd, insec));
891   if (outsec == NULL)
892     {
893       outsec = bfd_make_section (outbfd, bfd_section_name (inbfd, insec));
894       if (outsec == NULL)
895         bfd_fatal ("make section");
896     }
897
898   insec->output_section = outsec;
899   insec->output_offset = 0;
900
901   if (! bfd_set_section_size (outbfd, outsec,
902                               bfd_section_size (inbfd, insec)))
903     bfd_fatal ("set section size");
904
905   if (! bfd_set_section_vma (outbfd, outsec,
906                              bfd_section_vma (inbfd, insec)))
907     bfd_fatal ("set section vma");
908
909   if (! bfd_set_section_alignment (outbfd, outsec,
910                                  bfd_section_alignment (inbfd, insec)))
911     bfd_fatal ("set section alignment");
912
913   f = bfd_get_section_flags (inbfd, insec);
914   if (! bfd_set_section_flags (outbfd, outsec, f))
915     bfd_fatal ("set section flags");
916
917   if ((f & SEC_LOAD) == 0 && (f & SEC_ALLOC) != 0)
918     total_bss_size += bfd_section_size (inbfd, insec);
919 }
920
921 /* Copy the section contents.  */
922
923 static void
924 copy_sections (inbfd, insec, data_ptr)
925      bfd *inbfd;
926      asection *insec;
927      PTR data_ptr;
928 {
929   bfd *outbfd = (bfd *) data_ptr;
930   asection *outsec;
931   bfd_size_type size;
932   PTR contents;
933   bfd_size_type reloc_size;
934
935   outsec = bfd_get_section_by_name (outbfd, bfd_section_name (inbfd, insec));
936   assert (outsec != NULL);
937
938   size = bfd_get_section_size_before_reloc (insec);
939   if (size == 0)
940     return;
941
942   /* FIXME: Why are these necessary?  */
943   insec->_cooked_size = insec->_raw_size;
944   insec->reloc_done = true;
945
946   if ((bfd_get_section_flags (inbfd, insec) & SEC_HAS_CONTENTS) == 0)
947     contents = NULL;
948   else
949     {
950       contents = xmalloc (size);
951       if (! bfd_get_section_contents (inbfd, insec, contents,
952                                       (file_ptr) 0, size))
953         bfd_fatal (bfd_get_filename (inbfd));
954     }
955
956   reloc_size = bfd_get_reloc_upper_bound (inbfd, insec);
957   if (reloc_size == 0)
958     bfd_set_reloc (outbfd, outsec, (arelent **) NULL, 0);
959   else
960     {
961       arelent **relocs;
962       bfd_size_type reloc_count;
963
964       relocs = (arelent **) xmalloc (reloc_size);
965       reloc_count = bfd_canonicalize_reloc (inbfd, insec, relocs, symbols);
966       mangle_relocs (outbfd, insec, relocs, &reloc_count, (char *) contents,
967                      size);
968       bfd_set_reloc (outbfd, outsec, relocs, reloc_count);
969     }
970
971   if (contents != NULL)
972     {
973       if (! bfd_set_section_contents (outbfd, outsec, contents,
974                                       (file_ptr) 0, size))
975         bfd_fatal (bfd_get_filename (outbfd));
976       free (contents);
977     }
978 }
979
980 /* Some, perhaps all, NetWare targets require changing the relocs used
981    by the input formats.  */
982
983 static void
984 mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents, contents_size)
985      bfd *outbfd;
986      asection *insec;
987      arelent **relocs;
988      bfd_size_type *reloc_count_ptr;
989      char *contents;
990      bfd_size_type contents_size;
991 {
992   switch (bfd_get_arch (outbfd))
993     {
994     case bfd_arch_i386:
995       i386_mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents,
996                           contents_size);
997       break;
998     default:
999       break;
1000     }
1001 }
1002
1003 /* NetWare on the i386 supports a restricted set of relocs, which are
1004    different from those used on other i386 targets.  This routine
1005    converts the relocs.  It is, obviously, very target dependent.  At
1006    the moment, the nlm32-i386 backend performs similar translations;
1007    however, it is more reliable and efficient to do them here.  */
1008
1009 static reloc_howto_type nlm_i386_pcrel_howto =
1010   HOWTO (1,                     /* type */
1011          0,                     /* rightshift */
1012          2,                     /* size (0 = byte, 1 = short, 2 = long) */
1013          32,                    /* bitsize */
1014          true,                  /* pc_relative */
1015          0,                     /* bitpos */
1016          complain_overflow_signed, /* complain_on_overflow */
1017          0,                     /* special_function */
1018          "DISP32",              /* name */
1019          true,                  /* partial_inplace */
1020          0xffffffff,            /* src_mask */
1021          0xffffffff,            /* dst_mask */
1022          true);                 /* pcrel_offset */
1023
1024 static void
1025 i386_mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents,
1026                     contents_size)
1027      bfd *outbfd;
1028      asection *insec;
1029      arelent **relocs;
1030      bfd_size_type *reloc_count_ptr;
1031      char *contents;
1032      bfd_size_type contents_size;
1033 {
1034   bfd_size_type reloc_count, i;
1035
1036   reloc_count = *reloc_count_ptr;
1037   for (i = 0; i < reloc_count; i++)
1038     {
1039       arelent *rel;
1040       asymbol *sym;
1041       bfd_vma addend;
1042
1043       rel = *relocs++;
1044       sym = *rel->sym_ptr_ptr;
1045
1046       /* Note that no serious harm will ensue if we fail to change a
1047          reloc.  The backend will fail when writing out the reloc.  */
1048
1049       /* Make sure this reloc is within the data we have.  We use only
1050          4 byte relocs here, so we insist on having 4 bytes.  */
1051       if (rel->address + 4 > contents_size)
1052         continue;
1053
1054       /* A PC relative reloc entirely within a single section is
1055          completely unnecessary.  This can be generated by ld -r.  */
1056       if (sym == insec->symbol
1057           && rel->howto != NULL
1058           && rel->howto->pc_relative
1059           && ! rel->howto->pcrel_offset)
1060         {
1061           --*reloc_count_ptr;
1062           --relocs;
1063           memmove (relocs, relocs + 1,
1064                    (reloc_count - i) * sizeof (arelent *));
1065           continue;
1066         }
1067
1068       /* NetWare doesn't support reloc addends, so we get rid of them
1069          here by simply adding them into the object data.  We handle
1070          the symbol value, if any, the same way.  */
1071       addend = rel->addend;
1072       if (! bfd_is_com_section (bfd_get_section (sym)))
1073         addend += sym->value;
1074
1075       if (addend != 0
1076           && rel->howto != NULL
1077           && rel->howto->rightshift == 0
1078           && rel->howto->size == 2
1079           && rel->howto->bitsize == 32
1080           && rel->howto->bitpos == 0
1081           && rel->howto->src_mask == 0xffffffff
1082           && rel->howto->dst_mask == 0xffffffff)
1083         {
1084           bfd_vma val;
1085
1086           val = bfd_get_32 (outbfd, contents + rel->address);
1087           val += addend;
1088           bfd_put_32 (outbfd, val, contents + rel->address);
1089
1090           /* Adjust the reloc for the changes we just made.  */
1091           rel->addend = 0;
1092           if (! bfd_is_com_section (bfd_get_section (sym))
1093               && sym->value != 0)
1094             rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
1095         }
1096
1097       /* NetWare uses a reloc with pcrel_offset set.  We adjust
1098          pc_relative relocs accordingly.  We are going to change the
1099          howto field, so we can only do this if the current one is
1100          compatible.  We should check that special_function is NULL
1101          here, but at the moment coff-i386 uses a special_function
1102          which does not affect what we are doing here.  */
1103       if (rel->howto != NULL
1104           && rel->howto->pc_relative
1105           && ! rel->howto->pcrel_offset
1106           && rel->howto->rightshift == 0
1107           && rel->howto->size == 2
1108           && rel->howto->bitsize == 32
1109           && rel->howto->bitpos == 0
1110           && rel->howto->src_mask == 0xffffffff
1111           && rel->howto->dst_mask == 0xffffffff)
1112         {
1113           bfd_vma val;
1114
1115           /* When pcrel_offset is not set, it means that the negative
1116              of the address of the memory location is stored in the
1117              memory location.  We must add it back in.  */
1118           val = bfd_get_32 (outbfd, contents + rel->address);
1119           val += rel->address;
1120           bfd_put_32 (outbfd, val, contents + rel->address);
1121
1122           /* We must change to a new howto.  */
1123           rel->howto = &nlm_i386_pcrel_howto;
1124         }
1125     }
1126 }