* config/tc-mips.c (macro_build): Handle '>' case (shift amount
[deliverable/binutils-gdb.git] / binutils / nlmconv.c
CommitLineData
d92aadfd
ILT
1/* nlmconv.c -- NLM conversion program
2 Copyright (C) 1993 Free Software Foundation, Inc.
3
4This file is part of GNU Binutils.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, 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>
ef5b5368 31#include <time.h>
d92aadfd
ILT
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
46extern char *strerror ();
ef5b5368
ILT
47
48#ifndef localtime
49extern struct tm *localtime ();
50#endif
51
52#ifndef SEEK_SET
53#define SEEK_SET 0
54#endif
d92aadfd
ILT
55\f
56/* Global variables. */
57
58/* The name used to invoke the program. */
59char *program_name;
60
61/* The version number. */
62extern char *program_version;
63
ef5b5368
ILT
64/* Local variables. */
65
66/* The symbol table. */
d92aadfd
ILT
67static asymbol **symbols;
68
ef5b5368
ILT
69/* The total amount of bss space. */
70static bfd_size_type total_bss_size;
d92aadfd
ILT
71
72/* The list of long options. */
73static struct option long_options[] =
74{
75 { "header-info", required_argument, 0, 'T' },
ef5b5368 76 { "help", no_argument, 0, 'h' },
d92aadfd
ILT
77 { "input-format", required_argument, 0, 'I' },
78 { "output-format", required_argument, 0, 'O' },
ef5b5368 79 { "version", no_argument, 0, 'V' },
d92aadfd
ILT
80 { NULL, no_argument, 0, 0 }
81};
82
83/* Local routines. */
84
85static void show_help PARAMS ((void));
86static void show_usage PARAMS ((FILE *, int));
87static const char *select_output_format PARAMS ((enum bfd_architecture,
88 long, boolean));
89static void setup_sections PARAMS ((bfd *, asection *, PTR));
90static void copy_sections PARAMS ((bfd *, asection *, PTR));
ef5b5368
ILT
91static void mangle_relocs PARAMS ((bfd *, asection *, arelent **,
92 bfd_size_type *, char *,
d92aadfd 93 bfd_size_type));
ef5b5368
ILT
94static void i386_mangle_relocs PARAMS ((bfd *, asection *, arelent **,
95 bfd_size_type *, char *,
96 bfd_size_type));
d92aadfd
ILT
97\f
98/* The main routine. */
99
100int
101main (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;
ef5b5368
ILT
111 asymbol **newsyms, **outsyms;
112 unsigned int symcount, newsymalloc, newsymcount;
113 asection *bss_sec;
114 asymbol *endsym;
d92aadfd
ILT
115 unsigned int i;
116 char inlead, outlead;
117 boolean gotstart, gotexit, gotcheck;
118 struct stat st;
ef5b5368 119 FILE *custom_data, *help_data, *message_data, *rpc_data, *shared_data;
d92aadfd
ILT
120 bfd_size_type custom_size, help_size, message_size, module_size, rpc_size;
121 asection *custom_section, *help_section, *message_section, *module_section;
ef5b5368
ILT
122 asection *rpc_section, *shared_section;
123 bfd *sharedbfd;
124 bfd_size_type shared_offset, shared_size;
125 Nlm_Internal_Fixed_Header sharedhdr;
d92aadfd
ILT
126 int len;
127
128 program_name = argv[0];
129
130 bfd_init ();
131
ef5b5368 132 while ((opt = getopt_long (argc, argv, "hI:O:T:V", long_options, (int *) 0))
d92aadfd
ILT
133 != EOF)
134 {
135 switch (opt)
136 {
ef5b5368 137 case 'h':
d92aadfd
ILT
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;
ef5b5368 149 case 'V':
d92aadfd
ILT
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
ef5b5368
ILT
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
d92aadfd
ILT
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;
ef5b5368
ILT
258 newsymalloc = 10;
259 newsyms = (asymbol **) xmalloc (newsymalloc * sizeof (asymbol *));
260 newsymcount = 0;
261 endsym = NULL;
d92aadfd
ILT
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
ef5b5368
ILT
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)
d92aadfd
ILT
337 {
338 register struct string_list *l;
ef5b5368 339 int found_simple;
d92aadfd 340
ef5b5368
ILT
341 /* Unfortunately, a symbol can appear multiple times on the
342 export list, with and without prefixes. */
343 found_simple = 0;
d92aadfd
ILT
344 for (l = export_symbols; l != NULL; l = l->next)
345 {
346 if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
ef5b5368 347 found_simple = 1;
d92aadfd
ILT
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 {
ef5b5368
ILT
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;
d92aadfd
ILT
370 }
371 }
372 }
ef5b5368
ILT
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 }
d92aadfd
ILT
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
ef5b5368
ILT
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);
d92aadfd
ILT
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
d92aadfd
ILT
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 }
ef5b5368
ILT
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 }
d92aadfd
ILT
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 }
ef5b5368
ILT
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 }
d92aadfd
ILT
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
830static void
831show_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
840static void
841show_usage (file, status)
842 FILE *file;
843 int status;
844{
845 fprintf (file, "\
ef5b5368 846Usage: %s [-hV] [-I format] [-O format] [-T header-file]\n\
d92aadfd
ILT
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
857static const char *
858select_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
880static void
881setup_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;
ef5b5368 888 flagword f;
d92aadfd
ILT
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
ef5b5368
ILT
913 f = bfd_get_section_flags (inbfd, insec);
914 if (! bfd_set_section_flags (outbfd, outsec, f))
d92aadfd 915 bfd_fatal ("set section flags");
ef5b5368
ILT
916
917 if ((f & SEC_LOAD) == 0 && (f & SEC_ALLOC) != 0)
918 total_bss_size += bfd_section_size (inbfd, insec);
d92aadfd
ILT
919}
920
921/* Copy the section contents. */
922
923static void
924copy_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);
ef5b5368
ILT
966 mangle_relocs (outbfd, insec, relocs, &reloc_count, (char *) contents,
967 size);
d92aadfd
ILT
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
983static void
ef5b5368 984mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents, contents_size)
d92aadfd 985 bfd *outbfd;
ef5b5368 986 asection *insec;
d92aadfd 987 arelent **relocs;
ef5b5368 988 bfd_size_type *reloc_count_ptr;
d92aadfd
ILT
989 char *contents;
990 bfd_size_type contents_size;
991{
992 switch (bfd_get_arch (outbfd))
993 {
994 case bfd_arch_i386:
ef5b5368 995 i386_mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents,
d92aadfd
ILT
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
1009static 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
1024static void
ef5b5368
ILT
1025i386_mangle_relocs (outbfd, insec, relocs, reloc_count_ptr, contents,
1026 contents_size)
d92aadfd 1027 bfd *outbfd;
ef5b5368 1028 asection *insec;
d92aadfd 1029 arelent **relocs;
ef5b5368 1030 bfd_size_type *reloc_count_ptr;
d92aadfd
ILT
1031 char *contents;
1032 bfd_size_type contents_size;
1033{
ef5b5368
ILT
1034 bfd_size_type reloc_count, i;
1035
1036 reloc_count = *reloc_count_ptr;
1037 for (i = 0; i < reloc_count; i++)
d92aadfd
ILT
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
ef5b5368
ILT
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
d92aadfd
ILT
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}
This page took 0.072709 seconds and 4 git commands to generate.