Touches most files in bfd/, so likely will be blamed for everything..
[deliverable/binutils-gdb.git] / bfd / nlm32-ppc.c
CommitLineData
252b5132 1/* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
dc810e39 2 Copyright 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
252b5132
RH
3
4This file is part of BFD, the Binary File Descriptor library.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
35static boolean nlm_powerpc_backend_object_p
36 PARAMS ((bfd *));
37static boolean nlm_powerpc_write_prefix
38 PARAMS ((bfd *));
39#endif
40
41static boolean nlm_powerpc_read_reloc
42 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
43static boolean nlm_powerpc_mangle_relocs
44 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
45static boolean nlm_powerpc_read_import
46 PARAMS ((bfd *, nlmNAME(symbol_type) *));
47
48#ifdef OLDFORMAT
49static boolean nlm_powerpc_write_reloc
50 PARAMS ((bfd *, asection *, arelent *, int));
51#endif
52
53static boolean nlm_powerpc_write_import
54 PARAMS ((bfd *, asection *, arelent *));
55static boolean nlm_powerpc_write_external
56 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
57
58#ifndef OLDFORMAT
59static boolean nlm_powerpc_set_public_section
60 PARAMS ((bfd *, nlmNAME(symbol_type) *));
61static 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
73static boolean
74nlm_powerpc_backend_object_p (abfd)
75 bfd *abfd;
76{
77 struct nlm32_powerpc_external_prefix_header s;
78
dc810e39 79 if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
252b5132
RH
80 return false;
81
82 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
dc810e39 83 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
252b5132
RH
84 return false;
85
86 return true;
87}
88
89/* Write out the prefix. */
90
91static boolean
92nlm_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);
dc810e39
AM
99 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
100 H_PUT_32 (abfd, 0, s.origins);
252b5132
RH
101
102 /* FIXME: What should we do about the date? */
103
dc810e39 104 if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
252b5132
RH
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
116static 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
133static boolean
134nlm_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
dc810e39 144 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
252b5132
RH
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, 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
200static reloc_howto_type nlm_powerpc_howto_table[] =
201{
202 /* Standard 32 bit relocation. */
1518639e
KH
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 */
252b5132 209 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
210 0, /* special_function */
211 "R_POS", /* name */
212 true, /* partial_inplace */
213 0xffffffff, /* src_mask */
214 0xffffffff, /* dst_mask */
252b5132
RH
215 false), /* pcrel_offset */
216
217 /* 32 bit relocation, but store negative value. */
1518639e
KH
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 */
252b5132 224 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
225 0, /* special_function */
226 "R_NEG", /* name */
227 true, /* partial_inplace */
228 0xffffffff, /* src_mask */
229 0xffffffff, /* dst_mask */
252b5132
RH
230 false), /* pcrel_offset */
231
232 /* 32 bit PC relative relocation. */
1518639e
KH
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 */
252b5132 239 complain_overflow_signed, /* complain_on_overflow */
1518639e
KH
240 0, /* special_function */
241 "R_REL", /* name */
242 true, /* partial_inplace */
243 0xffffffff, /* src_mask */
244 0xffffffff, /* dst_mask */
252b5132 245 false), /* pcrel_offset */
1518639e 246
252b5132 247 /* 16 bit TOC relative relocation. */
1518639e
KH
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 */
252b5132 254 complain_overflow_signed, /* complain_on_overflow */
1518639e
KH
255 0, /* special_function */
256 "R_TOC", /* name */
257 true, /* partial_inplace */
258 0xffff, /* src_mask */
259 0xffff, /* dst_mask */
252b5132 260 false), /* pcrel_offset */
1518639e 261
252b5132 262 /* I don't really know what this is. */
1518639e
KH
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 */
252b5132 269 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
270 0, /* special_function */
271 "R_RTB", /* name */
272 true, /* partial_inplace */
273 0xffffffff, /* src_mask */
274 0xffffffff, /* dst_mask */
252b5132 275 false), /* pcrel_offset */
1518639e 276
252b5132 277 /* External TOC relative symbol. */
1518639e
KH
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 */
252b5132 284 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
285 0, /* special_function */
286 "R_GL", /* name */
287 true, /* partial_inplace */
288 0xffff, /* src_mask */
289 0xffff, /* dst_mask */
252b5132 290 false), /* pcrel_offset */
1518639e 291
252b5132 292 /* Local TOC relative symbol. */
1518639e
KH
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 */
252b5132 299 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
300 0, /* special_function */
301 "R_TCL", /* name */
302 true, /* partial_inplace */
303 0xffff, /* src_mask */
304 0xffff, /* dst_mask */
252b5132 305 false), /* pcrel_offset */
1518639e 306
252b5132 307 { 7 },
1518639e 308
252b5132 309 /* Non modifiable absolute branch. */
1518639e
KH
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 */
252b5132 316 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
317 0, /* special_function */
318 "R_BA", /* name */
319 true, /* partial_inplace */
320 0x3fffffc, /* src_mask */
321 0x3fffffc, /* dst_mask */
252b5132 322 false), /* pcrel_offset */
1518639e 323
252b5132
RH
324 { 9 },
325
326 /* Non modifiable relative branch. */
1518639e
KH
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 */
252b5132 333 complain_overflow_signed, /* complain_on_overflow */
1518639e
KH
334 0, /* special_function */
335 "R_BR", /* name */
336 true, /* partial_inplace */
337 0x3fffffc, /* src_mask */
338 0x3fffffc, /* dst_mask */
252b5132 339 false), /* pcrel_offset */
1518639e 340
252b5132
RH
341 { 0xb },
342
343 /* Indirect load. */
1518639e
KH
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 */
252b5132 350 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
351 0, /* special_function */
352 "R_RL", /* name */
353 true, /* partial_inplace */
354 0xffff, /* src_mask */
355 0xffff, /* dst_mask */
252b5132 356 false), /* pcrel_offset */
1518639e 357
252b5132 358 /* Load address. */
1518639e
KH
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 */
252b5132 365 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
366 0, /* special_function */
367 "R_RLA", /* name */
368 true, /* partial_inplace */
369 0xffff, /* src_mask */
370 0xffff, /* dst_mask */
252b5132 371 false), /* pcrel_offset */
1518639e 372
252b5132 373 { 0xe },
1518639e 374
252b5132 375 /* Non-relocating reference. */
1518639e
KH
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 */
252b5132 382 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
383 0, /* special_function */
384 "R_REF", /* name */
385 false, /* partial_inplace */
386 0, /* src_mask */
387 0, /* dst_mask */
252b5132 388 false), /* pcrel_offset */
1518639e 389
252b5132
RH
390 { 0x10 },
391 { 0x11 },
1518639e 392
252b5132 393 /* TOC relative indirect load. */
1518639e
KH
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 */
252b5132 400 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
401 0, /* special_function */
402 "R_TRL", /* name */
403 true, /* partial_inplace */
404 0xffff, /* src_mask */
405 0xffff, /* dst_mask */
252b5132 406 false), /* pcrel_offset */
1518639e 407
252b5132 408 /* TOC relative load address. */
1518639e
KH
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 */
252b5132 415 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
416 0, /* special_function */
417 "R_TRLA", /* name */
418 true, /* partial_inplace */
419 0xffff, /* src_mask */
420 0xffff, /* dst_mask */
252b5132 421 false), /* pcrel_offset */
1518639e 422
252b5132 423 /* Modifiable relative branch. */
1518639e
KH
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 */
252b5132 430 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
431 0, /* special_function */
432 "R_RRTBI", /* name */
433 true, /* partial_inplace */
434 0xffffffff, /* src_mask */
435 0xffffffff, /* dst_mask */
252b5132 436 false), /* pcrel_offset */
1518639e 437
252b5132 438 /* Modifiable absolute branch. */
1518639e
KH
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 */
252b5132 445 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
446 0, /* special_function */
447 "R_RRTBA", /* name */
448 true, /* partial_inplace */
449 0xffffffff, /* src_mask */
450 0xffffffff, /* dst_mask */
252b5132 451 false), /* pcrel_offset */
1518639e 452
252b5132 453 /* Modifiable call absolute indirect. */
1518639e
KH
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 */
252b5132 460 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
461 0, /* special_function */
462 "R_CAI", /* name */
463 true, /* partial_inplace */
464 0xffff, /* src_mask */
465 0xffff, /* dst_mask */
252b5132 466 false), /* pcrel_offset */
1518639e 467
252b5132 468 /* Modifiable call relative. */
1518639e
KH
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 */
252b5132 475 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
476 0, /* special_function */
477 "R_REL", /* name */
478 true, /* partial_inplace */
479 0xffff, /* src_mask */
480 0xffff, /* dst_mask */
252b5132 481 false), /* pcrel_offset */
1518639e 482
252b5132 483 /* Modifiable branch absolute. */
1518639e
KH
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 */
252b5132 490 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
491 0, /* special_function */
492 "R_RBA", /* name */
493 true, /* partial_inplace */
494 0xffff, /* src_mask */
495 0xffff, /* dst_mask */
252b5132 496 false), /* pcrel_offset */
1518639e 497
252b5132 498 /* Modifiable branch absolute. */
1518639e
KH
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 */
252b5132 505 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
506 0, /* special_function */
507 "R_RBAC", /* name */
508 true, /* partial_inplace */
509 0xffff, /* src_mask */
510 0xffff, /* dst_mask */
252b5132 511 false), /* pcrel_offset */
1518639e 512
252b5132 513 /* Modifiable branch relative. */
1518639e
KH
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 */
252b5132 520 complain_overflow_signed, /* complain_on_overflow */
1518639e
KH
521 0, /* special_function */
522 "R_REL", /* name */
523 true, /* partial_inplace */
524 0xffff, /* src_mask */
525 0xffff, /* dst_mask */
252b5132 526 false), /* pcrel_offset */
1518639e 527
252b5132 528 /* Modifiable branch absolute. */
1518639e
KH
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 */
252b5132 535 complain_overflow_bitfield, /* complain_on_overflow */
1518639e
KH
536 0, /* special_function */
537 "R_REL", /* name */
538 true, /* partial_inplace */
539 0xffff, /* src_mask */
540 0xffff, /* dst_mask */
252b5132
RH
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
549static boolean
550nlm_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. */
dc810e39 564 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
252b5132
RH
565 return false;
566
567 /* Swap in the fields. */
dc810e39
AM
568 l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
569 l_symndx = H_GET_32 (abfd, ext.l_symndx);
570 l_rtype = H_GET_16 (abfd, ext.l_rtype);
571 l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
252b5132
RH
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
640static boolean
641nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
5f771d47
ILT
642 bfd *abfd ATTRIBUTE_UNUSED;
643 asection *sec ATTRIBUTE_UNUSED;
644 PTR data ATTRIBUTE_UNUSED;
645 bfd_vma offset ATTRIBUTE_UNUSED;
646 bfd_size_type count ATTRIBUTE_UNUSED;
252b5132
RH
647{
648 return true;
649}
650
651/* Read a PowerPC NLM import record */
652
653static boolean
654nlm_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
dc810e39 664 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
252b5132
RH
665 != sizeof (symlength))
666 return (false);
667 sym -> symbol.the_bfd = abfd;
dc810e39 668 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
252b5132
RH
669 if (name == NULL)
670 return false;
dc810e39 671 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
252b5132
RH
672 return (false);
673 name[symlength] = '\0';
674 sym -> symbol.name = name;
675 sym -> symbol.flags = 0;
676 sym -> symbol.value = 0;
677 sym -> symbol.section = bfd_und_section_ptr;
dc810e39
AM
678 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
679 != sizeof (temp))
252b5132 680 return (false);
dc810e39 681 rcount = H_GET_32 (abfd, temp);
252b5132
RH
682 nlm_relocs = ((struct nlm_relent *)
683 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
684 if (nlm_relocs == (struct nlm_relent *) NULL)
685 return false;
686 sym -> relocs = nlm_relocs;
687 sym -> rcnt = 0;
688 while (sym -> rcnt < rcount)
689 {
690 asection *section;
1518639e 691
252b5132
RH
692 if (nlm_powerpc_read_reloc (abfd, sym, &section,
693 &nlm_relocs -> reloc)
694 == false)
695 return false;
696 nlm_relocs -> section = section;
697 nlm_relocs++;
698 sym -> rcnt++;
699 }
700 return true;
701}
702
703#ifndef OLDFORMAT
704
705/* Write a PowerPC NLM reloc. */
706
707static boolean
708nlm_powerpc_write_import (abfd, sec, rel)
709 bfd *abfd;
710 asection *sec;
711 arelent *rel;
712{
713 asymbol *sym;
714 bfd_vma val;
715 bfd_byte temp[4];
716
717 /* PowerPC NetWare only supports one kind of reloc. */
718 if (rel->addend != 0
719 || rel->howto == NULL
720 || rel->howto->rightshift != 0
721 || rel->howto->size != 2
722 || rel->howto->bitsize != 32
723 || rel->howto->bitpos != 0
724 || rel->howto->pc_relative
725 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
726 || rel->howto->dst_mask != 0xffffffff)
727 {
728 bfd_set_error (bfd_error_invalid_operation);
729 return false;
730 }
731
732 sym = *rel->sym_ptr_ptr;
733
734 /* The value we write out is the offset into the appropriate
735 segment, rightshifted by two. This offset is the section vma,
736 adjusted by the vma of the lowest section in that segment, plus
737 the address of the relocation. */
738 val = bfd_get_section_vma (abfd, sec) + rel->address;
739 if ((val & 3) != 0)
740 {
741 bfd_set_error (bfd_error_bad_value);
742 return false;
743 }
744 val >>= 2;
745
746 /* The high bit is 0 if the reloc is in the data section, or 1 if
747 the reloc is in the code section. */
748 if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
749 val -= nlm_get_data_low (abfd);
750 else
751 {
752 val -= nlm_get_text_low (abfd);
753 val |= NLM_HIBIT;
754 }
1518639e 755
252b5132
RH
756 if (! bfd_is_und_section (bfd_get_section (sym)))
757 {
758 /* This is an internal relocation fixup. The second most
759 significant bit is 0 if this is a reloc against the data
760 segment, or 1 if it is a reloc against the text segment. */
761 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
762 val |= NLM_HIBIT >> 1;
763 }
764
765 bfd_put_32 (abfd, val, temp);
dc810e39 766 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
252b5132
RH
767 return false;
768
769 return true;
770}
771
772#else /* OLDFORMAT */
773
774/* This is used for the reloc handling in the old format. */
775
776/* Write a PowerPC NLM reloc. */
777
778static boolean
779nlm_powerpc_write_reloc (abfd, sec, rel, indx)
780 bfd *abfd;
781 asection *sec;
782 arelent *rel;
783 int indx;
784{
785 struct nlm32_powerpc_external_reloc ext;
786 asection *code_sec, *data_sec, *bss_sec;
787 asymbol *sym;
788 asection *symsec;
789 unsigned long l_symndx;
790 int l_rtype;
791 int l_rsecnm;
792 reloc_howto_type *howto;
793 bfd_size_type address;
794
795 /* Get the sections now, for convenience. */
796 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
797 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
798 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
799
800 sym = *rel->sym_ptr_ptr;
801 symsec = bfd_get_section (sym);
802 if (indx != -1)
803 {
804 BFD_ASSERT (bfd_is_und_section (symsec));
805 l_symndx = indx + 3;
806 }
807 else
808 {
809 if (symsec == code_sec)
810 l_symndx = 0;
811 else if (symsec == data_sec)
812 l_symndx = 1;
813 else if (symsec == bss_sec)
814 l_symndx = 2;
815 else
816 {
817 bfd_set_error (bfd_error_bad_value);
818 return false;
819 }
820 }
821
dc810e39 822 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
252b5132
RH
823
824 for (howto = nlm_powerpc_howto_table;
825 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
826 howto++)
827 {
828 if (howto->rightshift == rel->howto->rightshift
829 && howto->size == rel->howto->size
830 && howto->bitsize == rel->howto->bitsize
831 && howto->pc_relative == rel->howto->pc_relative
832 && howto->bitpos == rel->howto->bitpos
833 && (howto->partial_inplace == rel->howto->partial_inplace
834 || (! rel->howto->partial_inplace
835 && rel->addend == 0))
836 && (howto->src_mask == rel->howto->src_mask
837 || (rel->howto->src_mask == 0
838 && rel->addend == 0))
839 && howto->dst_mask == rel->howto->dst_mask
840 && howto->pcrel_offset == rel->howto->pcrel_offset)
841 break;
842 }
843 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
844 {
845 bfd_set_error (bfd_error_bad_value);
846 return false;
847 }
848
849 l_rtype = howto->type;
850 if (howto->complain_on_overflow == complain_overflow_signed)
851 l_rtype |= 0x8000;
852 l_rtype |= (howto->bitsize - 1) << 8;
dc810e39 853 H_PUT_16 (abfd, l_rtype, ext.l_rtype);
252b5132
RH
854
855 address = rel->address;
856
857 if (sec == code_sec)
858 l_rsecnm = 0;
859 else if (sec == data_sec)
860 {
861 l_rsecnm = 1;
862 address += bfd_section_size (abfd, code_sec);
863 }
864 else
865 {
866 bfd_set_error (bfd_error_bad_value);
867 return false;
868 }
869
dc810e39
AM
870 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
871 H_PUT_32 (abfd, address, ext.l_vaddr);
252b5132 872
dc810e39 873 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
252b5132
RH
874 return false;
875
876 return true;
877}
878
879/* Write a PowerPC NLM import. */
880
881static boolean
882nlm_powerpc_write_import (abfd, sec, rel)
883 bfd *abfd;
884 asection *sec;
885 arelent *rel;
886{
887 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
888}
889
890#endif /* OLDFORMAT */
891
892/* Write a PowerPC NLM external symbol. This routine keeps a static
893 count of the symbol index. FIXME: I don't know if this is
894 necessary, and the index never gets reset. */
895
896static boolean
897nlm_powerpc_write_external (abfd, count, sym, relocs)
898 bfd *abfd;
899 bfd_size_type count;
900 asymbol *sym;
901 struct reloc_and_sec *relocs;
902{
903 unsigned int i;
904 bfd_byte len;
905 unsigned char temp[NLM_TARGET_LONG_SIZE];
906#ifdef OLDFORMAT
907 static int indx;
908#endif
909
910 len = strlen (sym->name);
dc810e39
AM
911 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
912 != sizeof (bfd_byte))
913 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
252b5132
RH
914 return false;
915
916 bfd_put_32 (abfd, count, temp);
dc810e39 917 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
252b5132
RH
918 return false;
919
920 for (i = 0; i < count; i++)
921 {
922#ifndef OLDFORMAT
923 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
924 return false;
925#else
926 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
927 relocs[i].rel, indx))
928 return false;
929#endif
930 }
931
932#ifdef OLDFORMAT
933 ++indx;
934#endif
935
936 return true;
937}
938\f
939#ifndef OLDFORMAT
940
941/* PowerPC Netware uses a word offset, not a byte offset, for public
942 symbols. */
943
944/* Set the section for a public symbol. */
945
946static boolean
947nlm_powerpc_set_public_section (abfd, sym)
948 bfd *abfd;
949 nlmNAME(symbol_type) *sym;
950{
951 if (sym->symbol.value & NLM_HIBIT)
952 {
953 sym->symbol.value &= ~NLM_HIBIT;
954 sym->symbol.flags |= BSF_FUNCTION;
955 sym->symbol.section =
956 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
957 }
958 else
959 {
960 sym->symbol.section =
961 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
962 }
963
964 sym->symbol.value <<= 2;
965
966 return true;
967}
968
969/* Get the offset to write out for a public symbol. */
970
971static bfd_vma
972nlm_powerpc_get_public_offset (abfd, sym)
973 bfd *abfd;
974 asymbol *sym;
975{
976 bfd_vma offset;
977 asection *sec;
978
979 offset = bfd_asymbol_value (sym);
980 sec = bfd_get_section (sym);
981 if (sec->flags & SEC_CODE)
982 {
983 offset -= nlm_get_text_low (abfd);
984 offset |= NLM_HIBIT;
985 }
986 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
987 {
988 /* SEC_ALLOC is for the .bss section. */
989 offset -= nlm_get_data_low (abfd);
990 }
991 else
992 {
993 /* We can't handle an exported symbol that is not in the code or
994 data segment. */
995 bfd_set_error (bfd_error_invalid_operation);
996 /* FIXME: No way to return error. */
997 abort ();
998 }
999
1000 return offset;
1001}
1002
1003#endif /* ! defined (OLDFORMAT) */
1004\f
1005#include "nlmswap.h"
1006
1007static const struct nlm_backend_data nlm32_powerpc_backend =
1008{
1009 "NetWare PowerPC Module \032",
1010 sizeof (Nlm32_powerpc_External_Fixed_Header),
1011#ifndef OLDFORMAT
1012 0, /* optional_prefix_size */
1013#else
1014 sizeof (struct nlm32_powerpc_external_prefix_header),
1015#endif
1016 bfd_arch_powerpc,
1017 0,
1018 false,
1019#ifndef OLDFORMAT
1020 0, /* backend_object_p */
1021 0, /* write_prefix */
1022#else
1023 nlm_powerpc_backend_object_p,
1024 nlm_powerpc_write_prefix,
1025#endif
1026 nlm_powerpc_read_reloc,
1027 nlm_powerpc_mangle_relocs,
1028 nlm_powerpc_read_import,
1029 nlm_powerpc_write_import,
1030#ifndef OLDFORMAT
1031 nlm_powerpc_set_public_section,
1032 nlm_powerpc_get_public_offset,
1033#else
1034 0, /* set_public_section */
1035 0, /* get_public_offset */
1036#endif
1037 nlm_swap_fixed_header_in,
1038 nlm_swap_fixed_header_out,
1039 nlm_powerpc_write_external,
1040 0, /* write_export */
1041};
1042
1043#define TARGET_BIG_NAME "nlm32-powerpc"
1044#define TARGET_BIG_SYM nlmNAME(powerpc_vec)
1045#define TARGET_BACKEND_DATA &nlm32_powerpc_backend
1046
1047#include "nlm-target.h"
This page took 0.188821 seconds and 4 git commands to generate.