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