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