* Many files: Added gettext invocations around user-visible
[deliverable/binutils-gdb.git] / binutils / nlmconv.c
CommitLineData
d92aadfd 1/* nlmconv.c -- NLM conversion program
9d04d618 2 Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
d92aadfd
ILT
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
1d1a5a53 18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
d92aadfd
ILT
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
1d1a5a53
ILT
25 NetWare linker, NLMLINK. */
26
27/* AIX requires this to be the first thing in the file. */
28#ifndef __GNUC__
29# ifdef _AIX
30 #pragma alloca
31#endif
32#endif
33
34#include "bfd.h"
35#include "libiberty.h"
36#include "bucomm.h"
d92aadfd
ILT
37
38#include <ansidecl.h>
ef5b5368 39#include <time.h>
90d8edfd 40#include <ctype.h>
d92aadfd 41#include <sys/stat.h>
0f6df2ee 42#include <sys/file.h>
d92aadfd
ILT
43#include <assert.h>
44#include <getopt.h>
1d1a5a53 45
d92aadfd
ILT
46/* Internal BFD NLM header. */
47#include "libnlm.h"
48#include "nlmconv.h"
49
9d11577a 50#ifdef NLMCONV_ALPHA
419093bc
ILT
51#include "coff/sym.h"
52#include "coff/ecoff.h"
9d11577a 53#endif
419093bc 54
d92aadfd
ILT
55/* If strerror is just a macro, we want to use the one from libiberty
56 since it will handle undefined values. */
57#undef strerror
58extern char *strerror ();
ef5b5368
ILT
59
60#ifndef localtime
61extern struct tm *localtime ();
62#endif
63
64#ifndef SEEK_SET
65#define SEEK_SET 0
66#endif
0f6df2ee
ILT
67
68#ifndef R_OK
69#define R_OK 4
70#define W_OK 2
71#define X_OK 1
72#endif
d92aadfd
ILT
73\f
74/* Global variables. */
75
76/* The name used to invoke the program. */
77char *program_name;
78
ef5b5368
ILT
79/* Local variables. */
80
0f6df2ee
ILT
81/* Whether to print out debugging information (currently just controls
82 whether it prints the linker command if there is one). */
83static int debug;
84
ef5b5368 85/* The symbol table. */
d92aadfd
ILT
86static asymbol **symbols;
87
dcb210cb
ILT
88/* A section we create in the output file to hold pointers to where
89 the sections of the input file end up. We will put a pointer to
90 this section in the NLM header. These is an entry for each input
91 section. The format is
92 null terminated section name
93 zeroes to adjust to 4 byte boundary
94 4 byte section data file pointer
95 4 byte section size
96 We don't need a version number. The way we find this information
97 is by finding a stamp in the NLM header information. If we need to
98 change the format of this information, we can simply change the
99 stamp. */
100static asection *secsec;
101
0f6df2ee
ILT
102/* A temporary file name to be unlinked on exit. Actually, for most
103 errors, we leave it around. It's not clear whether that is helpful
104 or not. */
105static char *unlink_on_exit;
106
d92aadfd
ILT
107/* The list of long options. */
108static struct option long_options[] =
109{
0f6df2ee 110 { "debug", no_argument, 0, 'd' },
419093bc 111 { "header-file", required_argument, 0, 'T' },
ef5b5368 112 { "help", no_argument, 0, 'h' },
e70f2bde
ILT
113 { "input-target", required_argument, 0, 'I' },
114 { "input-format", required_argument, 0, 'I' }, /* Obsolete */
0f6df2ee 115 { "linker", required_argument, 0, 'l' },
e70f2bde
ILT
116 { "output-target", required_argument, 0, 'O' },
117 { "output-format", required_argument, 0, 'O' }, /* Obsolete */
ef5b5368 118 { "version", no_argument, 0, 'V' },
d92aadfd
ILT
119 { NULL, no_argument, 0, 0 }
120};
121
122/* Local routines. */
123
124static void show_help PARAMS ((void));
125static void show_usage PARAMS ((FILE *, int));
126static const char *select_output_format PARAMS ((enum bfd_architecture,
419093bc 127 unsigned long, boolean));
d92aadfd
ILT
128static void setup_sections PARAMS ((bfd *, asection *, PTR));
129static void copy_sections PARAMS ((bfd *, asection *, PTR));
419093bc 130static void mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
ae5d2ff5 131 long *, char *,
d92aadfd 132 bfd_size_type));
9d11577a
ILT
133static void default_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
134 long *, char *,
135 bfd_size_type));
136static char *link_inputs PARAMS ((struct string_list *, char *));
9d11577a
ILT
137
138#ifdef NLMCONV_I386
419093bc 139static void i386_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
ae5d2ff5 140 long *, char *,
a30f59a4 141 bfd_size_type));
9d11577a
ILT
142#endif
143
144#ifdef NLMCONV_ALPHA
419093bc 145static void alpha_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
ae5d2ff5 146 long *, char *,
419093bc 147 bfd_size_type));
9d11577a
ILT
148#endif
149
150#ifdef NLMCONV_POWERPC
c59fa195 151static void powerpc_build_stubs PARAMS ((bfd *, bfd *, asymbol ***, long *));
4bd7a65f
ILT
152static void powerpc_resolve_stubs PARAMS ((bfd *, bfd *));
153static void powerpc_mangle_relocs PARAMS ((bfd *, asection *, arelent ***,
ae5d2ff5 154 long *, char *,
4bd7a65f 155 bfd_size_type));
9d11577a 156#endif
d92aadfd
ILT
157\f
158/* The main routine. */
159
160int
161main (argc, argv)
162 int argc;
163 char **argv;
164{
165 int opt;
0f6df2ee 166 char *input_file = NULL;
d92aadfd
ILT
167 const char *input_format = NULL;
168 const char *output_format = NULL;
169 const char *header_file = NULL;
0f6df2ee
ILT
170 char *ld_arg = NULL;
171 Nlm_Internal_Fixed_Header fixed_hdr_struct;
172 Nlm_Internal_Variable_Header var_hdr_struct;
173 Nlm_Internal_Version_Header version_hdr_struct;
174 Nlm_Internal_Copyright_Header copyright_hdr_struct;
175 Nlm_Internal_Extended_Header extended_hdr_struct;
d92aadfd
ILT
176 bfd *inbfd;
177 bfd *outbfd;
ef5b5368 178 asymbol **newsyms, **outsyms;
ae5d2ff5
ILT
179 long symcount, newsymalloc, newsymcount;
180 long symsize;
4bd7a65f 181 asection *text_sec, *bss_sec, *data_sec;
90d8edfd
ILT
182 bfd_vma vma;
183 bfd_size_type align;
ef5b5368 184 asymbol *endsym;
ae5d2ff5 185 long i;
d92aadfd
ILT
186 char inlead, outlead;
187 boolean gotstart, gotexit, gotcheck;
188 struct stat st;
9d04d618
TT
189 FILE *custom_data = NULL;
190 FILE *help_data = NULL;
191 FILE *message_data = NULL;
192 FILE *rpc_data = NULL;
193 FILE *shared_data = NULL;
194 size_t custom_size = 0;
195 size_t help_size = 0;
196 size_t message_size = 0;
197 size_t module_size = 0;
198 size_t rpc_size = 0;
199 asection *custom_section = NULL;
200 asection *help_section = NULL;
201 asection *message_section = NULL;
202 asection *module_section = NULL;
203 asection *rpc_section = NULL;
204 asection *shared_section = NULL;
ef5b5368 205 bfd *sharedbfd;
9d04d618
TT
206 size_t shared_offset = 0;
207 size_t shared_size = 0;
ef5b5368 208 Nlm_Internal_Fixed_Header sharedhdr;
d92aadfd 209 int len;
90d8edfd 210 char *modname;
cef35d48 211 char **matching;
d92aadfd
ILT
212
213 program_name = argv[0];
7681bc7b 214 xmalloc_set_program_name (program_name);
d92aadfd
ILT
215
216 bfd_init ();
1d1a5a53 217 set_default_bfd_target ();
d92aadfd 218
0f6df2ee
ILT
219 while ((opt = getopt_long (argc, argv, "dhI:l:O:T:V", long_options,
220 (int *) NULL))
d92aadfd
ILT
221 != EOF)
222 {
223 switch (opt)
224 {
0f6df2ee
ILT
225 case 'd':
226 debug = 1;
227 break;
ef5b5368 228 case 'h':
d92aadfd
ILT
229 show_help ();
230 /*NOTREACHED*/
231 case 'I':
232 input_format = optarg;
233 break;
0f6df2ee
ILT
234 case 'l':
235 ld_arg = optarg;
236 break;
d92aadfd
ILT
237 case 'O':
238 output_format = optarg;
239 break;
240 case 'T':
241 header_file = optarg;
242 break;
ef5b5368 243 case 'V':
1d1a5a53 244 print_version ("nlmconv");
d92aadfd
ILT
245 /*NOTREACHED*/
246 case 0:
247 break;
248 default:
249 show_usage (stderr, 1);
250 /*NOTREACHED*/
251 }
252 }
253
0f6df2ee
ILT
254 /* The input and output files may be named on the command line. */
255 output_file = NULL;
256 if (optind < argc)
d92aadfd 257 {
0f6df2ee
ILT
258 input_file = argv[optind];
259 ++optind;
260 if (optind < argc)
261 {
262 output_file = argv[optind];
263 ++optind;
264 if (optind < argc)
265 show_usage (stderr, 1);
266 if (strcmp (input_file, output_file) == 0)
267 {
268 fprintf (stderr,
9d04d618 269 _("%s: input and output files must be different\n"),
0f6df2ee
ILT
270 program_name);
271 exit (1);
272 }
273 }
d92aadfd
ILT
274 }
275
d92aadfd 276 /* Initialize the header information to default values. */
0f6df2ee
ILT
277 fixed_hdr = &fixed_hdr_struct;
278 memset ((PTR) &fixed_hdr_struct, 0, sizeof fixed_hdr_struct);
279 var_hdr = &var_hdr_struct;
280 memset ((PTR) &var_hdr_struct, 0, sizeof var_hdr_struct);
281 version_hdr = &version_hdr_struct;
282 memset ((PTR) &version_hdr_struct, 0, sizeof version_hdr_struct);
283 copyright_hdr = &copyright_hdr_struct;
284 memset ((PTR) &copyright_hdr_struct, 0, sizeof copyright_hdr_struct);
285 extended_hdr = &extended_hdr_struct;
286 memset ((PTR) &extended_hdr_struct, 0, sizeof extended_hdr_struct);
d92aadfd
ILT
287 check_procedure = NULL;
288 custom_file = NULL;
289 debug_info = false;
290 exit_procedure = "_Stop";
291 export_symbols = NULL;
292 map_file = NULL;
293 full_map = false;
294 help_file = NULL;
295 import_symbols = NULL;
296 message_file = NULL;
297 modules = NULL;
298 sharelib_file = NULL;
299 start_procedure = "_Prelude";
300 verbose = false;
301 rpc_file = NULL;
302
303 parse_errors = 0;
304
305 /* Parse the header file (if there is one). */
306 if (header_file != NULL)
307 {
308 if (! nlmlex_file (header_file)
309 || yyparse () != 0
310 || parse_errors != 0)
311 exit (1);
312 }
313
0f6df2ee
ILT
314 if (input_files != NULL)
315 {
316 if (input_file != NULL)
317 {
318 fprintf (stderr,
9d04d618 319 _("%s: input file named both on command line and with INPUT\n"),
0f6df2ee
ILT
320 program_name);
321 exit (1);
322 }
323 if (input_files->next == NULL)
324 input_file = input_files->string;
325 else
326 input_file = link_inputs (input_files, ld_arg);
327 }
328 else if (input_file == NULL)
329 {
9d04d618 330 fprintf (stderr, _("%s: no input file\n"), program_name);
0f6df2ee
ILT
331 show_usage (stderr, 1);
332 }
333
334 inbfd = bfd_openr (input_file, input_format);
335 if (inbfd == NULL)
336 bfd_fatal (input_file);
337
cef35d48
DM
338 if (! bfd_check_format_matches (inbfd, bfd_object, &matching))
339 {
340 bfd_nonfatal (input_file);
7681bc7b 341 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
cef35d48
DM
342 {
343 list_matching_formats (matching);
344 free (matching);
345 }
346 exit (1);
347 }
0f6df2ee
ILT
348
349 if (output_format == NULL)
350 output_format = select_output_format (bfd_get_arch (inbfd),
351 bfd_get_mach (inbfd),
1d1a5a53 352 bfd_big_endian (inbfd));
0f6df2ee
ILT
353
354 assert (output_format != NULL);
355
356 /* Use the output file named on the command line if it exists.
357 Otherwise use the file named in the OUTPUT statement. */
358 if (output_file == NULL)
359 {
9d04d618 360 fprintf (stderr, _("%s: no name for output file\n"),
0f6df2ee
ILT
361 program_name);
362 show_usage (stderr, 1);
363 }
364
365 outbfd = bfd_openw (output_file, output_format);
366 if (outbfd == NULL)
367 bfd_fatal (output_file);
368 if (! bfd_set_format (outbfd, bfd_object))
369 bfd_fatal (output_file);
370
0c5dc23c 371 assert (bfd_get_flavour (outbfd) == bfd_target_nlm_flavour);
0f6df2ee
ILT
372
373 if (bfd_arch_get_compatible (inbfd, outbfd) == NULL)
374 fprintf (stderr,
9d04d618 375 _("%s: warning:input and output formats are not compatible\n"),
0f6df2ee
ILT
376 program_name);
377
378 /* Move the values read from the command file into outbfd. */
379 *nlm_fixed_header (outbfd) = fixed_hdr_struct;
380 *nlm_variable_header (outbfd) = var_hdr_struct;
381 *nlm_version_header (outbfd) = version_hdr_struct;
382 *nlm_copyright_header (outbfd) = copyright_hdr_struct;
383 *nlm_extended_header (outbfd) = extended_hdr_struct;
384
d92aadfd
ILT
385 /* Start copying the input BFD to the output BFD. */
386 if (! bfd_set_file_flags (outbfd, bfd_get_file_flags (inbfd)))
387 bfd_fatal (bfd_get_filename (outbfd));
388
ae5d2ff5
ILT
389 symsize = bfd_get_symtab_upper_bound (inbfd);
390 if (symsize < 0)
391 bfd_fatal (input_file);
392 symbols = (asymbol **) xmalloc (symsize);
d92aadfd 393 symcount = bfd_canonicalize_symtab (inbfd, symbols);
ae5d2ff5
ILT
394 if (symcount < 0)
395 bfd_fatal (input_file);
d92aadfd 396
90d8edfd 397 /* Make sure we have a .bss section. */
ef5b5368
ILT
398 bss_sec = bfd_get_section_by_name (outbfd, NLM_UNINITIALIZED_DATA_NAME);
399 if (bss_sec == NULL)
400 {
401 bss_sec = bfd_make_section (outbfd, NLM_UNINITIALIZED_DATA_NAME);
90d8edfd
ILT
402 if (bss_sec == NULL
403 || ! bfd_set_section_flags (outbfd, bss_sec, SEC_ALLOC)
404 || ! bfd_set_section_alignment (outbfd, bss_sec, 1))
9d04d618 405 bfd_fatal (_("make .bss section"));
ef5b5368 406 }
dcb210cb
ILT
407
408 /* We store the original section names in the .nlmsections section,
409 so that programs which understand it can resurrect the original
410 sections from the NLM. We will put a pointer to .nlmsections in
411 the NLM header area. */
412 secsec = bfd_make_section (outbfd, ".nlmsections");
413 if (secsec == NULL)
9d04d618 414 bfd_fatal (_("make .nlmsections section"));
dcb210cb 415 if (! bfd_set_section_flags (outbfd, secsec, SEC_HAS_CONTENTS))
9d04d618 416 bfd_fatal (_("set .nlmsections flags"));
4bd7a65f 417
9d11577a 418#ifdef NLMCONV_POWERPC
4bd7a65f
ILT
419 /* For PowerPC NetWare we need to build stubs for calls to undefined
420 symbols. Because each stub requires an entry in the TOC section
421 which must be at the same location as other entries in the TOC
422 section, we must do this before determining where the TOC section
423 goes in setup_sections. */
03975925 424 if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
c59fa195 425 powerpc_build_stubs (inbfd, outbfd, &symbols, &symcount);
9d11577a 426#endif
ef5b5368
ILT
427
428 /* Set up the sections. */
429 bfd_map_over_sections (inbfd, setup_sections, (PTR) outbfd);
430
4bd7a65f
ILT
431 text_sec = bfd_get_section_by_name (outbfd, NLM_CODE_NAME);
432
90d8edfd
ILT
433 /* The .bss section immediately follows the .data section. */
434 data_sec = bfd_get_section_by_name (outbfd, NLM_INITIALIZED_DATA_NAME);
435 if (data_sec != NULL)
436 {
437 bfd_size_type add;
438
439 vma = bfd_get_section_size_before_reloc (data_sec);
440 align = 1 << bss_sec->alignment_power;
441 add = ((vma + align - 1) &~ (align - 1)) - vma;
442 vma += add;
443 if (! bfd_set_section_vma (outbfd, bss_sec, vma))
9d04d618 444 bfd_fatal (_("set .bss vma"));
90d8edfd
ILT
445 if (add != 0)
446 {
447 bfd_size_type data_size;
448
449 data_size = bfd_get_section_size_before_reloc (data_sec);
450 if (! bfd_set_section_size (outbfd, data_sec, data_size + add))
9d04d618 451 bfd_fatal (_("set .data size"));
90d8edfd
ILT
452 }
453 }
454
d92aadfd
ILT
455 /* Adjust symbol information. */
456 inlead = bfd_get_symbol_leading_char (inbfd);
457 outlead = bfd_get_symbol_leading_char (outbfd);
458 gotstart = false;
459 gotexit = false;
460 gotcheck = false;
ef5b5368
ILT
461 newsymalloc = 10;
462 newsyms = (asymbol **) xmalloc (newsymalloc * sizeof (asymbol *));
463 newsymcount = 0;
464 endsym = NULL;
d92aadfd
ILT
465 for (i = 0; i < symcount; i++)
466 {
467 register asymbol *sym;
468
469 sym = symbols[i];
470
471 /* Add or remove a leading underscore. */
472 if (inlead != outlead)
473 {
474 if (inlead != '\0')
475 {
476 if (bfd_asymbol_name (sym)[0] == inlead)
477 {
478 if (outlead == '\0')
479 ++sym->name;
480 else
481 {
482 char *new;
483
484 new = xmalloc (strlen (bfd_asymbol_name (sym)) + 1);
485 new[0] = outlead;
486 strcpy (new + 1, bfd_asymbol_name (sym) + 1);
487 sym->name = new;
488 }
489 }
490 }
491 else
492 {
493 char *new;
494
495 new = xmalloc (strlen (bfd_asymbol_name (sym)) + 2);
496 new[0] = outlead;
497 strcpy (new + 1, bfd_asymbol_name (sym));
498 sym->name = new;
499 }
500 }
501
ef5b5368
ILT
502 /* NLM's have an uninitialized data section, but they do not
503 have a common section in the Unix sense. Move all common
504 symbols into the .bss section, and mark them as exported. */
505 if (bfd_is_com_section (bfd_get_section (sym)))
506 {
507 bfd_vma size;
ef5b5368
ILT
508
509 sym->section = bss_sec;
510 size = sym->value;
511 sym->value = bss_sec->_raw_size;
512 bss_sec->_raw_size += size;
513 align = 1 << bss_sec->alignment_power;
514 bss_sec->_raw_size = (bss_sec->_raw_size + align - 1) &~ (align - 1);
ef5b5368
ILT
515 sym->flags |= BSF_EXPORT | BSF_GLOBAL;
516 }
90d8edfd
ILT
517 else if (bfd_get_section (sym)->output_section != NULL)
518 {
519 /* Move the symbol into the output section. */
520 sym->value += bfd_get_section (sym)->output_offset;
521 sym->section = bfd_get_section (sym)->output_section;
522 /* This is no longer a section symbol. */
523 sym->flags &=~ BSF_SECTION_SYM;
524 }
ef5b5368
ILT
525
526 /* Force _edata and _end to be defined. This would normally be
527 done by the linker, but the manipulation of the common
528 symbols will confuse it. */
4bd7a65f
ILT
529 if ((sym->flags & BSF_DEBUGGING) == 0
530 && bfd_asymbol_name (sym)[0] == '_'
a18ff4a7 531 && bfd_is_und_section (bfd_get_section (sym)))
ef5b5368
ILT
532 {
533 if (strcmp (bfd_asymbol_name (sym), "_edata") == 0)
534 {
535 sym->section = bss_sec;
536 sym->value = 0;
537 }
538 if (strcmp (bfd_asymbol_name (sym), "_end") == 0)
539 {
540 sym->section = bss_sec;
541 endsym = sym;
542 }
d5e29b60 543
9d11577a 544#ifdef NLMCONV_POWERPC
4bd7a65f
ILT
545 /* For PowerPC NetWare, we define __GOT0. This is the start
546 of the .got section. */
547 if (bfd_get_arch (inbfd) == bfd_arch_powerpc
548 && strcmp (bfd_asymbol_name (sym), "__GOT0") == 0)
549 {
550 asection *got_sec;
551
552 got_sec = bfd_get_section_by_name (inbfd, ".got");
553 assert (got_sec != (asection *) NULL);
554 sym->value = got_sec->output_offset;
555 sym->section = got_sec->output_section;
556 }
9d11577a 557#endif
4bd7a65f 558 }
ef5b5368
ILT
559
560 /* If this is a global symbol, check the export list. */
561 if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) != 0)
d92aadfd
ILT
562 {
563 register struct string_list *l;
ef5b5368 564 int found_simple;
d92aadfd 565
ef5b5368
ILT
566 /* Unfortunately, a symbol can appear multiple times on the
567 export list, with and without prefixes. */
568 found_simple = 0;
d92aadfd
ILT
569 for (l = export_symbols; l != NULL; l = l->next)
570 {
571 if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
ef5b5368 572 found_simple = 1;
d92aadfd
ILT
573 else
574 {
575 char *zbase;
576
577 zbase = strchr (l->string, '@');
578 if (zbase != NULL
579 && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
580 {
ef5b5368
ILT
581 /* We must add a symbol with this prefix. */
582 if (newsymcount >= newsymalloc)
583 {
584 newsymalloc += 10;
585 newsyms = ((asymbol **)
cef35d48 586 xrealloc ((PTR) newsyms,
ef5b5368
ILT
587 (newsymalloc
588 * sizeof (asymbol *))));
589 }
590 newsyms[newsymcount] =
591 (asymbol *) xmalloc (sizeof (asymbol));
592 *newsyms[newsymcount] = *sym;
593 newsyms[newsymcount]->name = l->string;
594 ++newsymcount;
d92aadfd
ILT
595 }
596 }
597 }
ef5b5368
ILT
598 if (! found_simple)
599 {
600 /* The unmodified symbol is actually not exported at
601 all. */
602 sym->flags &=~ (BSF_GLOBAL | BSF_EXPORT);
603 sym->flags |= BSF_LOCAL;
604 }
d92aadfd
ILT
605 }
606
607 /* If it's an undefined symbol, see if it's on the import list.
608 Change the prefix if necessary. */
a18ff4a7 609 if (bfd_is_und_section (bfd_get_section (sym)))
d92aadfd
ILT
610 {
611 register struct string_list *l;
612
613 for (l = import_symbols; l != NULL; l = l->next)
614 {
615 if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
616 break;
617 else
618 {
619 char *zbase;
620
621 zbase = strchr (l->string, '@');
622 if (zbase != NULL
623 && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
624 {
625 sym->name = l->string;
626 break;
627 }
628 }
629 }
630 if (l == NULL)
631 fprintf (stderr,
9d04d618 632 _("%s: warning: symbol %s imported but not in import list\n"),
d92aadfd
ILT
633 program_name, bfd_asymbol_name (sym));
634 }
635
636 /* See if it's one of the special named symbols. */
4bd7a65f 637 if ((sym->flags & BSF_DEBUGGING) == 0)
d92aadfd 638 {
4bd7a65f
ILT
639 bfd_vma val;
640
641 /* FIXME: If these symbols are not in the .text section, we
642 add the .text section size to the value. This may not be
643 correct for all targets. I'm not sure how this should
644 really be handled. */
645 if (strcmp (bfd_asymbol_name (sym), start_procedure) == 0)
646 {
647 val = bfd_asymbol_value (sym);
648 if (bfd_get_section (sym) == data_sec
649 && text_sec != (asection *) NULL)
650 val += bfd_section_size (outbfd, text_sec);
651 if (! bfd_set_start_address (outbfd, val))
9d04d618 652 bfd_fatal (_("set start address"));
4bd7a65f
ILT
653 gotstart = true;
654 }
655 if (strcmp (bfd_asymbol_name (sym), exit_procedure) == 0)
656 {
657 val = bfd_asymbol_value (sym);
658 if (bfd_get_section (sym) == data_sec
659 && text_sec != (asection *) NULL)
660 val += bfd_section_size (outbfd, text_sec);
661 nlm_fixed_header (outbfd)->exitProcedureOffset = val;
662 gotexit = true;
663 }
664 if (check_procedure != NULL
665 && strcmp (bfd_asymbol_name (sym), check_procedure) == 0)
666 {
667 val = bfd_asymbol_value (sym);
668 if (bfd_get_section (sym) == data_sec
669 && text_sec != (asection *) NULL)
670 val += bfd_section_size (outbfd, text_sec);
671 nlm_fixed_header (outbfd)->checkUnloadProcedureOffset = val;
672 gotcheck = true;
673 }
d92aadfd
ILT
674 }
675 }
676
ef5b5368 677 if (endsym != NULL)
4bd7a65f
ILT
678 {
679 endsym->value = bfd_get_section_size_before_reloc (bss_sec);
680
681 /* FIXME: If any relocs referring to _end use inplace addends,
682 then I think they need to be updated. This is handled by
683 i386_mangle_relocs. Is it needed for any other object
684 formats? */
685 }
ef5b5368
ILT
686
687 if (newsymcount == 0)
688 outsyms = symbols;
689 else
690 {
691 outsyms = (asymbol **) xmalloc ((symcount + newsymcount + 1)
692 * sizeof (asymbol *));
693 memcpy (outsyms, symbols, symcount * sizeof (asymbol *));
694 memcpy (outsyms + symcount, newsyms, newsymcount * sizeof (asymbol *));
695 outsyms[symcount + newsymcount] = NULL;
696 }
697
698 bfd_set_symtab (outbfd, outsyms, symcount + newsymcount);
d92aadfd
ILT
699
700 if (! gotstart)
9d04d618 701 fprintf (stderr, _("%s: warning: START procedure %s not defined\n"),
d92aadfd
ILT
702 program_name, start_procedure);
703 if (! gotexit)
9d04d618 704 fprintf (stderr, _("%s: warning: EXIT procedure %s not defined\n"),
d92aadfd
ILT
705 program_name, exit_procedure);
706 if (check_procedure != NULL
707 && ! gotcheck)
9d04d618 708 fprintf (stderr, _("%s: warning: CHECK procedure %s not defined\n"),
d92aadfd
ILT
709 program_name, check_procedure);
710
d92aadfd
ILT
711 /* Add additional sections required for the header information. */
712 if (custom_file != NULL)
713 {
714 custom_data = fopen (custom_file, "r");
715 if (custom_data == NULL
716 || fstat (fileno (custom_data), &st) < 0)
717 {
718 fprintf (stderr, "%s:%s: %s\n", program_name, custom_file,
719 strerror (errno));
720 custom_file = NULL;
721 }
722 else
723 {
724 custom_size = st.st_size;
725 custom_section = bfd_make_section (outbfd, ".nlmcustom");
726 if (custom_section == NULL
727 || ! bfd_set_section_size (outbfd, custom_section, custom_size)
728 || ! bfd_set_section_flags (outbfd, custom_section,
729 SEC_HAS_CONTENTS))
9d04d618 730 bfd_fatal (_("custom section"));
d92aadfd
ILT
731 }
732 }
733 if (help_file != NULL)
734 {
735 help_data = fopen (help_file, "r");
736 if (help_data == NULL
737 || fstat (fileno (help_data), &st) < 0)
738 {
739 fprintf (stderr, "%s:%s: %s\n", program_name, help_file,
740 strerror (errno));
741 help_file = NULL;
742 }
743 else
744 {
745 help_size = st.st_size;
746 help_section = bfd_make_section (outbfd, ".nlmhelp");
747 if (help_section == NULL
748 || ! bfd_set_section_size (outbfd, help_section, help_size)
749 || ! bfd_set_section_flags (outbfd, help_section,
750 SEC_HAS_CONTENTS))
9d04d618 751 bfd_fatal (_("help section"));
d92aadfd
ILT
752 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
753 }
754 }
755 if (message_file != NULL)
756 {
757 message_data = fopen (message_file, "r");
758 if (message_data == NULL
759 || fstat (fileno (message_data), &st) < 0)
760 {
761 fprintf (stderr, "%s:%s: %s\n", program_name, message_file,
762 strerror (errno));
763 message_file = NULL;
764 }
765 else
766 {
767 message_size = st.st_size;
768 message_section = bfd_make_section (outbfd, ".nlmmessages");
769 if (message_section == NULL
770 || ! bfd_set_section_size (outbfd, message_section, message_size)
771 || ! bfd_set_section_flags (outbfd, message_section,
772 SEC_HAS_CONTENTS))
9d04d618 773 bfd_fatal (_("message section"));
d92aadfd
ILT
774 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
775 }
776 }
777 if (modules != NULL)
778 {
779 struct string_list *l;
780
781 module_size = 0;
782 for (l = modules; l != NULL; l = l->next)
783 module_size += strlen (l->string) + 1;
784 module_section = bfd_make_section (outbfd, ".nlmmodules");
785 if (module_section == NULL
786 || ! bfd_set_section_size (outbfd, module_section, module_size)
787 || ! bfd_set_section_flags (outbfd, module_section,
788 SEC_HAS_CONTENTS))
9d04d618 789 bfd_fatal (_("module section"));
d92aadfd
ILT
790 }
791 if (rpc_file != NULL)
792 {
793 rpc_data = fopen (rpc_file, "r");
794 if (rpc_data == NULL
795 || fstat (fileno (rpc_data), &st) < 0)
796 {
797 fprintf (stderr, "%s:%s: %s\n", program_name, rpc_file,
798 strerror (errno));
799 rpc_file = NULL;
800 }
801 else
802 {
803 rpc_size = st.st_size;
804 rpc_section = bfd_make_section (outbfd, ".nlmrpc");
805 if (rpc_section == NULL
806 || ! bfd_set_section_size (outbfd, rpc_section, rpc_size)
807 || ! bfd_set_section_flags (outbfd, rpc_section,
808 SEC_HAS_CONTENTS))
9d04d618 809 bfd_fatal (_("rpc section"));
d92aadfd
ILT
810 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
811 }
812 }
ef5b5368
ILT
813 if (sharelib_file != NULL)
814 {
815 sharedbfd = bfd_openr (sharelib_file, output_format);
816 if (sharedbfd == NULL
817 || ! bfd_check_format (sharedbfd, bfd_object))
818 {
819 fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
7681bc7b 820 bfd_errmsg (bfd_get_error ()));
ef5b5368
ILT
821 sharelib_file = NULL;
822 }
823 else
824 {
825 sharedhdr = *nlm_fixed_header (sharedbfd);
826 bfd_close (sharedbfd);
827 shared_data = fopen (sharelib_file, "r");
828 if (shared_data == NULL
829 || (fstat (fileno (shared_data), &st) < 0))
830 {
831 fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
832 strerror (errno));
833 sharelib_file = NULL;
834 }
835 else
836 {
837 /* If we were clever, we could just copy out the
838 sections of the shared library which we actually
839 need. However, we would have to figure out the sizes
840 of the external and public information, and that can
841 not be done without reading through them. */
1edb7335
ILT
842 if (sharedhdr.uninitializedDataSize > 0)
843 {
844 /* There is no place to record this information. */
845 fprintf (stderr,
9d04d618 846 _("%s:%s: warning: shared libraries can not have uninitialized data\n"),
1edb7335
ILT
847 program_name, sharelib_file);
848 }
ef5b5368 849 shared_offset = st.st_size;
9d04d618 850 if (shared_offset > (size_t) sharedhdr.codeImageOffset)
ef5b5368 851 shared_offset = sharedhdr.codeImageOffset;
9d04d618 852 if (shared_offset > (size_t) sharedhdr.dataImageOffset)
ef5b5368 853 shared_offset = sharedhdr.dataImageOffset;
9d04d618 854 if (shared_offset > (size_t) sharedhdr.relocationFixupOffset)
ef5b5368 855 shared_offset = sharedhdr.relocationFixupOffset;
9d04d618 856 if (shared_offset > (size_t) sharedhdr.externalReferencesOffset)
ef5b5368 857 shared_offset = sharedhdr.externalReferencesOffset;
9d04d618 858 if (shared_offset > (size_t) sharedhdr.publicsOffset)
ef5b5368
ILT
859 shared_offset = sharedhdr.publicsOffset;
860 shared_size = st.st_size - shared_offset;
861 shared_section = bfd_make_section (outbfd, ".nlmshared");
862 if (shared_section == NULL
863 || ! bfd_set_section_size (outbfd, shared_section,
864 shared_size)
865 || ! bfd_set_section_flags (outbfd, shared_section,
866 SEC_HAS_CONTENTS))
9d04d618 867 bfd_fatal (_("shared section"));
ef5b5368
ILT
868 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
869 }
870 }
871 }
872
873 /* Check whether a version was given. */
874 if (strncmp (version_hdr->stamp, "VeRsIoN#", 8) != 0)
9d04d618 875 fprintf (stderr, _("%s: warning: No version number given\n"),
ef5b5368
ILT
876 program_name);
877
878 /* At least for now, always create an extended header, because that
879 is what NLMLINK does. */
880 strncpy (nlm_extended_header (outbfd)->stamp, "MeSsAgEs", 8);
881
162794fe 882 strncpy (nlm_cygnus_ext_header (outbfd)->stamp, "CyGnUsEx", 8);
dcb210cb 883
ef5b5368
ILT
884 /* If the date was not given, force it in. */
885 if (nlm_version_header (outbfd)->month == 0
886 && nlm_version_header (outbfd)->day == 0
887 && nlm_version_header (outbfd)->year == 0)
888 {
90d8edfd 889 time_t now;
ef5b5368
ILT
890 struct tm *ptm;
891
892 time (&now);
893 ptm = localtime (&now);
894 nlm_version_header (outbfd)->month = ptm->tm_mon + 1;
895 nlm_version_header (outbfd)->day = ptm->tm_mday;
896 nlm_version_header (outbfd)->year = ptm->tm_year + 1900;
897 strncpy (version_hdr->stamp, "VeRsIoN#", 8);
898 }
4bd7a65f 899
9d11577a 900#ifdef NLMCONV_POWERPC
4bd7a65f 901 /* Resolve the stubs we build for PowerPC NetWare. */
03975925
ILT
902 if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
903 powerpc_resolve_stubs (inbfd, outbfd);
9d11577a 904#endif
d92aadfd
ILT
905
906 /* Copy over the sections. */
907 bfd_map_over_sections (inbfd, copy_sections, (PTR) outbfd);
908
909 /* Finish up the header information. */
910 if (custom_file != NULL)
911 {
912 PTR data;
913
914 data = xmalloc (custom_size);
915 if (fread (data, 1, custom_size, custom_data) != custom_size)
9d04d618 916 fprintf (stderr, _("%s:%s: read: %s\n"), program_name, custom_file,
d92aadfd
ILT
917 strerror (errno));
918 else
919 {
920 if (! bfd_set_section_contents (outbfd, custom_section, data,
921 (file_ptr) 0, custom_size))
9d04d618 922 bfd_fatal (_("custom section"));
d92aadfd
ILT
923 nlm_fixed_header (outbfd)->customDataOffset =
924 custom_section->filepos;
925 nlm_fixed_header (outbfd)->customDataSize = custom_size;
926 }
927 free (data);
928 }
929 if (! debug_info)
930 {
931 /* As a special hack, the backend recognizes a debugInfoOffset
932 of -1 to mean that it should not output any debugging
933 information. This can not be handling by fiddling with the
934 symbol table because exported symbols appear in both the
935 export information and the debugging information. */
936 nlm_fixed_header (outbfd)->debugInfoOffset = (file_ptr) -1;
937 }
938 if (map_file != NULL)
939 fprintf (stderr,
9d04d618 940 _("%s: warning: MAP and FULLMAP are not supported; try ld -M\n"),
d92aadfd
ILT
941 program_name);
942 if (help_file != NULL)
943 {
944 PTR data;
945
946 data = xmalloc (help_size);
947 if (fread (data, 1, help_size, help_data) != help_size)
9d04d618 948 fprintf (stderr, _("%s:%s: read: %s\n"), program_name, help_file,
d92aadfd
ILT
949 strerror (errno));
950 else
951 {
952 if (! bfd_set_section_contents (outbfd, help_section, data,
953 (file_ptr) 0, help_size))
9d04d618 954 bfd_fatal (_("help section"));
d92aadfd
ILT
955 nlm_extended_header (outbfd)->helpFileOffset =
956 help_section->filepos;
957 nlm_extended_header (outbfd)->helpFileLength = help_size;
958 }
959 free (data);
960 }
961 if (message_file != NULL)
962 {
963 PTR data;
964
965 data = xmalloc (message_size);
966 if (fread (data, 1, message_size, message_data) != message_size)
9d04d618 967 fprintf (stderr, _("%s:%s: read: %s\n"), program_name, message_file,
d92aadfd
ILT
968 strerror (errno));
969 else
970 {
971 if (! bfd_set_section_contents (outbfd, message_section, data,
972 (file_ptr) 0, message_size))
9d04d618 973 bfd_fatal (_("message section"));
d92aadfd
ILT
974 nlm_extended_header (outbfd)->messageFileOffset =
975 message_section->filepos;
976 nlm_extended_header (outbfd)->messageFileLength = message_size;
977
978 /* FIXME: Are these offsets correct on all platforms? Are
979 they 32 bits on all platforms? What endianness? */
980 nlm_extended_header (outbfd)->languageID =
981 bfd_h_get_32 (outbfd, (bfd_byte *) data + 106);
982 nlm_extended_header (outbfd)->messageCount =
983 bfd_h_get_32 (outbfd, (bfd_byte *) data + 110);
984 }
985 free (data);
986 }
987 if (modules != NULL)
988 {
989 PTR data;
419093bc 990 unsigned char *set;
d92aadfd
ILT
991 struct string_list *l;
992 bfd_size_type c;
993
994 data = xmalloc (module_size);
995 c = 0;
419093bc 996 set = (unsigned char *) data;
d92aadfd
ILT
997 for (l = modules; l != NULL; l = l->next)
998 {
999 *set = strlen (l->string);
1000 strncpy (set + 1, l->string, *set);
1001 set += *set + 1;
1002 ++c;
1003 }
1004 if (! bfd_set_section_contents (outbfd, module_section, data,
1005 (file_ptr) 0, module_size))
9d04d618 1006 bfd_fatal (_("module section"));
d92aadfd
ILT
1007 nlm_fixed_header (outbfd)->moduleDependencyOffset =
1008 module_section->filepos;
1009 nlm_fixed_header (outbfd)->numberOfModuleDependencies = c;
1010 }
1011 if (rpc_file != NULL)
1012 {
1013 PTR data;
1014
1015 data = xmalloc (rpc_size);
1016 if (fread (data, 1, rpc_size, rpc_data) != rpc_size)
9d04d618 1017 fprintf (stderr, _("%s:%s: read: %s\n"), program_name, rpc_file,
d92aadfd
ILT
1018 strerror (errno));
1019 else
1020 {
1021 if (! bfd_set_section_contents (outbfd, rpc_section, data,
1022 (file_ptr) 0, rpc_size))
9d04d618 1023 bfd_fatal (_("rpc section"));
d92aadfd
ILT
1024 nlm_extended_header (outbfd)->RPCDataOffset =
1025 rpc_section->filepos;
1026 nlm_extended_header (outbfd)->RPCDataLength = rpc_size;
1027 }
1028 free (data);
1029 }
ef5b5368
ILT
1030 if (sharelib_file != NULL)
1031 {
1032 PTR data;
1033
1034 data = xmalloc (shared_size);
1035 if (fseek (shared_data, shared_offset, SEEK_SET) != 0
1036 || fread (data, 1, shared_size, shared_data) != shared_size)
9d04d618 1037 fprintf (stderr, _("%s:%s: read: %s\n"), program_name, sharelib_file,
ef5b5368
ILT
1038 strerror (errno));
1039 else
1040 {
1041 if (! bfd_set_section_contents (outbfd, shared_section, data,
1042 (file_ptr) 0, shared_size))
9d04d618 1043 bfd_fatal (_("shared section"));
ef5b5368
ILT
1044 }
1045 nlm_extended_header (outbfd)->sharedCodeOffset =
1046 sharedhdr.codeImageOffset - shared_offset + shared_section->filepos;
1047 nlm_extended_header (outbfd)->sharedCodeLength =
1048 sharedhdr.codeImageSize;
1049 nlm_extended_header (outbfd)->sharedDataOffset =
1050 sharedhdr.dataImageOffset - shared_offset + shared_section->filepos;
1051 nlm_extended_header (outbfd)->sharedDataLength =
1052 sharedhdr.dataImageSize;
1053 nlm_extended_header (outbfd)->sharedRelocationFixupOffset =
1054 (sharedhdr.relocationFixupOffset
1055 - shared_offset
1056 + shared_section->filepos);
1057 nlm_extended_header (outbfd)->sharedRelocationFixupCount =
1058 sharedhdr.numberOfRelocationFixups;
1059 nlm_extended_header (outbfd)->sharedExternalReferenceOffset =
1060 (sharedhdr.externalReferencesOffset
1061 - shared_offset
1062 + shared_section->filepos);
1063 nlm_extended_header (outbfd)->sharedExternalReferenceCount =
1064 sharedhdr.numberOfExternalReferences;
1065 nlm_extended_header (outbfd)->sharedPublicsOffset =
1066 sharedhdr.publicsOffset - shared_offset + shared_section->filepos;
1067 nlm_extended_header (outbfd)->sharedPublicsCount =
1068 sharedhdr.numberOfPublics;
a30f59a4
ILT
1069 nlm_extended_header (outbfd)->sharedDebugRecordOffset =
1070 sharedhdr.debugInfoOffset - shared_offset + shared_section->filepos;
1071 nlm_extended_header (outbfd)->sharedDebugRecordCount =
1072 sharedhdr.numberOfDebugRecords;
ef5b5368
ILT
1073 nlm_extended_header (outbfd)->SharedInitializationOffset =
1074 sharedhdr.codeStartOffset;
1075 nlm_extended_header (outbfd)->SharedExitProcedureOffset =
1076 sharedhdr.exitProcedureOffset;
1077 free (data);
1078 }
0f6df2ee 1079 len = strlen (output_file);
d92aadfd
ILT
1080 if (len > NLM_MODULE_NAME_SIZE - 2)
1081 len = NLM_MODULE_NAME_SIZE - 2;
1082 nlm_fixed_header (outbfd)->moduleName[0] = len;
90d8edfd 1083
0f6df2ee 1084 strncpy (nlm_fixed_header (outbfd)->moduleName + 1, output_file,
d92aadfd
ILT
1085 NLM_MODULE_NAME_SIZE - 2);
1086 nlm_fixed_header (outbfd)->moduleName[NLM_MODULE_NAME_SIZE - 1] = '\0';
90d8edfd
ILT
1087 for (modname = nlm_fixed_header (outbfd)->moduleName;
1088 *modname != '\0';
1089 modname++)
9d04d618 1090 if (islower ((unsigned char) *modname))
90d8edfd
ILT
1091 *modname = toupper (*modname);
1092
d92aadfd
ILT
1093 strncpy (nlm_variable_header (outbfd)->oldThreadName, " LONG",
1094 NLM_OLD_THREAD_NAME_LENGTH);
1095
162794fe
ILT
1096 nlm_cygnus_ext_header (outbfd)->offset = secsec->filepos;
1097 nlm_cygnus_ext_header (outbfd)->length = bfd_section_size (outbfd, secsec);
dcb210cb 1098
d92aadfd 1099 if (! bfd_close (outbfd))
0f6df2ee 1100 bfd_fatal (output_file);
d92aadfd 1101 if (! bfd_close (inbfd))
0f6df2ee
ILT
1102 bfd_fatal (input_file);
1103
1104 if (unlink_on_exit != NULL)
1105 unlink (unlink_on_exit);
d92aadfd
ILT
1106
1107 return 0;
1108}
1109\f
1110/* Display a help message and exit. */
1111
1112static void
1113show_help ()
1114{
9d04d618 1115 printf (_("%s: Convert an object file into a NetWare Loadable Module\n"),
d92aadfd
ILT
1116 program_name);
1117 show_usage (stdout, 0);
1118}
1119
1120/* Show a usage message and exit. */
1121
1122static void
1123show_usage (file, status)
1124 FILE *file;
1125 int status;
1126{
9d04d618 1127 fprintf (file, _("\
e70f2bde
ILT
1128Usage: %s [-dhV] [-I bfdname] [-O bfdname] [-T header-file] [-l linker]\n\
1129 [--input-target=bfdname] [--output-target=bfdname]\n\
0f6df2ee
ILT
1130 [--header-file=file] [--linker=linker] [--debug]\n\
1131 [--help] [--version]\n\
9d04d618 1132 [in-file [out-file]]\n"),
d92aadfd 1133 program_name);
1d1a5a53 1134 if (status == 0)
9d04d618 1135 fprintf (file, _("Report bugs to bug-gnu-utils@gnu.org\n"));
d92aadfd
ILT
1136 exit (status);
1137}
1138\f
1139/* Select the output format based on the input architecture, machine,
1140 and endianness. This chooses the appropriate NLM target. */
1141
1142static const char *
1143select_output_format (arch, mach, bigendian)
1144 enum bfd_architecture arch;
419093bc 1145 unsigned long mach;
d92aadfd
ILT
1146 boolean bigendian;
1147{
1148 switch (arch)
1149 {
9d11577a 1150#ifdef NLMCONV_I386
d92aadfd
ILT
1151 case bfd_arch_i386:
1152 return "nlm32-i386";
9d11577a
ILT
1153#endif
1154#ifdef NLMCONV_SPARC
a30f59a4
ILT
1155 case bfd_arch_sparc:
1156 return "nlm32-sparc";
9d11577a
ILT
1157#endif
1158#ifdef NLMCONV_ALPHA
419093bc
ILT
1159 case bfd_arch_alpha:
1160 return "nlm32-alpha";
9d11577a
ILT
1161#endif
1162#ifdef NLMCONV_POWERPC
4bd7a65f
ILT
1163 case bfd_arch_powerpc:
1164 return "nlm32-powerpc";
9d11577a 1165#endif
d92aadfd 1166 default:
9d04d618 1167 fprintf (stderr, _("%s: support not compiled in for %s\n"),
d92aadfd
ILT
1168 program_name, bfd_printable_arch_mach (arch, mach));
1169 exit (1);
1170 /* Avoid warning. */
1171 return NULL;
1172 }
1173 /*NOTREACHED*/
1174}
1175\f
90d8edfd
ILT
1176/* The BFD sections are copied in two passes. This function selects
1177 the output section for each input section, and sets up the section
1178 name, size, etc. */
d92aadfd
ILT
1179
1180static void
1181setup_sections (inbfd, insec, data_ptr)
1182 bfd *inbfd;
1183 asection *insec;
1184 PTR data_ptr;
1185{
1186 bfd *outbfd = (bfd *) data_ptr;
ef5b5368 1187 flagword f;
90d8edfd
ILT
1188 const char *outname;
1189 asection *outsec;
e70f2bde
ILT
1190 bfd_vma offset;
1191 bfd_size_type align;
1192 bfd_size_type add;
dcb210cb 1193 bfd_size_type secsecsize;
d92aadfd 1194
90d8edfd
ILT
1195 f = bfd_get_section_flags (inbfd, insec);
1196 if (f & SEC_CODE)
1197 outname = NLM_CODE_NAME;
1198 else if ((f & SEC_LOAD) && (f & SEC_HAS_CONTENTS))
1199 outname = NLM_INITIALIZED_DATA_NAME;
1200 else if (f & SEC_ALLOC)
1201 outname = NLM_UNINITIALIZED_DATA_NAME;
1202 else
1203 outname = bfd_section_name (inbfd, insec);
1204
1205 outsec = bfd_get_section_by_name (outbfd, outname);
d92aadfd
ILT
1206 if (outsec == NULL)
1207 {
90d8edfd 1208 outsec = bfd_make_section (outbfd, outname);
d92aadfd 1209 if (outsec == NULL)
9d04d618 1210 bfd_fatal (_("make section"));
d92aadfd
ILT
1211 }
1212
1213 insec->output_section = outsec;
e70f2bde
ILT
1214
1215 offset = bfd_section_size (outbfd, outsec);
1216 align = 1 << bfd_section_alignment (inbfd, insec);
1217 add = ((offset + align - 1) &~ (align - 1)) - offset;
1218 insec->output_offset = offset + add;
d92aadfd
ILT
1219
1220 if (! bfd_set_section_size (outbfd, outsec,
90d8edfd 1221 (bfd_section_size (outbfd, outsec)
e70f2bde
ILT
1222 + bfd_section_size (inbfd, insec)
1223 + add)))
9d04d618 1224 bfd_fatal (_("set section size"));
d92aadfd 1225
90d8edfd
ILT
1226 if ((bfd_section_alignment (inbfd, insec)
1227 > bfd_section_alignment (outbfd, outsec))
1228 && ! bfd_set_section_alignment (outbfd, outsec,
1229 bfd_section_alignment (inbfd, insec)))
9d04d618 1230 bfd_fatal (_("set section alignment"));
d92aadfd 1231
1d1a5a53
ILT
1232 if (! bfd_set_section_flags (outbfd, outsec,
1233 f | bfd_get_section_flags (outbfd, outsec)))
9d04d618 1234 bfd_fatal (_("set section flags"));
419093bc
ILT
1235
1236 bfd_set_reloc (outbfd, outsec, (arelent **) NULL, 0);
dcb210cb
ILT
1237
1238 /* For each input section we allocate space for an entry in
1239 .nlmsections. */
1240 secsecsize = bfd_section_size (outbfd, secsec);
1241 secsecsize += strlen (bfd_section_name (inbfd, insec)) + 1;
1242 secsecsize = (secsecsize + 3) &~ 3;
1243 secsecsize += 8;
1244 if (! bfd_set_section_size (outbfd, secsec, secsecsize))
9d04d618 1245 bfd_fatal (_("set .nlmsections size"));
d92aadfd
ILT
1246}
1247
1248/* Copy the section contents. */
1249
1250static void
1251copy_sections (inbfd, insec, data_ptr)
1252 bfd *inbfd;
1253 asection *insec;
1254 PTR data_ptr;
1255{
dcb210cb 1256 static bfd_size_type secsecoff = 0;
d92aadfd 1257 bfd *outbfd = (bfd *) data_ptr;
dcb210cb 1258 const char *inname;
d92aadfd
ILT
1259 asection *outsec;
1260 bfd_size_type size;
1261 PTR contents;
ae5d2ff5 1262 long reloc_size;
dcb210cb
ILT
1263 bfd_byte buf[4];
1264 bfd_size_type add;
1265
1266 inname = bfd_section_name (inbfd, insec);
d92aadfd 1267
90d8edfd 1268 outsec = insec->output_section;
d92aadfd
ILT
1269 assert (outsec != NULL);
1270
1271 size = bfd_get_section_size_before_reloc (insec);
d92aadfd
ILT
1272
1273 /* FIXME: Why are these necessary? */
1274 insec->_cooked_size = insec->_raw_size;
1275 insec->reloc_done = true;
1276
1277 if ((bfd_get_section_flags (inbfd, insec) & SEC_HAS_CONTENTS) == 0)
1278 contents = NULL;
1279 else
1280 {
1281 contents = xmalloc (size);
1282 if (! bfd_get_section_contents (inbfd, insec, contents,
1283 (file_ptr) 0, size))
1284 bfd_fatal (bfd_get_filename (inbfd));
1285 }
1286
1287 reloc_size = bfd_get_reloc_upper_bound (inbfd, insec);
ae5d2ff5
ILT
1288 if (reloc_size < 0)
1289 bfd_fatal (bfd_get_filename (inbfd));
419093bc 1290 if (reloc_size != 0)
d92aadfd
ILT
1291 {
1292 arelent **relocs;
ae5d2ff5 1293 long reloc_count;
d92aadfd
ILT
1294
1295 relocs = (arelent **) xmalloc (reloc_size);
1296 reloc_count = bfd_canonicalize_reloc (inbfd, insec, relocs, symbols);
ae5d2ff5
ILT
1297 if (reloc_count < 0)
1298 bfd_fatal (bfd_get_filename (inbfd));
419093bc 1299 mangle_relocs (outbfd, insec, &relocs, &reloc_count, (char *) contents,
ef5b5368 1300 size);
419093bc
ILT
1301
1302 /* FIXME: refers to internal BFD fields. */
1303 if (outsec->orelocation != (arelent **) NULL)
1304 {
1305 bfd_size_type total_count;
1306 arelent **combined;
1307
1308 total_count = reloc_count + outsec->reloc_count;
d5e29b60 1309 combined = (arelent **) xmalloc (total_count * sizeof (arelent *));
419093bc 1310 memcpy (combined, outsec->orelocation,
d5e29b60 1311 outsec->reloc_count * sizeof (arelent *));
419093bc 1312 memcpy (combined + outsec->reloc_count, relocs,
d5e29b60 1313 (size_t) (reloc_count * sizeof (arelent *)));
419093bc
ILT
1314 free (outsec->orelocation);
1315 reloc_count = total_count;
1316 relocs = combined;
1317 }
1318
d92aadfd
ILT
1319 bfd_set_reloc (outbfd, outsec, relocs, reloc_count);
1320 }
1321
1322 if (contents != NULL)
1323 {
1324 if (! bfd_set_section_contents (outbfd, outsec, contents,
90d8edfd 1325 insec->output_offset, size))
d92aadfd
ILT
1326 bfd_fatal (bfd_get_filename (outbfd));
1327 free (contents);
1328 }
dcb210cb
ILT
1329
1330 /* Add this section to .nlmsections. */
1331 if (! bfd_set_section_contents (outbfd, secsec, (PTR) inname, secsecoff,
1332 strlen (inname) + 1))
9d04d618 1333 bfd_fatal (_("set .nlmsection contents"));
dcb210cb
ILT
1334 secsecoff += strlen (inname) + 1;
1335
1336 add = ((secsecoff + 3) &~ 3) - secsecoff;
1337 if (add != 0)
1338 {
1339 bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
1340 if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, add))
9d04d618 1341 bfd_fatal (_("set .nlmsection contents"));
dcb210cb
ILT
1342 secsecoff += add;
1343 }
1344
1345 if (contents != NULL)
1346 bfd_h_put_32 (outbfd, (bfd_vma) outsec->filepos, buf);
1347 else
1348 bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
1349 if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
9d04d618 1350 bfd_fatal (_("set .nlmsection contents"));
dcb210cb
ILT
1351 secsecoff += 4;
1352
1353 bfd_h_put_32 (outbfd, (bfd_vma) size, buf);
1354 if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
9d04d618 1355 bfd_fatal (_("set .nlmsection contents"));
dcb210cb 1356 secsecoff += 4;
d92aadfd
ILT
1357}
1358
1359/* Some, perhaps all, NetWare targets require changing the relocs used
1360 by the input formats. */
1361
1362static void
419093bc
ILT
1363mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,
1364 contents_size)
d92aadfd 1365 bfd *outbfd;
ef5b5368 1366 asection *insec;
419093bc 1367 arelent ***relocs_ptr;
ae5d2ff5 1368 long *reloc_count_ptr;
d92aadfd
ILT
1369 char *contents;
1370 bfd_size_type contents_size;
1371{
1372 switch (bfd_get_arch (outbfd))
1373 {
9d11577a 1374#ifdef NLMCONV_I386
d92aadfd 1375 case bfd_arch_i386:
419093bc
ILT
1376 i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
1377 contents, contents_size);
1378 break;
9d11577a
ILT
1379#endif
1380#ifdef NLMCONV_ALPHA
419093bc
ILT
1381 case bfd_arch_alpha:
1382 alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
1383 contents, contents_size);
d92aadfd 1384 break;
9d11577a
ILT
1385#endif
1386#ifdef NLMCONV_POWERPC
4bd7a65f
ILT
1387 case bfd_arch_powerpc:
1388 powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
1389 contents, contents_size);
1390 break;
9d11577a 1391#endif
d92aadfd 1392 default:
419093bc
ILT
1393 default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
1394 contents, contents_size);
d92aadfd
ILT
1395 break;
1396 }
1397}
1398
419093bc
ILT
1399/* By default all we need to do for relocs is change the address by
1400 the output_offset. */
1401
1402/*ARGSUSED*/
1403static void
1404default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,
1405 contents_size)
1406 bfd *outbfd;
1407 asection *insec;
1408 arelent ***relocs_ptr;
ae5d2ff5 1409 long *reloc_count_ptr;
419093bc
ILT
1410 char *contents;
1411 bfd_size_type contents_size;
1412{
1413 if (insec->output_offset != 0)
1414 {
ae5d2ff5 1415 long reloc_count;
419093bc 1416 register arelent **relocs;
ae5d2ff5 1417 register long i;
419093bc
ILT
1418
1419 reloc_count = *reloc_count_ptr;
1420 relocs = *relocs_ptr;
1421 for (i = 0; i < reloc_count; i++, relocs++)
1422 (*relocs)->address += insec->output_offset;
1423 }
1424}
9d11577a
ILT
1425\f
1426#ifdef NLMCONV_I386
419093bc 1427
d92aadfd
ILT
1428/* NetWare on the i386 supports a restricted set of relocs, which are
1429 different from those used on other i386 targets. This routine
1430 converts the relocs. It is, obviously, very target dependent. At
1431 the moment, the nlm32-i386 backend performs similar translations;
1432 however, it is more reliable and efficient to do them here. */
1433
1434static reloc_howto_type nlm_i386_pcrel_howto =
1435 HOWTO (1, /* type */
1436 0, /* rightshift */
1437 2, /* size (0 = byte, 1 = short, 2 = long) */
1438 32, /* bitsize */
1439 true, /* pc_relative */
1440 0, /* bitpos */
1441 complain_overflow_signed, /* complain_on_overflow */
1442 0, /* special_function */
1443 "DISP32", /* name */
1444 true, /* partial_inplace */
1445 0xffffffff, /* src_mask */
1446 0xffffffff, /* dst_mask */
1447 true); /* pcrel_offset */
1448
1449static void
419093bc 1450i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,
ef5b5368 1451 contents_size)
d92aadfd 1452 bfd *outbfd;
ef5b5368 1453 asection *insec;
419093bc 1454 arelent ***relocs_ptr;
ae5d2ff5 1455 long *reloc_count_ptr;
d92aadfd
ILT
1456 char *contents;
1457 bfd_size_type contents_size;
1458{
ae5d2ff5 1459 long reloc_count, i;
419093bc 1460 arelent **relocs;
ef5b5368
ILT
1461
1462 reloc_count = *reloc_count_ptr;
419093bc 1463 relocs = *relocs_ptr;
ef5b5368 1464 for (i = 0; i < reloc_count; i++)
d92aadfd
ILT
1465 {
1466 arelent *rel;
1467 asymbol *sym;
a30f59a4 1468 bfd_size_type address;
d92aadfd
ILT
1469 bfd_vma addend;
1470
1471 rel = *relocs++;
1472 sym = *rel->sym_ptr_ptr;
1473
a30f59a4
ILT
1474 /* We're moving the relocs from the input section to the output
1475 section, so we must adjust the address accordingly. */
1476 address = rel->address;
1477 rel->address += insec->output_offset;
1478
d92aadfd
ILT
1479 /* Note that no serious harm will ensue if we fail to change a
1480 reloc. The backend will fail when writing out the reloc. */
1481
1482 /* Make sure this reloc is within the data we have. We use only
1483 4 byte relocs here, so we insist on having 4 bytes. */
a30f59a4 1484 if (address + 4 > contents_size)
d92aadfd
ILT
1485 continue;
1486
ef5b5368
ILT
1487 /* A PC relative reloc entirely within a single section is
1488 completely unnecessary. This can be generated by ld -r. */
1489 if (sym == insec->symbol
1490 && rel->howto != NULL
1491 && rel->howto->pc_relative
1492 && ! rel->howto->pcrel_offset)
1493 {
1494 --*reloc_count_ptr;
1495 --relocs;
1496 memmove (relocs, relocs + 1,
419093bc 1497 (size_t) ((reloc_count - i) * sizeof (arelent *)));
ef5b5368
ILT
1498 continue;
1499 }
1500
90d8edfd
ILT
1501 /* Get the amount the relocation will add in. */
1502 addend = rel->addend + sym->value;
1503
1504 /* NetWare doesn't support PC relative relocs against defined
1505 symbols, so we have to eliminate them by doing the relocation
1506 now. We can only do this if the reloc is within a single
1507 section. */
1508 if (rel->howto != NULL
1509 && rel->howto->pc_relative
1510 && bfd_get_section (sym) == insec->output_section)
1511 {
1512 bfd_vma val;
1513
1514 if (rel->howto->pcrel_offset)
a30f59a4 1515 addend -= address;
90d8edfd 1516
a30f59a4 1517 val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
90d8edfd 1518 val += addend;
a30f59a4 1519 bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
90d8edfd
ILT
1520
1521 --*reloc_count_ptr;
1522 --relocs;
1523 memmove (relocs, relocs + 1,
419093bc 1524 (size_t) ((reloc_count - i) * sizeof (arelent *)));
90d8edfd
ILT
1525 continue;
1526 }
1527
d92aadfd
ILT
1528 /* NetWare doesn't support reloc addends, so we get rid of them
1529 here by simply adding them into the object data. We handle
1530 the symbol value, if any, the same way. */
d92aadfd
ILT
1531 if (addend != 0
1532 && rel->howto != NULL
1533 && rel->howto->rightshift == 0
1534 && rel->howto->size == 2
1535 && rel->howto->bitsize == 32
1536 && rel->howto->bitpos == 0
1537 && rel->howto->src_mask == 0xffffffff
1538 && rel->howto->dst_mask == 0xffffffff)
1539 {
1540 bfd_vma val;
1541
a30f59a4 1542 val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
d92aadfd 1543 val += addend;
a30f59a4 1544 bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
d92aadfd
ILT
1545
1546 /* Adjust the reloc for the changes we just made. */
1547 rel->addend = 0;
a18ff4a7 1548 if (! bfd_is_und_section (bfd_get_section (sym)))
d92aadfd
ILT
1549 rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
1550 }
1551
1552 /* NetWare uses a reloc with pcrel_offset set. We adjust
1553 pc_relative relocs accordingly. We are going to change the
1554 howto field, so we can only do this if the current one is
1555 compatible. We should check that special_function is NULL
1556 here, but at the moment coff-i386 uses a special_function
1557 which does not affect what we are doing here. */
1558 if (rel->howto != NULL
1559 && rel->howto->pc_relative
1560 && ! rel->howto->pcrel_offset
1561 && rel->howto->rightshift == 0
1562 && rel->howto->size == 2
1563 && rel->howto->bitsize == 32
1564 && rel->howto->bitpos == 0
1565 && rel->howto->src_mask == 0xffffffff
1566 && rel->howto->dst_mask == 0xffffffff)
1567 {
1568 bfd_vma val;
1569
1570 /* When pcrel_offset is not set, it means that the negative
1571 of the address of the memory location is stored in the
1572 memory location. We must add it back in. */
a30f59a4
ILT
1573 val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
1574 val += address;
1575 bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
d92aadfd
ILT
1576
1577 /* We must change to a new howto. */
1578 rel->howto = &nlm_i386_pcrel_howto;
1579 }
1580 }
1581}
419093bc 1582
9d11577a
ILT
1583#endif /* NLMCONV_I386 */
1584\f
1585#ifdef NLMCONV_ALPHA
1586
419093bc
ILT
1587/* On the Alpha the first reloc for every section must be a special
1588 relocs which hold the GP address. Also, the first reloc in the
1589 file must be a special reloc which holds the address of the .lita
1590 section. */
1591
1592static reloc_howto_type nlm32_alpha_nw_howto =
1593 HOWTO (ALPHA_R_NW_RELOC, /* type */
1594 0, /* rightshift */
1595 0, /* size (0 = byte, 1 = short, 2 = long) */
1596 0, /* bitsize */
1597 false, /* pc_relative */
1598 0, /* bitpos */
1599 complain_overflow_dont, /* complain_on_overflow */
1600 0, /* special_function */
1601 "NW_RELOC", /* name */
1602 false, /* partial_inplace */
1603 0, /* src_mask */
1604 0, /* dst_mask */
1605 false); /* pcrel_offset */
1606
1607/*ARGSUSED*/
1608static void
1609alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,
1610 contents_size)
1611 bfd *outbfd;
1612 asection *insec;
1613 register arelent ***relocs_ptr;
ae5d2ff5 1614 long *reloc_count_ptr;
419093bc
ILT
1615 char *contents;
1616 bfd_size_type contents_size;
1617{
ae5d2ff5 1618 long old_reloc_count;
419093bc
ILT
1619 arelent **old_relocs;
1620 register arelent **relocs;
1621
1622 old_reloc_count = *reloc_count_ptr;
1623 old_relocs = *relocs_ptr;
1624 relocs = (arelent **) xmalloc ((old_reloc_count + 3) * sizeof (arelent *));
1625 *relocs_ptr = relocs;
1626
1627 if (nlm_alpha_backend_data (outbfd)->lita_address == 0)
1628 {
1629 bfd *inbfd;
1630 asection *lita_section;
1631
1632 inbfd = insec->owner;
1633 lita_section = bfd_get_section_by_name (inbfd, _LITA);
1634 if (lita_section != (asection *) NULL)
1635 {
1636 nlm_alpha_backend_data (outbfd)->lita_address =
1637 bfd_get_section_vma (inbfd, lita_section);
1638 nlm_alpha_backend_data (outbfd)->lita_size =
1639 bfd_section_size (inbfd, lita_section);
1640 }
1641 else
1642 {
1643 /* Avoid outputting this reloc again. */
1644 nlm_alpha_backend_data (outbfd)->lita_address = 4;
1645 }
1646
1647 *relocs = (arelent *) xmalloc (sizeof (arelent));
a18ff4a7 1648 (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
419093bc
ILT
1649 (*relocs)->address = nlm_alpha_backend_data (outbfd)->lita_address;
1650 (*relocs)->addend = nlm_alpha_backend_data (outbfd)->lita_size + 1;
1651 (*relocs)->howto = &nlm32_alpha_nw_howto;
1652 ++relocs;
1653 ++(*reloc_count_ptr);
1654 }
1655
f645a4bf 1656 /* Get the GP value from bfd. */
419093bc 1657 if (nlm_alpha_backend_data (outbfd)->gp == 0)
f645a4bf
ILT
1658 nlm_alpha_backend_data (outbfd)->gp =
1659 bfd_ecoff_get_gp_value (insec->owner);
419093bc
ILT
1660
1661 *relocs = (arelent *) xmalloc (sizeof (arelent));
a18ff4a7 1662 (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
419093bc
ILT
1663 (*relocs)->address = nlm_alpha_backend_data (outbfd)->gp;
1664 (*relocs)->addend = 0;
1665 (*relocs)->howto = &nlm32_alpha_nw_howto;
1666 ++relocs;
1667 ++(*reloc_count_ptr);
1668
1669 memcpy ((PTR) relocs, (PTR) old_relocs,
1670 (size_t) old_reloc_count * sizeof (arelent *));
1671 relocs[old_reloc_count] = (arelent *) NULL;
1672
1673 free (old_relocs);
1674
1675 if (insec->output_offset != 0)
1676 {
1677 register bfd_size_type i;
1678
9d04d618 1679 for (i = 0; i < (bfd_size_type) old_reloc_count; i++, relocs++)
419093bc
ILT
1680 (*relocs)->address += insec->output_offset;
1681 }
1682}
4bd7a65f 1683
9d11577a
ILT
1684#endif /* NLMCONV_ALPHA */
1685\f
1686#ifdef NLMCONV_POWERPC
1687
4bd7a65f
ILT
1688/* We keep a linked list of stubs which we must build. Because BFD
1689 requires us to know the sizes of all sections before we can set the
1690 contents of any, we must figure out which stubs we want to build
1691 before we can actually build any of them. */
1692
1693struct powerpc_stub
1694{
1695 /* Next stub in linked list. */
1696 struct powerpc_stub *next;
1697
1698 /* Symbol whose value is the start of the stub. This is a symbol
1699 whose name begins with `.'. */
1700 asymbol *start;
1701
1702 /* Symbol we are going to create a reloc against. This is a symbol
1703 with the same name as START but without the leading `.'. */
1704 asymbol *reloc;
1705
1706 /* The TOC index for this stub. This is the index into the TOC
1707 section at which the reloc is created. */
1708 unsigned int toc_index;
1709};
1710
1711/* The linked list of stubs. */
1712
1713static struct powerpc_stub *powerpc_stubs;
1714
1715/* This is what a stub looks like. The first instruction will get
1716 adjusted with the correct TOC index. */
1717
1718static unsigned long powerpc_stub_insns[] =
1719{
1720 0x81820000, /* lwz r12,0(r2) */
1721 0x90410014, /* stw r2,20(r1) */
1722 0x800c0000, /* lwz r0,0(r12) */
1723 0x804c0004, /* lwz r2,r(r12) */
1724 0x7c0903a6, /* mtctr r0 */
1725 0x4e800420, /* bctr */
1726 0, /* Traceback table. */
1727 0xc8000,
1728 0
1729};
1730
1731#define POWERPC_STUB_INSN_COUNT \
1732 (sizeof powerpc_stub_insns / sizeof powerpc_stub_insns[0])
1733
1734#define POWERPC_STUB_SIZE (4 * POWERPC_STUB_INSN_COUNT)
1735
1736/* Each stub uses a four byte TOC entry. */
1737#define POWERPC_STUB_TOC_ENTRY_SIZE (4)
1738
1739/* The original size of the .got section. */
1740static bfd_size_type powerpc_initial_got_size;
1741
1742/* Look for all undefined symbols beginning with `.', and prepare to
1743 build a stub for each one. */
1744
1745static void
c59fa195 1746powerpc_build_stubs (inbfd, outbfd, symbols_ptr, symcount_ptr)
4bd7a65f 1747 bfd *inbfd;
c59fa195 1748 bfd *outbfd;
4bd7a65f 1749 asymbol ***symbols_ptr;
ae5d2ff5 1750 long *symcount_ptr;
4bd7a65f
ILT
1751{
1752 asection *stub_sec;
1753 asection *got_sec;
1754 unsigned int got_base;
ae5d2ff5
ILT
1755 long i;
1756 long symcount;
1757 long stubcount;
4bd7a65f
ILT
1758
1759 /* Make a section to hold stubs. We don't set SEC_HAS_CONTENTS for
1760 the section to prevent copy_sections from reading from it. */
1761 stub_sec = bfd_make_section (inbfd, ".stubs");
1762 if (stub_sec == (asection *) NULL
1763 || ! bfd_set_section_flags (inbfd, stub_sec,
1764 (SEC_CODE
1765 | SEC_RELOC
1766 | SEC_ALLOC
1767 | SEC_LOAD))
1768 || ! bfd_set_section_alignment (inbfd, stub_sec, 2))
1769 bfd_fatal (".stubs");
1770
1771 /* Get the TOC section, which is named .got. */
1772 got_sec = bfd_get_section_by_name (inbfd, ".got");
1773 if (got_sec == (asection *) NULL)
1774 {
1775 got_sec = bfd_make_section (inbfd, ".got");
1776 if (got_sec == (asection *) NULL
1777 || ! bfd_set_section_flags (inbfd, got_sec,
1778 (SEC_DATA
1779 | SEC_RELOC
1780 | SEC_ALLOC
1781 | SEC_LOAD
1782 | SEC_HAS_CONTENTS))
1783 || ! bfd_set_section_alignment (inbfd, got_sec, 2))
1784 bfd_fatal (".got");
1785 }
1786
1787 powerpc_initial_got_size = bfd_section_size (inbfd, got_sec);
1788 got_base = powerpc_initial_got_size;
1789 got_base = (got_base + 3) &~ 3;
1790
1791 stubcount = 0;
1792
1793 symcount = *symcount_ptr;
1794 for (i = 0; i < symcount; i++)
1795 {
1796 asymbol *sym;
1797 asymbol *newsym;
1798 char *newname;
1799 struct powerpc_stub *item;
1800
1801 sym = (*symbols_ptr)[i];
1802
1803 /* We must make a stub for every undefined symbol whose name
1804 starts with '.'. */
1805 if (bfd_asymbol_name (sym)[0] != '.'
a18ff4a7 1806 || ! bfd_is_und_section (bfd_get_section (sym)))
4bd7a65f
ILT
1807 continue;
1808
1809 /* Make a new undefined symbol with the same name but without
1810 the leading `.'. */
1811 newsym = (asymbol *) xmalloc (sizeof (asymbol));
1812 *newsym = *sym;
1813 newname = (char *) xmalloc (strlen (bfd_asymbol_name (sym)));
1814 strcpy (newname, bfd_asymbol_name (sym) + 1);
1815 newsym->name = newname;
1816
1817 /* Define the `.' symbol to be in the stub section. */
1818 sym->section = stub_sec;
1819 sym->value = stubcount * POWERPC_STUB_SIZE;
ae5d2ff5
ILT
1820 /* We set the BSF_DYNAMIC flag here so that we can check it when
1821 we are mangling relocs. FIXME: This is a hack. */
1822 sym->flags = BSF_LOCAL | BSF_DYNAMIC;
4bd7a65f
ILT
1823
1824 /* Add this stub to the linked list. */
1825 item = (struct powerpc_stub *) xmalloc (sizeof (struct powerpc_stub));
1826 item->start = sym;
1827 item->reloc = newsym;
1828 item->toc_index = got_base + stubcount * POWERPC_STUB_TOC_ENTRY_SIZE;
1829
1830 item->next = powerpc_stubs;
1831 powerpc_stubs = item;
1832
1833 ++stubcount;
1834 }
1835
1836 if (stubcount > 0)
1837 {
1838 asymbol **s;
1839 struct powerpc_stub *l;
1840
1841 /* Add the new symbols we just created to the symbol table. */
1842 *symbols_ptr = (asymbol **) xrealloc ((char *) *symbols_ptr,
1843 ((symcount + stubcount)
1844 * sizeof (asymbol)));
1845 *symcount_ptr += stubcount;
1846 s = &(*symbols_ptr)[symcount];
1847 for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
1848 *s++ = l->reloc;
1849
1850 /* Set the size of the .stubs section and increase the size of
1851 the .got section. */
1852 if (! bfd_set_section_size (inbfd, stub_sec,
1853 stubcount * POWERPC_STUB_SIZE)
1854 || ! bfd_set_section_size (inbfd, got_sec,
1855 (got_base
1856 + (stubcount
1857 * POWERPC_STUB_TOC_ENTRY_SIZE))))
9d04d618 1858 bfd_fatal (_("stub section sizes"));
4bd7a65f
ILT
1859 }
1860}
1861
1862/* Resolve all the stubs for PowerPC NetWare. We fill in the contents
1863 of the output section, and create new relocs in the TOC. */
1864
1865static void
1866powerpc_resolve_stubs (inbfd, outbfd)
1867 bfd *inbfd;
1868 bfd *outbfd;
1869{
1870 bfd_byte buf[POWERPC_STUB_SIZE];
1871 unsigned int i;
1872 unsigned int stubcount;
1873 arelent **relocs;
1874 asection *got_sec;
1875 arelent **r;
1876 struct powerpc_stub *l;
1877
1878 if (powerpc_stubs == (struct powerpc_stub *) NULL)
1879 return;
1880
1881 for (i = 0; i < POWERPC_STUB_INSN_COUNT; i++)
1882 bfd_put_32 (outbfd, (bfd_vma) powerpc_stub_insns[i], buf + i * 4);
1883
1884 got_sec = bfd_get_section_by_name (inbfd, ".got");
1885 assert (got_sec != (asection *) NULL);
1886 assert (got_sec->output_section->orelocation == (arelent **) NULL);
1887
1888 stubcount = 0;
1889 for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
1890 ++stubcount;
1891 relocs = (arelent **) xmalloc (stubcount * sizeof (arelent *));
1892
1893 r = relocs;
1894 for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
1895 {
1896 arelent *reloc;
1897
1898 /* Adjust the first instruction to use the right TOC index. */
1899 bfd_put_32 (outbfd, (bfd_vma) powerpc_stub_insns[0] + l->toc_index, buf);
1900
1901 /* Write this stub out. */
1902 if (! bfd_set_section_contents (outbfd,
1903 bfd_get_section (l->start),
1904 buf,
1905 l->start->value,
1906 POWERPC_STUB_SIZE))
9d04d618 1907 bfd_fatal (_("writing stub"));
4bd7a65f
ILT
1908
1909 /* Create a new reloc for the TOC entry. */
1910 reloc = (arelent *) xmalloc (sizeof (arelent));
1911 reloc->sym_ptr_ptr = &l->reloc;
1912 reloc->address = l->toc_index + got_sec->output_offset;
1913 reloc->addend = 0;
1914 reloc->howto = bfd_reloc_type_lookup (inbfd, BFD_RELOC_32);
1915
1916 *r++ = reloc;
1917 }
1918
1919 bfd_set_reloc (outbfd, got_sec->output_section, relocs, stubcount);
1920}
1921
1922/* Adjust relocation entries for PowerPC NetWare. We do not output
1923 TOC relocations. The object code already contains the offset from
1924 the TOC pointer. When the function is called, the TOC register,
1925 r2, will be set to the correct TOC value, so there is no need for
1926 any further reloc. */
1927
1928/*ARGSUSED*/
1929static void
1930powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,
1931 contents_size)
1932 bfd *outbfd;
1933 asection *insec;
1934 register arelent ***relocs_ptr;
ae5d2ff5 1935 long *reloc_count_ptr;
4bd7a65f
ILT
1936 char *contents;
1937 bfd_size_type contents_size;
1938{
1d1a5a53 1939 reloc_howto_type *toc_howto;
ae5d2ff5 1940 long reloc_count;
4bd7a65f 1941 register arelent **relocs;
ae5d2ff5 1942 register long i;
4bd7a65f
ILT
1943
1944 toc_howto = bfd_reloc_type_lookup (insec->owner, BFD_RELOC_PPC_TOC16);
1945 if (toc_howto == (reloc_howto_type *) NULL)
1946 abort ();
1947
1948 /* If this is the .got section, clear out all the contents beyond
1949 the initial size. We must do this here because copy_sections is
1950 going to write out whatever we return in the contents field. */
1951 if (strcmp (bfd_get_section_name (insec->owner, insec), ".got") == 0)
1952 memset (contents + powerpc_initial_got_size, 0,
1d1a5a53
ILT
1953 (size_t) (bfd_get_section_size_after_reloc (insec)
1954 - powerpc_initial_got_size));
4bd7a65f
ILT
1955
1956 reloc_count = *reloc_count_ptr;
1957 relocs = *relocs_ptr;
1958 for (i = 0; i < reloc_count; i++)
1959 {
1960 arelent *rel;
1961 asymbol *sym;
1d1a5a53 1962 bfd_vma sym_value;
4bd7a65f
ILT
1963
1964 rel = *relocs++;
1965 sym = *rel->sym_ptr_ptr;
1966
1d1a5a53
ILT
1967 /* Convert any relocs against the .bss section into relocs
1968 against the .data section. */
1969 if (strcmp (bfd_get_section_name (outbfd, bfd_get_section (sym)),
1970 NLM_UNINITIALIZED_DATA_NAME) == 0)
1971 {
1972 asection *datasec;
1973
1974 datasec = bfd_get_section_by_name (outbfd,
1975 NLM_INITIALIZED_DATA_NAME);
1976 if (datasec != NULL)
1977 {
1978 rel->addend += (bfd_get_section_vma (outbfd,
1979 bfd_get_section (sym))
1980 + sym->value);
1981 rel->sym_ptr_ptr = datasec->symbol_ptr_ptr;
1982 sym = *rel->sym_ptr_ptr;
1983 }
1984 }
1985
4bd7a65f
ILT
1986 /* We must be able to resolve all PC relative relocs at this
1987 point. If we get a branch to an undefined symbol we build a
1988 stub, since NetWare will resolve undefined symbols into a
1989 pointer to a function descriptor. */
1990 if (rel->howto->pc_relative)
1991 {
1992 /* This check for whether a symbol is in the same section as
1993 the reloc will be wrong if there is a PC relative reloc
1994 between two sections both of which were placed in the
1995 same output section. This should not happen. */
1996 if (bfd_get_section (sym) != insec->output_section)
9d04d618 1997 fprintf (stderr, _("%s: unresolved PC relative reloc against %s\n"),
4bd7a65f
ILT
1998 program_name, bfd_asymbol_name (sym));
1999 else
2000 {
2001 bfd_vma val;
2002
2003 assert (rel->howto->size == 2 && rel->howto->pcrel_offset);
2004 val = bfd_get_32 (outbfd, (bfd_byte *) contents + rel->address);
2005 val = ((val &~ rel->howto->dst_mask)
2006 | (((val & rel->howto->src_mask)
2007 + (sym->value - rel->address)
2008 + rel->addend)
2009 & rel->howto->dst_mask));
2010 bfd_put_32 (outbfd, val, (bfd_byte *) contents + rel->address);
2011
ae5d2ff5
ILT
2012 /* If this reloc is against an stubbed symbol and the
2013 next instruction is
4bd7a65f
ILT
2014 cror 31,31,31
2015 then we replace the next instruction with
2016 lwz r2,20(r1)
ae5d2ff5 2017 This reloads the TOC pointer after a stub call. */
4bd7a65f 2018 if (bfd_asymbol_name (sym)[0] == '.'
ae5d2ff5 2019 && (sym->flags & BSF_DYNAMIC) != 0
4bd7a65f
ILT
2020 && (bfd_get_32 (outbfd,
2021 (bfd_byte *) contents + rel->address + 4)
2022 == 0x4ffffb82)) /* cror 31,31,31 */
2023 bfd_put_32 (outbfd, (bfd_vma) 0x80410014, /* lwz r2,20(r1) */
2024 (bfd_byte *) contents + rel->address + 4);
2025
2026 --*reloc_count_ptr;
2027 --relocs;
2028 memmove (relocs, relocs + 1,
2029 (size_t) ((reloc_count - 1) * sizeof (arelent *)));
2030 continue;
2031 }
2032 }
2033
2034 /* When considering a TOC reloc, we do not want to include the
2035 symbol value. The symbol will be start of the TOC section
2036 (which is named .got). We do want to include the addend. */
2037 if (rel->howto == toc_howto)
1d1a5a53 2038 sym_value = 0;
4bd7a65f 2039 else
1d1a5a53 2040 sym_value = sym->value;
4bd7a65f
ILT
2041
2042 /* If this is a relocation against a symbol with a value, or
2043 there is a reloc addend, we need to update the addend in the
2044 object file. */
1d1a5a53 2045 if (sym_value + rel->addend != 0)
4bd7a65f
ILT
2046 {
2047 bfd_vma val;
2048
2049 switch (rel->howto->size)
2050 {
2051 case 1:
2052 val = bfd_get_16 (outbfd,
2053 (bfd_byte *) contents + rel->address);
2054 val = ((val &~ rel->howto->dst_mask)
2055 | (((val & rel->howto->src_mask)
1d1a5a53 2056 + sym_value
4bd7a65f
ILT
2057 + rel->addend)
2058 & rel->howto->dst_mask));
2059 if ((bfd_signed_vma) val < - 0x8000
2060 || (bfd_signed_vma) val >= 0x8000)
2061 fprintf (stderr,
9d04d618 2062 _("%s: overflow when adjusting relocation against %s\n"),
4bd7a65f
ILT
2063 program_name, bfd_asymbol_name (sym));
2064 bfd_put_16 (outbfd, val, (bfd_byte *) contents + rel->address);
2065 break;
2066
2067 case 2:
2068 val = bfd_get_32 (outbfd,
2069 (bfd_byte *) contents + rel->address);
2070 val = ((val &~ rel->howto->dst_mask)
2071 | (((val & rel->howto->src_mask)
1d1a5a53 2072 + sym_value
4bd7a65f
ILT
2073 + rel->addend)
2074 & rel->howto->dst_mask));
2075 bfd_put_32 (outbfd, val, (bfd_byte *) contents + rel->address);
2076 break;
2077
2078 default:
2079 abort ();
2080 }
2081
1d1a5a53
ILT
2082 if (! bfd_is_und_section (bfd_get_section (sym)))
2083 rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
4bd7a65f
ILT
2084 rel->addend = 0;
2085 }
2086
2087 /* Now that we have incorporated the addend, remove any TOC
2088 relocs. */
2089 if (rel->howto == toc_howto)
2090 {
2091 --*reloc_count_ptr;
2092 --relocs;
2093 memmove (relocs, relocs + 1,
2094 (size_t) ((reloc_count - i) * sizeof (arelent *)));
2095 continue;
2096 }
2097
2098 rel->address += insec->output_offset;
2099 }
2100}
9d11577a
ILT
2101
2102#endif /* NLMCONV_POWERPC */
0f6df2ee
ILT
2103\f
2104/* Name of linker. */
2105#ifndef LD_NAME
2106#define LD_NAME "ld"
2107#endif
2108
2109/* Temporary file name base. */
2110static char *temp_filename;
2111
2112/* The user has specified several input files. Invoke the linker to
2113 link them all together, and convert and delete the resulting output
2114 file. */
2115
2116static char *
2117link_inputs (inputs, ld)
2118 struct string_list *inputs;
2119 char *ld;
2120{
2121 size_t c;
2122 struct string_list *q;
2123 char **argv;
2124 size_t i;
2125 int pid;
2126 int status;
1d1a5a53
ILT
2127 char *errfmt;
2128 char *errarg;
0f6df2ee
ILT
2129
2130 c = 0;
2131 for (q = inputs; q != NULL; q = q->next)
2132 ++c;
2133
1d1a5a53 2134 argv = (char **) alloca ((c + 5) * sizeof(char *));
0f6df2ee
ILT
2135
2136#ifndef __MSDOS__
2137 if (ld == NULL)
2138 {
2139 char *p;
2140
2141 /* Find the linker to invoke based on how nlmconv was run. */
2142 p = program_name + strlen (program_name);
2143 while (p != program_name)
2144 {
2145 if (p[-1] == '/')
2146 {
2147 ld = (char *) xmalloc (p - program_name + strlen (LD_NAME) + 1);
2148 memcpy (ld, program_name, p - program_name);
2149 strcpy (ld + (p - program_name), LD_NAME);
2150 break;
2151 }
2152 --p;
2153 }
2154 }
2155#endif
2156
2157 if (ld == NULL)
2158 ld = (char *) LD_NAME;
2159
1d1a5a53 2160 temp_filename = choose_temp_base ();
0f6df2ee
ILT
2161
2162 unlink_on_exit = xmalloc (strlen (temp_filename) + 3);
2163 sprintf (unlink_on_exit, "%s.O", temp_filename);
2164
2165 argv[0] = ld;
1d1a5a53 2166 argv[1] = (char *) "-Ur";
0f6df2ee
ILT
2167 argv[2] = (char *) "-o";
2168 argv[3] = unlink_on_exit;
2169 i = 4;
2170 for (q = inputs; q != NULL; q = q->next, i++)
2171 argv[i] = q->string;
2172 argv[i] = NULL;
2173
2174 if (debug)
2175 {
2176 for (i = 0; argv[i] != NULL; i++)
2177 fprintf (stderr, " %s", argv[i]);
2178 fprintf (stderr, "\n");
2179 }
2180
1d1a5a53
ILT
2181 pid = pexecute (ld, argv, program_name, (char *) NULL, &errfmt, &errarg,
2182 PEXECUTE_SEARCH | PEXECUTE_ONE);
2183 if (pid == -1)
0f6df2ee 2184 {
9d04d618 2185 fprintf (stderr, _("%s: execution of %s failed: "), program_name, ld);
1d1a5a53 2186 fprintf (stderr, errfmt, errarg);
0f6df2ee
ILT
2187 unlink (unlink_on_exit);
2188 exit (1);
2189 }
2190
1d1a5a53 2191 if (pwait (pid, &status, 0) < 0)
0f6df2ee 2192 {
1d1a5a53 2193 perror ("pwait");
0f6df2ee
ILT
2194 unlink (unlink_on_exit);
2195 exit (1);
2196 }
2197
1d1a5a53 2198 if (status != 0)
0f6df2ee 2199 {
9d04d618 2200 fprintf (stderr, _("%s: Execution of %s failed\n"), program_name, ld);
1d1a5a53 2201 unlink (unlink_on_exit);
0f6df2ee 2202 exit (1);
0f6df2ee 2203 }
0f6df2ee 2204
1d1a5a53 2205 return unlink_on_exit;
0f6df2ee 2206}
This page took 0.458984 seconds and 4 git commands to generate.