This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / bfd / nlm32-ppc.c
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright (C) 1994 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23
24 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
25 old format. */
26
27 #define ARCH_SIZE 32
28
29 #include "nlm/ppc-ext.h"
30 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
31
32 #include "libnlm.h"
33
34 #ifdef OLDFORMAT
35 static boolean nlm_powerpc_backend_object_p
36 PARAMS ((bfd *));
37 static boolean nlm_powerpc_write_prefix
38 PARAMS ((bfd *));
39 #endif
40
41 static boolean nlm_powerpc_read_reloc
42 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
43 static boolean nlm_powerpc_mangle_relocs
44 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
45 static boolean nlm_powerpc_read_import
46 PARAMS ((bfd *, nlmNAME(symbol_type) *));
47
48 #ifdef OLDFORMAT
49 static boolean nlm_powerpc_write_reloc
50 PARAMS ((bfd *, asection *, arelent *, int));
51 #endif
52
53 static boolean nlm_powerpc_write_import
54 PARAMS ((bfd *, asection *, arelent *));
55 static boolean nlm_powerpc_write_external
56 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
57
58 #ifndef OLDFORMAT
59 static boolean nlm_powerpc_set_public_section
60 PARAMS ((bfd *, nlmNAME(symbol_type) *));
61 static bfd_vma nlm_powerpc_get_public_offset
62 PARAMS ((bfd *, asymbol *));
63 #endif
64 \f
65 #ifdef OLDFORMAT
66
67 /* The prefix header is only used in the old format. */
68
69 /* PowerPC NLM's have a prefix header before the standard NLM. This
70 function reads it in, verifies the version, and seeks the bfd to
71 the location before the regular NLM header. */
72
73 static boolean
74 nlm_powerpc_backend_object_p (abfd)
75 bfd *abfd;
76 {
77 struct nlm32_powerpc_external_prefix_header s;
78
79 if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
80 return false;
81
82 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
83 || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
84 return false;
85
86 return true;
87 }
88
89 /* Write out the prefix. */
90
91 static boolean
92 nlm_powerpc_write_prefix (abfd)
93 bfd *abfd;
94 {
95 struct nlm32_powerpc_external_prefix_header s;
96
97 memset (&s, 0, sizeof s);
98 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
99 bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
100 bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins);
101
102 /* FIXME: What should we do about the date? */
103
104 if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
105 return false;
106
107 return true;
108 }
109
110 #endif /* OLDFORMAT */
111 \f
112 #ifndef OLDFORMAT
113
114 /* There is only one type of reloc in a PowerPC NLM. */
115
116 static reloc_howto_type nlm_powerpc_howto =
117 HOWTO (0, /* type */
118 0, /* rightshift */
119 2, /* size (0 = byte, 1 = short, 2 = long) */
120 32, /* bitsize */
121 false, /* pc_relative */
122 0, /* bitpos */
123 complain_overflow_bitfield, /* complain_on_overflow */
124 0, /* special_function */
125 "32", /* name */
126 true, /* partial_inplace */
127 0xffffffff, /* src_mask */
128 0xffffffff, /* dst_mask */
129 false); /* pcrel_offset */
130
131 /* Read a PowerPC NLM reloc. */
132
133 static boolean
134 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
135 bfd *abfd;
136 nlmNAME(symbol_type) *sym;
137 asection **secp;
138 arelent *rel;
139 {
140 bfd_byte temp[4];
141 bfd_vma val;
142 const char *name;
143
144 if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
145 return false;
146
147 val = bfd_get_32 (abfd, temp);
148
149 /* The value is a word offset into either the code or data segment.
150 This is the location which needs to be adjusted.
151
152 The high bit is 0 if the value is an offset into the data
153 segment, or 1 if the value is an offset into the text segment.
154
155 If this is a relocation fixup rather than an imported symbol (the
156 sym argument is NULL), then the second most significant bit is 0
157 if the address of the data segment should be added to the
158 location addressed by the value, or 1 if the address of the text
159 segment should be added.
160
161 If this is an imported symbol, the second most significant bit is
162 not used and must be 0. */
163
164 if ((val & NLM_HIBIT) == 0)
165 name = NLM_INITIALIZED_DATA_NAME;
166 else
167 {
168 name = NLM_CODE_NAME;
169 val &=~ NLM_HIBIT;
170 }
171 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
172
173 if (sym == NULL)
174 {
175 if ((val & (NLM_HIBIT >> 1)) == 0)
176 name = NLM_INITIALIZED_DATA_NAME;
177 else
178 {
179 name = NLM_CODE_NAME;
180 val &=~ (NLM_HIBIT >> 1);
181 }
182 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
183 }
184
185 rel->howto = &nlm_powerpc_howto;
186
187 rel->address = val << 2;
188 rel->addend = 0;
189
190 return true;
191 }
192
193 #else /* OLDFORMAT */
194
195 /* This reloc handling is only applicable to the old format. */
196
197 /* How to process the various reloc types. PowerPC NLMs use XCOFF
198 reloc types, and I have just copied the XCOFF reloc table here. */
199
200 static reloc_howto_type nlm_powerpc_howto_table[] =
201 {
202 /* Standard 32 bit relocation. */
203 HOWTO (0, /* type */
204 0, /* rightshift */
205 2, /* size (0 = byte, 1 = short, 2 = long) */
206 32, /* bitsize */
207 false, /* pc_relative */
208 0, /* bitpos */
209 complain_overflow_bitfield, /* complain_on_overflow */
210 0, /* special_function */
211 "R_POS", /* name */
212 true, /* partial_inplace */
213 0xffffffff, /* src_mask */
214 0xffffffff, /* dst_mask */
215 false), /* pcrel_offset */
216
217 /* 32 bit relocation, but store negative value. */
218 HOWTO (1, /* type */
219 0, /* rightshift */
220 -2, /* size (0 = byte, 1 = short, 2 = long) */
221 32, /* bitsize */
222 false, /* pc_relative */
223 0, /* bitpos */
224 complain_overflow_bitfield, /* complain_on_overflow */
225 0, /* special_function */
226 "R_NEG", /* name */
227 true, /* partial_inplace */
228 0xffffffff, /* src_mask */
229 0xffffffff, /* dst_mask */
230 false), /* pcrel_offset */
231
232 /* 32 bit PC relative relocation. */
233 HOWTO (2, /* type */
234 0, /* rightshift */
235 2, /* size (0 = byte, 1 = short, 2 = long) */
236 32, /* bitsize */
237 true, /* pc_relative */
238 0, /* bitpos */
239 complain_overflow_signed, /* complain_on_overflow */
240 0, /* special_function */
241 "R_REL", /* name */
242 true, /* partial_inplace */
243 0xffffffff, /* src_mask */
244 0xffffffff, /* dst_mask */
245 false), /* pcrel_offset */
246
247 /* 16 bit TOC relative relocation. */
248 HOWTO (3, /* type */
249 0, /* rightshift */
250 1, /* size (0 = byte, 1 = short, 2 = long) */
251 16, /* bitsize */
252 false, /* pc_relative */
253 0, /* bitpos */
254 complain_overflow_signed, /* complain_on_overflow */
255 0, /* special_function */
256 "R_TOC", /* name */
257 true, /* partial_inplace */
258 0xffff, /* src_mask */
259 0xffff, /* dst_mask */
260 false), /* pcrel_offset */
261
262 /* I don't really know what this is. */
263 HOWTO (4, /* type */
264 1, /* rightshift */
265 2, /* size (0 = byte, 1 = short, 2 = long) */
266 32, /* bitsize */
267 false, /* pc_relative */
268 0, /* bitpos */
269 complain_overflow_bitfield, /* complain_on_overflow */
270 0, /* special_function */
271 "R_RTB", /* name */
272 true, /* partial_inplace */
273 0xffffffff, /* src_mask */
274 0xffffffff, /* dst_mask */
275 false), /* pcrel_offset */
276
277 /* External TOC relative symbol. */
278 HOWTO (5, /* type */
279 0, /* rightshift */
280 2, /* size (0 = byte, 1 = short, 2 = long) */
281 16, /* bitsize */
282 false, /* pc_relative */
283 0, /* bitpos */
284 complain_overflow_bitfield, /* complain_on_overflow */
285 0, /* special_function */
286 "R_GL", /* name */
287 true, /* partial_inplace */
288 0xffff, /* src_mask */
289 0xffff, /* dst_mask */
290 false), /* pcrel_offset */
291
292 /* Local TOC relative symbol. */
293 HOWTO (6, /* type */
294 0, /* rightshift */
295 2, /* size (0 = byte, 1 = short, 2 = long) */
296 16, /* bitsize */
297 false, /* pc_relative */
298 0, /* bitpos */
299 complain_overflow_bitfield, /* complain_on_overflow */
300 0, /* special_function */
301 "R_TCL", /* name */
302 true, /* partial_inplace */
303 0xffff, /* src_mask */
304 0xffff, /* dst_mask */
305 false), /* pcrel_offset */
306
307 { 7 },
308
309 /* Non modifiable absolute branch. */
310 HOWTO (8, /* type */
311 0, /* rightshift */
312 2, /* size (0 = byte, 1 = short, 2 = long) */
313 26, /* bitsize */
314 false, /* pc_relative */
315 0, /* bitpos */
316 complain_overflow_bitfield, /* complain_on_overflow */
317 0, /* special_function */
318 "R_BA", /* name */
319 true, /* partial_inplace */
320 0x3fffffc, /* src_mask */
321 0x3fffffc, /* dst_mask */
322 false), /* pcrel_offset */
323
324 { 9 },
325
326 /* Non modifiable relative branch. */
327 HOWTO (0xa, /* type */
328 0, /* rightshift */
329 2, /* size (0 = byte, 1 = short, 2 = long) */
330 26, /* bitsize */
331 true, /* pc_relative */
332 0, /* bitpos */
333 complain_overflow_signed, /* complain_on_overflow */
334 0, /* special_function */
335 "R_BR", /* name */
336 true, /* partial_inplace */
337 0x3fffffc, /* src_mask */
338 0x3fffffc, /* dst_mask */
339 false), /* pcrel_offset */
340
341 { 0xb },
342
343 /* Indirect load. */
344 HOWTO (0xc, /* type */
345 0, /* rightshift */
346 2, /* size (0 = byte, 1 = short, 2 = long) */
347 16, /* bitsize */
348 false, /* pc_relative */
349 0, /* bitpos */
350 complain_overflow_bitfield, /* complain_on_overflow */
351 0, /* special_function */
352 "R_RL", /* name */
353 true, /* partial_inplace */
354 0xffff, /* src_mask */
355 0xffff, /* dst_mask */
356 false), /* pcrel_offset */
357
358 /* Load address. */
359 HOWTO (0xd, /* type */
360 0, /* rightshift */
361 2, /* size (0 = byte, 1 = short, 2 = long) */
362 16, /* bitsize */
363 false, /* pc_relative */
364 0, /* bitpos */
365 complain_overflow_bitfield, /* complain_on_overflow */
366 0, /* special_function */
367 "R_RLA", /* name */
368 true, /* partial_inplace */
369 0xffff, /* src_mask */
370 0xffff, /* dst_mask */
371 false), /* pcrel_offset */
372
373 { 0xe },
374
375 /* Non-relocating reference. */
376 HOWTO (0xf, /* type */
377 0, /* rightshift */
378 2, /* size (0 = byte, 1 = short, 2 = long) */
379 32, /* bitsize */
380 false, /* pc_relative */
381 0, /* bitpos */
382 complain_overflow_bitfield, /* complain_on_overflow */
383 0, /* special_function */
384 "R_REF", /* name */
385 false, /* partial_inplace */
386 0, /* src_mask */
387 0, /* dst_mask */
388 false), /* pcrel_offset */
389
390 { 0x10 },
391 { 0x11 },
392
393 /* TOC relative indirect load. */
394 HOWTO (0x12, /* type */
395 0, /* rightshift */
396 2, /* size (0 = byte, 1 = short, 2 = long) */
397 16, /* bitsize */
398 false, /* pc_relative */
399 0, /* bitpos */
400 complain_overflow_bitfield, /* complain_on_overflow */
401 0, /* special_function */
402 "R_TRL", /* name */
403 true, /* partial_inplace */
404 0xffff, /* src_mask */
405 0xffff, /* dst_mask */
406 false), /* pcrel_offset */
407
408 /* TOC relative load address. */
409 HOWTO (0x13, /* type */
410 0, /* rightshift */
411 2, /* size (0 = byte, 1 = short, 2 = long) */
412 16, /* bitsize */
413 false, /* pc_relative */
414 0, /* bitpos */
415 complain_overflow_bitfield, /* complain_on_overflow */
416 0, /* special_function */
417 "R_TRLA", /* name */
418 true, /* partial_inplace */
419 0xffff, /* src_mask */
420 0xffff, /* dst_mask */
421 false), /* pcrel_offset */
422
423 /* Modifiable relative branch. */
424 HOWTO (0x14, /* type */
425 1, /* rightshift */
426 2, /* size (0 = byte, 1 = short, 2 = long) */
427 32, /* bitsize */
428 false, /* pc_relative */
429 0, /* bitpos */
430 complain_overflow_bitfield, /* complain_on_overflow */
431 0, /* special_function */
432 "R_RRTBI", /* name */
433 true, /* partial_inplace */
434 0xffffffff, /* src_mask */
435 0xffffffff, /* dst_mask */
436 false), /* pcrel_offset */
437
438 /* Modifiable absolute branch. */
439 HOWTO (0x15, /* type */
440 1, /* rightshift */
441 2, /* size (0 = byte, 1 = short, 2 = long) */
442 32, /* bitsize */
443 false, /* pc_relative */
444 0, /* bitpos */
445 complain_overflow_bitfield, /* complain_on_overflow */
446 0, /* special_function */
447 "R_RRTBA", /* name */
448 true, /* partial_inplace */
449 0xffffffff, /* src_mask */
450 0xffffffff, /* dst_mask */
451 false), /* pcrel_offset */
452
453 /* Modifiable call absolute indirect. */
454 HOWTO (0x16, /* type */
455 0, /* rightshift */
456 2, /* size (0 = byte, 1 = short, 2 = long) */
457 16, /* bitsize */
458 false, /* pc_relative */
459 0, /* bitpos */
460 complain_overflow_bitfield, /* complain_on_overflow */
461 0, /* special_function */
462 "R_CAI", /* name */
463 true, /* partial_inplace */
464 0xffff, /* src_mask */
465 0xffff, /* dst_mask */
466 false), /* pcrel_offset */
467
468 /* Modifiable call relative. */
469 HOWTO (0x17, /* type */
470 0, /* rightshift */
471 2, /* size (0 = byte, 1 = short, 2 = long) */
472 16, /* bitsize */
473 false, /* pc_relative */
474 0, /* bitpos */
475 complain_overflow_bitfield, /* complain_on_overflow */
476 0, /* special_function */
477 "R_REL", /* name */
478 true, /* partial_inplace */
479 0xffff, /* src_mask */
480 0xffff, /* dst_mask */
481 false), /* pcrel_offset */
482
483 /* Modifiable branch absolute. */
484 HOWTO (0x18, /* type */
485 0, /* rightshift */
486 2, /* size (0 = byte, 1 = short, 2 = long) */
487 16, /* bitsize */
488 false, /* pc_relative */
489 0, /* bitpos */
490 complain_overflow_bitfield, /* complain_on_overflow */
491 0, /* special_function */
492 "R_RBA", /* name */
493 true, /* partial_inplace */
494 0xffff, /* src_mask */
495 0xffff, /* dst_mask */
496 false), /* pcrel_offset */
497
498 /* Modifiable branch absolute. */
499 HOWTO (0x19, /* type */
500 0, /* rightshift */
501 2, /* size (0 = byte, 1 = short, 2 = long) */
502 16, /* bitsize */
503 false, /* pc_relative */
504 0, /* bitpos */
505 complain_overflow_bitfield, /* complain_on_overflow */
506 0, /* special_function */
507 "R_RBAC", /* name */
508 true, /* partial_inplace */
509 0xffff, /* src_mask */
510 0xffff, /* dst_mask */
511 false), /* pcrel_offset */
512
513 /* Modifiable branch relative. */
514 HOWTO (0x1a, /* type */
515 0, /* rightshift */
516 2, /* size (0 = byte, 1 = short, 2 = long) */
517 26, /* bitsize */
518 false, /* pc_relative */
519 0, /* bitpos */
520 complain_overflow_signed, /* complain_on_overflow */
521 0, /* special_function */
522 "R_REL", /* name */
523 true, /* partial_inplace */
524 0xffff, /* src_mask */
525 0xffff, /* dst_mask */
526 false), /* pcrel_offset */
527
528 /* Modifiable branch absolute. */
529 HOWTO (0x1b, /* type */
530 0, /* rightshift */
531 2, /* size (0 = byte, 1 = short, 2 = long) */
532 16, /* bitsize */
533 false, /* pc_relative */
534 0, /* bitpos */
535 complain_overflow_bitfield, /* complain_on_overflow */
536 0, /* special_function */
537 "R_REL", /* name */
538 true, /* partial_inplace */
539 0xffff, /* src_mask */
540 0xffff, /* dst_mask */
541 false) /* pcrel_offset */
542 };
543
544 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
545 / sizeof nlm_powerpc_howto_table[0])
546
547 /* Read a PowerPC NLM reloc. */
548
549 static boolean
550 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
551 bfd *abfd;
552 nlmNAME(symbol_type) *sym;
553 asection **secp;
554 arelent *rel;
555 {
556 struct nlm32_powerpc_external_reloc ext;
557 bfd_vma l_vaddr;
558 unsigned long l_symndx;
559 int l_rtype;
560 int l_rsecnm;
561 asection *code_sec, *data_sec, *bss_sec;
562
563 /* Read the reloc from the file. */
564 if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
565 return false;
566
567 /* Swap in the fields. */
568 l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
569 l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
570 l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
571 l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
572
573 /* Get the sections now, for convenience. */
574 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
575 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
576 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
577
578 /* Work out the arelent fields. */
579 if (sym != NULL)
580 {
581 /* This is an import. sym_ptr_ptr is filled in by
582 nlm_canonicalize_reloc. */
583 rel->sym_ptr_ptr = NULL;
584 }
585 else
586 {
587 asection *sec;
588
589 if (l_symndx == 0)
590 sec = code_sec;
591 else if (l_symndx == 1)
592 sec = data_sec;
593 else if (l_symndx == 2)
594 sec = bss_sec;
595 else
596 {
597 bfd_set_error (bfd_error_bad_value);
598 return false;
599 }
600
601 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
602 }
603
604 rel->addend = 0;
605
606 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
607
608 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
609
610 BFD_ASSERT (rel->howto->name != NULL
611 && ((l_rtype & 0x8000) != 0
612 ? (rel->howto->complain_on_overflow
613 == complain_overflow_signed)
614 : (rel->howto->complain_on_overflow
615 == complain_overflow_bitfield))
616 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
617
618 if (l_rsecnm == 0)
619 *secp = code_sec;
620 else if (l_rsecnm == 1)
621 {
622 *secp = data_sec;
623 l_vaddr -= bfd_section_size (abfd, code_sec);
624 }
625 else
626 {
627 bfd_set_error (bfd_error_bad_value);
628 return false;
629 }
630
631 rel->address = l_vaddr;
632
633 return true;
634 }
635
636 #endif /* OLDFORMAT */
637
638 /* Mangle PowerPC NLM relocs for output. */
639
640 static boolean
641 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
642 bfd *abfd;
643 asection *sec;
644 PTR data;
645 bfd_vma offset;
646 bfd_size_type count;
647 {
648 return true;
649 }
650
651 /* Read a PowerPC NLM import record */
652
653 static boolean
654 nlm_powerpc_read_import (abfd, sym)
655 bfd *abfd;
656 nlmNAME(symbol_type) *sym;
657 {
658 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
659 bfd_size_type rcount; /* number of relocs */
660 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
661 unsigned char symlength; /* length of symbol name */
662 char *name;
663
664 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
665 != sizeof (symlength))
666 return (false);
667 sym -> symbol.the_bfd = abfd;
668 name = bfd_alloc (abfd, symlength + 1);
669 if (name == NULL)
670 {
671 bfd_set_error (bfd_error_no_memory);
672 return false;
673 }
674 if (bfd_read (name, symlength, 1, abfd) != symlength)
675 return (false);
676 name[symlength] = '\0';
677 sym -> symbol.name = name;
678 sym -> symbol.flags = 0;
679 sym -> symbol.value = 0;
680 sym -> symbol.section = &bfd_und_section;
681 if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
682 return (false);
683 rcount = bfd_h_get_32 (abfd, temp);
684 nlm_relocs = ((struct nlm_relent *)
685 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
686 if (nlm_relocs == (struct nlm_relent *) NULL)
687 {
688 bfd_set_error (bfd_error_no_memory);
689 return false;
690 }
691 sym -> relocs = nlm_relocs;
692 sym -> rcnt = 0;
693 while (sym -> rcnt < rcount)
694 {
695 asection *section;
696
697 if (nlm_powerpc_read_reloc (abfd, sym, &section,
698 &nlm_relocs -> reloc)
699 == false)
700 return false;
701 nlm_relocs -> section = section;
702 nlm_relocs++;
703 sym -> rcnt++;
704 }
705 return true;
706 }
707
708 #ifndef OLDFORMAT
709
710 /* Write a PowerPC NLM reloc. */
711
712 static boolean
713 nlm_powerpc_write_import (abfd, sec, rel)
714 bfd *abfd;
715 asection *sec;
716 arelent *rel;
717 {
718 asymbol *sym;
719 bfd_vma val;
720 bfd_byte temp[4];
721
722 /* PowerPC NetWare only supports one kind of reloc. */
723 if (rel->addend != 0
724 || rel->howto == NULL
725 || rel->howto->rightshift != 0
726 || rel->howto->size != 2
727 || rel->howto->bitsize != 32
728 || rel->howto->bitpos != 0
729 || rel->howto->pc_relative
730 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
731 || rel->howto->dst_mask != 0xffffffff)
732 {
733 bfd_set_error (bfd_error_invalid_operation);
734 return false;
735 }
736
737 sym = *rel->sym_ptr_ptr;
738
739 /* The value we write out is the offset into the appropriate
740 segment, rightshifted by two. This offset is the section vma,
741 adjusted by the vma of the lowest section in that segment, plus
742 the address of the relocation. */
743 val = bfd_get_section_vma (abfd, sec) + rel->address;
744 if ((val & 3) != 0)
745 {
746 bfd_set_error (bfd_error_bad_value);
747 return false;
748 }
749 val >>= 2;
750
751 /* The high bit is 0 if the reloc is in the data section, or 1 if
752 the reloc is in the code section. */
753 if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
754 val -= nlm_get_data_low (abfd);
755 else
756 {
757 val -= nlm_get_text_low (abfd);
758 val |= NLM_HIBIT;
759 }
760
761 if (bfd_get_section (sym) != &bfd_und_section)
762 {
763 /* This is an internal relocation fixup. The second most
764 significant bit is 0 if this is a reloc against the data
765 segment, or 1 if it is a reloc against the text segment. */
766 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
767 val |= NLM_HIBIT >> 1;
768 }
769
770 bfd_put_32 (abfd, val, temp);
771 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
772 return false;
773
774 return true;
775 }
776
777 #else /* OLDFORMAT */
778
779 /* This is used for the reloc handling in the old format. */
780
781 /* Write a PowerPC NLM reloc. */
782
783 static boolean
784 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
785 bfd *abfd;
786 asection *sec;
787 arelent *rel;
788 int indx;
789 {
790 struct nlm32_powerpc_external_reloc ext;
791 asection *code_sec, *data_sec, *bss_sec;
792 asymbol *sym;
793 asection *symsec;
794 unsigned long l_symndx;
795 int l_rtype;
796 int l_rsecnm;
797 const reloc_howto_type *howto;
798 bfd_size_type address;
799
800 /* Get the sections now, for convenience. */
801 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
802 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
803 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
804
805 sym = *rel->sym_ptr_ptr;
806 symsec = bfd_get_section (sym);
807 if (indx != -1)
808 {
809 BFD_ASSERT (symsec == &bfd_und_section);
810 l_symndx = indx + 3;
811 }
812 else
813 {
814 if (symsec == code_sec)
815 l_symndx = 0;
816 else if (symsec == data_sec)
817 l_symndx = 1;
818 else if (symsec == bss_sec)
819 l_symndx = 2;
820 else
821 {
822 bfd_set_error (bfd_error_bad_value);
823 return false;
824 }
825 }
826
827 bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
828
829 for (howto = nlm_powerpc_howto_table;
830 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
831 howto++)
832 {
833 if (howto->rightshift == rel->howto->rightshift
834 && howto->size == rel->howto->size
835 && howto->bitsize == rel->howto->bitsize
836 && howto->pc_relative == rel->howto->pc_relative
837 && howto->bitpos == rel->howto->bitpos
838 && (howto->partial_inplace == rel->howto->partial_inplace
839 || (! rel->howto->partial_inplace
840 && rel->addend == 0))
841 && (howto->src_mask == rel->howto->src_mask
842 || (rel->howto->src_mask == 0
843 && rel->addend == 0))
844 && howto->dst_mask == rel->howto->dst_mask
845 && howto->pcrel_offset == rel->howto->pcrel_offset)
846 break;
847 }
848 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
849 {
850 bfd_set_error (bfd_error_bad_value);
851 return false;
852 }
853
854 l_rtype = howto->type;
855 if (howto->complain_on_overflow == complain_overflow_signed)
856 l_rtype |= 0x8000;
857 l_rtype |= (howto->bitsize - 1) << 8;
858 bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
859
860 address = rel->address;
861
862 if (sec == code_sec)
863 l_rsecnm = 0;
864 else if (sec == data_sec)
865 {
866 l_rsecnm = 1;
867 address += bfd_section_size (abfd, code_sec);
868 }
869 else
870 {
871 bfd_set_error (bfd_error_bad_value);
872 return false;
873 }
874
875 bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
876 bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
877
878 if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
879 return false;
880
881 return true;
882 }
883
884 /* Write a PowerPC NLM import. */
885
886 static boolean
887 nlm_powerpc_write_import (abfd, sec, rel)
888 bfd *abfd;
889 asection *sec;
890 arelent *rel;
891 {
892 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
893 }
894
895 #endif /* OLDFORMAT */
896
897 /* Write a PowerPC NLM external symbol. This routine keeps a static
898 count of the symbol index. FIXME: I don't know if this is
899 necessary, and the index never gets reset. */
900
901 static boolean
902 nlm_powerpc_write_external (abfd, count, sym, relocs)
903 bfd *abfd;
904 bfd_size_type count;
905 asymbol *sym;
906 struct reloc_and_sec *relocs;
907 {
908 int i;
909 bfd_byte len;
910 unsigned char temp[NLM_TARGET_LONG_SIZE];
911 #ifdef OLDFORMAT
912 static int indx;
913 #endif
914
915 len = strlen (sym->name);
916 if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
917 || bfd_write (sym->name, len, 1, abfd) != len)
918 return false;
919
920 bfd_put_32 (abfd, count, temp);
921 if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
922 return false;
923
924 for (i = 0; i < count; i++)
925 {
926 #ifndef OLDFORMAT
927 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
928 return false;
929 #else
930 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
931 relocs[i].rel, indx))
932 return false;
933 #endif
934 }
935
936 #ifdef OLDFORMAT
937 ++indx;
938 #endif
939
940 return true;
941 }
942 \f
943 #ifndef OLDFORMAT
944
945 /* PowerPC Netware uses a word offset, not a byte offset, for public
946 symbols. */
947
948 /* Set the section for a public symbol. */
949
950 static boolean
951 nlm_powerpc_set_public_section (abfd, sym)
952 bfd *abfd;
953 nlmNAME(symbol_type) *sym;
954 {
955 if (sym->symbol.value & NLM_HIBIT)
956 {
957 sym->symbol.value &= ~NLM_HIBIT;
958 sym->symbol.flags |= BSF_FUNCTION;
959 sym->symbol.section =
960 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
961 }
962 else
963 {
964 sym->symbol.section =
965 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
966 }
967
968 sym->symbol.value <<= 2;
969
970 return true;
971 }
972
973 /* Get the offset to write out for a public symbol. */
974
975 static bfd_vma
976 nlm_powerpc_get_public_offset (abfd, sym)
977 bfd *abfd;
978 asymbol *sym;
979 {
980 bfd_vma offset;
981 asection *sec;
982
983 offset = bfd_asymbol_value (sym);
984 sec = bfd_get_section (sym);
985 if (sec->flags & SEC_CODE)
986 {
987 offset -= nlm_get_text_low (abfd);
988 offset |= NLM_HIBIT;
989 }
990 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
991 {
992 /* SEC_ALLOC is for the .bss section. */
993 offset -= nlm_get_data_low (abfd);
994 }
995 else
996 {
997 /* We can't handle an exported symbol that is not in the code or
998 data segment. */
999 bfd_set_error (bfd_error_invalid_operation);
1000 /* FIXME: No way to return error. */
1001 abort ();
1002 }
1003
1004 return offset;
1005 }
1006
1007 #endif /* ! defined (OLDFORMAT) */
1008 \f
1009 #include "nlmswap.h"
1010
1011 static const struct nlm_backend_data nlm32_powerpc_backend =
1012 {
1013 "NetWare PowerPC Module \032",
1014 sizeof (Nlm32_powerpc_External_Fixed_Header),
1015 #ifndef OLDFORMAT
1016 0, /* optional_prefix_size */
1017 #else
1018 sizeof (struct nlm32_powerpc_external_prefix_header),
1019 #endif
1020 bfd_arch_powerpc,
1021 0,
1022 false,
1023 #ifndef OLDFORMAT
1024 0, /* backend_object_p */
1025 0, /* write_prefix */
1026 #else
1027 nlm_powerpc_backend_object_p,
1028 nlm_powerpc_write_prefix,
1029 #endif
1030 nlm_powerpc_read_reloc,
1031 nlm_powerpc_mangle_relocs,
1032 nlm_powerpc_read_import,
1033 nlm_powerpc_write_import,
1034 #ifndef OLDFORMAT
1035 nlm_powerpc_set_public_section,
1036 nlm_powerpc_get_public_offset,
1037 #else
1038 0, /* set_public_section */
1039 0, /* get_public_offset */
1040 #endif
1041 nlm_swap_fixed_header_in,
1042 nlm_swap_fixed_header_out,
1043 nlm_powerpc_write_external,
1044 0, /* write_export */
1045 };
1046
1047 #define TARGET_BIG_NAME "nlm32-powerpc"
1048 #define TARGET_BIG_SYM nlmNAME(powerpc_vec)
1049 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend
1050
1051 #include "nlm-target.h"
This page took 0.079691 seconds and 5 git commands to generate.