]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/nlm32-alpha.c
* libbfd.c (bfd_read): Set bfd_error as appropriate for a short
[thirdparty/binutils-gdb.git] / bfd / nlm32-alpha.c
1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2 Copyright (C) 1993 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 /* This file describes the 32 bit Alpha NLM format. You might think
22 that an Alpha chip would use a 64 bit format, but, for some reason,
23 it doesn't. */
24
25 #include "bfd.h"
26 #include "sysdep.h"
27 #include "libbfd.h"
28
29 #define ARCH_SIZE 32
30
31 #include "nlm/alpha-ext.h"
32 #define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header
33
34 #include "libnlm.h"
35
36 static boolean nlm_alpha_backend_object_p
37 PARAMS ((bfd *));
38 static boolean nlm_alpha_write_prefix
39 PARAMS ((bfd *));
40 static boolean nlm_alpha_read_reloc
41 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
42 static boolean nlm_alpha_mangle_relocs
43 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
44 static boolean nlm_alpha_read_import
45 PARAMS ((bfd *, nlmNAME(symbol_type) *));
46 static boolean nlm_alpha_write_import
47 PARAMS ((bfd *, asection *, arelent *));
48 static boolean nlm_alpha_set_public_section
49 PARAMS ((bfd *, nlmNAME(symbol_type) *));
50 static bfd_vma nlm_alpha_get_public_offset
51 PARAMS ((bfd *, asymbol *));
52 static boolean nlm_alpha_write_external
53 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
54 \f
55 /* Alpha NLM's have a prefix header before the standard NLM. This
56 function reads it in, verifies the version, and seeks the bfd to
57 the location before the regular NLM header. */
58
59 static boolean
60 nlm_alpha_backend_object_p (abfd)
61 bfd *abfd;
62 {
63 struct nlm32_alpha_external_prefix_header s;
64 bfd_size_type size;
65
66 if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
67 return false;
68
69 if (bfd_h_get_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
70 return false;
71
72 /* FIXME: Should we check the format number? */
73
74 /* Skip to the end of the header. */
75 size = bfd_h_get_32 (abfd, s.size);
76 if (bfd_seek (abfd, size, SEEK_SET) != 0)
77 return false;
78
79 return true;
80 }
81
82 /* Write out the prefix. */
83
84 static boolean
85 nlm_alpha_write_prefix (abfd)
86 bfd *abfd;
87 {
88 struct nlm32_alpha_external_prefix_header s;
89
90 memset (&s, 0, sizeof s);
91 bfd_h_put_32 (abfd, (bfd_vma) NLM32_ALPHA_MAGIC, s.magic);
92 bfd_h_put_32 (abfd, (bfd_vma) 2, s.format);
93 bfd_h_put_32 (abfd, (bfd_vma) sizeof s, s.size);
94 if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
95 return false;
96 return true;
97 }
98 \f
99 /* How to process the various reloc types. */
100
101 static reloc_howto_type nlm32_alpha_howto_table[] =
102 {
103 /* Reloc type 0 is ignored by itself. However, it appears after a
104 GPDISP reloc to identify the location where the low order 16 bits
105 of the gp register are loaded. */
106 HOWTO (ALPHA_R_IGNORE, /* type */
107 0, /* rightshift */
108 0, /* size (0 = byte, 1 = short, 2 = long) */
109 8, /* bitsize */
110 false, /* pc_relative */
111 0, /* bitpos */
112 complain_overflow_dont, /* complain_on_overflow */
113 0, /* special_function */
114 "IGNORE", /* name */
115 false, /* partial_inplace */
116 0, /* src_mask */
117 0, /* dst_mask */
118 false), /* pcrel_offset */
119
120 /* A 32 bit reference to a symbol. */
121 HOWTO (ALPHA_R_REFLONG, /* type */
122 0, /* rightshift */
123 2, /* size (0 = byte, 1 = short, 2 = long) */
124 32, /* bitsize */
125 false, /* pc_relative */
126 0, /* bitpos */
127 complain_overflow_bitfield, /* complain_on_overflow */
128 0, /* special_function */
129 "REFLONG", /* name */
130 true, /* partial_inplace */
131 0xffffffff, /* src_mask */
132 0xffffffff, /* dst_mask */
133 false), /* pcrel_offset */
134
135 /* A 64 bit reference to a symbol. */
136 HOWTO (ALPHA_R_REFQUAD, /* type */
137 0, /* rightshift */
138 4, /* size (0 = byte, 1 = short, 2 = long) */
139 64, /* bitsize */
140 false, /* pc_relative */
141 0, /* bitpos */
142 complain_overflow_bitfield, /* complain_on_overflow */
143 0, /* special_function */
144 "REFQUAD", /* name */
145 true, /* partial_inplace */
146 0xffffffffffffffff, /* src_mask */
147 0xffffffffffffffff, /* dst_mask */
148 false), /* pcrel_offset */
149
150 /* A 32 bit GP relative offset. This is just like REFLONG except
151 that when the value is used the value of the gp register will be
152 added in. */
153 HOWTO (ALPHA_R_GPREL32, /* type */
154 0, /* rightshift */
155 2, /* size (0 = byte, 1 = short, 2 = long) */
156 32, /* bitsize */
157 false, /* pc_relative */
158 0, /* bitpos */
159 complain_overflow_bitfield, /* complain_on_overflow */
160 0, /* special_function */
161 "GPREL32", /* name */
162 true, /* partial_inplace */
163 0xffffffff, /* src_mask */
164 0xffffffff, /* dst_mask */
165 false), /* pcrel_offset */
166
167 /* Used for an instruction that refers to memory off the GP
168 register. The offset is 16 bits of the 32 bit instruction. This
169 reloc always seems to be against the .lita section. */
170 HOWTO (ALPHA_R_LITERAL, /* type */
171 0, /* rightshift */
172 2, /* size (0 = byte, 1 = short, 2 = long) */
173 16, /* bitsize */
174 false, /* pc_relative */
175 0, /* bitpos */
176 complain_overflow_signed, /* complain_on_overflow */
177 0, /* special_function */
178 "LITERAL", /* name */
179 true, /* partial_inplace */
180 0xffff, /* src_mask */
181 0xffff, /* dst_mask */
182 false), /* pcrel_offset */
183
184 /* This reloc only appears immediately following a LITERAL reloc.
185 It identifies a use of the literal. It seems that the linker can
186 use this to eliminate a portion of the .lita section. The symbol
187 index is special: 1 means the literal address is in the base
188 register of a memory format instruction; 2 means the literal
189 address is in the byte offset register of a byte-manipulation
190 instruction; 3 means the literal address is in the target
191 register of a jsr instruction. This does not actually do any
192 relocation. */
193 HOWTO (ALPHA_R_LITUSE, /* type */
194 0, /* rightshift */
195 2, /* size (0 = byte, 1 = short, 2 = long) */
196 32, /* bitsize */
197 false, /* pc_relative */
198 0, /* bitpos */
199 complain_overflow_dont, /* complain_on_overflow */
200 0, /* special_function */
201 "LITUSE", /* name */
202 false, /* partial_inplace */
203 0, /* src_mask */
204 0, /* dst_mask */
205 false), /* pcrel_offset */
206
207 /* Load the gp register. This is always used for a ldah instruction
208 which loads the upper 16 bits of the gp register. The next reloc
209 will be an IGNORE reloc which identifies the location of the lda
210 instruction which loads the lower 16 bits. The symbol index of
211 the GPDISP instruction appears to actually be the number of bytes
212 between the ldah and lda instructions. This gives two different
213 ways to determine where the lda instruction is; I don't know why
214 both are used. The value to use for the relocation is the
215 difference between the GP value and the current location; the
216 load will always be done against a register holding the current
217 address. */
218 HOWTO (ALPHA_R_GPDISP, /* type */
219 16, /* rightshift */
220 2, /* size (0 = byte, 1 = short, 2 = long) */
221 16, /* bitsize */
222 true, /* pc_relative */
223 0, /* bitpos */
224 complain_overflow_dont, /* complain_on_overflow */
225 0, /* special_function */
226 "GPDISP", /* name */
227 true, /* partial_inplace */
228 0xffff, /* src_mask */
229 0xffff, /* dst_mask */
230 true), /* pcrel_offset */
231
232 /* A 21 bit branch. The native assembler generates these for
233 branches within the text segment, and also fills in the PC
234 relative offset in the instruction. It seems to me that this
235 reloc, unlike the others, is not partial_inplace. */
236 HOWTO (ALPHA_R_BRADDR, /* type */
237 2, /* rightshift */
238 2, /* size (0 = byte, 1 = short, 2 = long) */
239 21, /* bitsize */
240 true, /* pc_relative */
241 0, /* bitpos */
242 complain_overflow_signed, /* complain_on_overflow */
243 0, /* special_function */
244 "BRADDR", /* name */
245 false, /* partial_inplace */
246 0, /* src_mask */
247 0x1fffff, /* dst_mask */
248 false), /* pcrel_offset */
249
250 /* A hint for a jump to a register. */
251 HOWTO (ALPHA_R_HINT, /* type */
252 2, /* rightshift */
253 2, /* size (0 = byte, 1 = short, 2 = long) */
254 14, /* bitsize */
255 false, /* pc_relative */
256 0, /* bitpos */
257 complain_overflow_dont, /* complain_on_overflow */
258 0, /* special_function */
259 "HINT", /* name */
260 true, /* partial_inplace */
261 0x3fff, /* src_mask */
262 0x3fff, /* dst_mask */
263 false), /* pcrel_offset */
264
265 /* 16 bit PC relative offset. */
266 HOWTO (ALPHA_R_SREL16, /* type */
267 0, /* rightshift */
268 1, /* size (0 = byte, 1 = short, 2 = long) */
269 16, /* bitsize */
270 true, /* pc_relative */
271 0, /* bitpos */
272 complain_overflow_signed, /* complain_on_overflow */
273 0, /* special_function */
274 "SREL16", /* name */
275 true, /* partial_inplace */
276 0xffff, /* src_mask */
277 0xffff, /* dst_mask */
278 false), /* pcrel_offset */
279
280 /* 32 bit PC relative offset. */
281 HOWTO (ALPHA_R_SREL32, /* type */
282 0, /* rightshift */
283 2, /* size (0 = byte, 1 = short, 2 = long) */
284 32, /* bitsize */
285 true, /* pc_relative */
286 0, /* bitpos */
287 complain_overflow_signed, /* complain_on_overflow */
288 0, /* special_function */
289 "SREL32", /* name */
290 true, /* partial_inplace */
291 0xffffffff, /* src_mask */
292 0xffffffff, /* dst_mask */
293 false), /* pcrel_offset */
294
295 /* A 64 bit PC relative offset. */
296 HOWTO (ALPHA_R_SREL64, /* type */
297 0, /* rightshift */
298 4, /* size (0 = byte, 1 = short, 2 = long) */
299 64, /* bitsize */
300 true, /* pc_relative */
301 0, /* bitpos */
302 complain_overflow_signed, /* complain_on_overflow */
303 0, /* special_function */
304 "SREL64", /* name */
305 true, /* partial_inplace */
306 0xffffffffffffffff, /* src_mask */
307 0xffffffffffffffff, /* dst_mask */
308 false), /* pcrel_offset */
309
310 /* Push a value on the reloc evaluation stack. */
311 HOWTO (ALPHA_R_OP_PUSH, /* type */
312 0, /* rightshift */
313 0, /* size (0 = byte, 1 = short, 2 = long) */
314 0, /* bitsize */
315 false, /* pc_relative */
316 0, /* bitpos */
317 complain_overflow_dont, /* complain_on_overflow */
318 0, /* special_function */
319 "OP_PUSH", /* name */
320 false, /* partial_inplace */
321 0, /* src_mask */
322 0, /* dst_mask */
323 false), /* pcrel_offset */
324
325 /* Store the value from the stack at the given address. Store it in
326 a bitfield of size r_size starting at bit position r_offset. */
327 HOWTO (ALPHA_R_OP_STORE, /* type */
328 0, /* rightshift */
329 4, /* size (0 = byte, 1 = short, 2 = long) */
330 64, /* bitsize */
331 false, /* pc_relative */
332 0, /* bitpos */
333 complain_overflow_dont, /* complain_on_overflow */
334 0, /* special_function */
335 "OP_STORE", /* name */
336 false, /* partial_inplace */
337 0, /* src_mask */
338 0xffffffffffffffff, /* dst_mask */
339 false), /* pcrel_offset */
340
341 /* Subtract the reloc address from the value on the top of the
342 relocation stack. */
343 HOWTO (ALPHA_R_OP_PSUB, /* type */
344 0, /* rightshift */
345 0, /* size (0 = byte, 1 = short, 2 = long) */
346 0, /* bitsize */
347 false, /* pc_relative */
348 0, /* bitpos */
349 complain_overflow_dont, /* complain_on_overflow */
350 0, /* special_function */
351 "OP_PSUB", /* name */
352 false, /* partial_inplace */
353 0, /* src_mask */
354 0, /* dst_mask */
355 false), /* pcrel_offset */
356
357 /* Shift the value on the top of the relocation stack right by the
358 given value. */
359 HOWTO (ALPHA_R_OP_PRSHIFT, /* type */
360 0, /* rightshift */
361 0, /* size (0 = byte, 1 = short, 2 = long) */
362 0, /* bitsize */
363 false, /* pc_relative */
364 0, /* bitpos */
365 complain_overflow_dont, /* complain_on_overflow */
366 0, /* special_function */
367 "OP_PRSHIFT", /* name */
368 false, /* partial_inplace */
369 0, /* src_mask */
370 0, /* dst_mask */
371 false), /* pcrel_offset */
372
373 /* Adjust the GP value for a new range in the object file. */
374 HOWTO (ALPHA_R_GPVALUE, /* type */
375 0, /* rightshift */
376 0, /* size (0 = byte, 1 = short, 2 = long) */
377 0, /* bitsize */
378 false, /* pc_relative */
379 0, /* bitpos */
380 complain_overflow_dont, /* complain_on_overflow */
381 0, /* special_function */
382 "GPVALUE", /* name */
383 false, /* partial_inplace */
384 0, /* src_mask */
385 0, /* dst_mask */
386 false) /* pcrel_offset */
387 };
388
389 static reloc_howto_type nlm32_alpha_nw_howto =
390 HOWTO (ALPHA_R_NW_RELOC, /* type */
391 0, /* rightshift */
392 0, /* size (0 = byte, 1 = short, 2 = long) */
393 0, /* bitsize */
394 false, /* pc_relative */
395 0, /* bitpos */
396 complain_overflow_dont, /* complain_on_overflow */
397 0, /* special_function */
398 "NW_RELOC", /* name */
399 false, /* partial_inplace */
400 0, /* src_mask */
401 0, /* dst_mask */
402 false); /* pcrel_offset */
403
404 /* Read an Alpha NLM reloc. This routine keeps some static data which
405 it uses when handling local relocs. This only works correctly
406 because all the local relocs are read at once. */
407
408 static boolean
409 nlm_alpha_read_reloc (abfd, sym, secp, rel)
410 bfd *abfd;
411 nlmNAME(symbol_type) *sym;
412 asection **secp;
413 arelent *rel;
414 {
415 static bfd_vma gp_value;
416 static bfd_vma lita_address;
417 struct nlm32_alpha_external_reloc ext;
418 bfd_vma r_vaddr;
419 long r_symndx;
420 int r_type, r_extern, r_offset, r_size;
421 asection *code_sec, *data_sec;
422
423 /* Read the reloc from the file. */
424 if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
425 return false;
426
427 /* Swap in the reloc information. */
428 r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext.r_vaddr);
429 r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext.r_symndx);
430
431 BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false);
432
433 r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
434 >> RELOC_BITS0_TYPE_SH_LITTLE);
435 r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;
436 r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)
437 >> RELOC_BITS1_OFFSET_SH_LITTLE);
438 /* Ignore the reserved bits. */
439 r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE)
440 >> RELOC_BITS3_SIZE_SH_LITTLE);
441
442 /* Fill in the BFD arelent structure. */
443 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
444 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
445 if (r_extern)
446 {
447 /* External relocations are only used for imports. */
448 BFD_ASSERT (sym != NULL);
449 /* We don't need to set sym_ptr_ptr for this case. It is set in
450 nlm_canonicalize_reloc. */
451 rel->sym_ptr_ptr = NULL;
452 rel->addend = 0;
453 }
454 else
455 {
456 /* Internal relocations are only used for local relocation
457 fixups. If they are not NW_RELOC or GPDISP or IGNORE, they
458 must be against .text or .data. */
459 BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL);
460 if (r_type == ALPHA_R_NW_RELOC
461 || r_type == ALPHA_R_GPDISP
462 || r_type == ALPHA_R_IGNORE)
463 {
464 rel->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
465 rel->addend = 0;
466 }
467 else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
468 {
469 rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr;
470 BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0);
471 rel->addend = 0;
472 }
473 else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
474 {
475 rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
476 rel->addend = - bfd_get_section_vma (abfd, data_sec);
477 }
478 else
479 {
480 BFD_ASSERT (0);
481 rel->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
482 rel->addend = 0;
483 }
484 }
485
486 /* We use the address to determine whether the reloc is in the .text
487 or .data section. R_NW_RELOC relocs don't really have a section,
488 so we put them in .text. */
489 if (r_type == ALPHA_R_NW_RELOC
490 || r_vaddr < bfd_section_size (abfd, code_sec))
491 {
492 *secp = code_sec;
493 rel->address = r_vaddr;
494 }
495 else
496 {
497 *secp = data_sec;
498 rel->address = r_vaddr - bfd_section_size (abfd, code_sec);
499 }
500
501 /* We must adjust the addend based on the type. */
502 BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE)
503 || r_type == ALPHA_R_NW_RELOC);
504
505 switch (r_type)
506 {
507 case ALPHA_R_BRADDR:
508 case ALPHA_R_SREL16:
509 case ALPHA_R_SREL32:
510 case ALPHA_R_SREL64:
511 /* The PC relative relocs do not seem to use the section VMA as
512 a negative addend. */
513 rel->addend = 0;
514 break;
515
516 case ALPHA_R_GPREL32:
517 /* Copy the gp value for this object file into the addend, to
518 ensure that we are not confused by the linker. */
519 if (! r_extern)
520 rel->addend += gp_value;
521 break;
522
523 case ALPHA_R_LITERAL:
524 BFD_ASSERT (! r_extern);
525 rel->addend += lita_address;
526 break;
527
528 case ALPHA_R_LITUSE:
529 case ALPHA_R_GPDISP:
530 /* The LITUSE and GPDISP relocs do not use a symbol, or an
531 addend, but they do use a special code. Put this code in the
532 addend field. */
533 rel->addend = r_symndx;
534 rel->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
535 break;
536
537 case ALPHA_R_OP_STORE:
538 /* The STORE reloc needs the size and offset fields. We store
539 them in the addend. */
540 BFD_ASSERT (r_offset < 256 && r_size < 256);
541 rel->addend = (r_offset << 8) + r_size;
542 break;
543
544 case ALPHA_R_OP_PUSH:
545 case ALPHA_R_OP_PSUB:
546 case ALPHA_R_OP_PRSHIFT:
547 /* The PUSH, PSUB and PRSHIFT relocs do not actually use an
548 address. I believe that the address supplied is really an
549 addend. */
550 rel->addend = r_vaddr;
551 break;
552
553 case ALPHA_R_GPVALUE:
554 /* Record the new gp value. */
555 gp_value += r_symndx;
556 rel->addend = gp_value;
557 break;
558
559 case ALPHA_R_IGNORE:
560 /* If the type is ALPHA_R_IGNORE, make sure this is a reference
561 to the absolute section so that the reloc is ignored. For
562 some reason the address of this reloc type is not adjusted by
563 the section vma. We record the gp value for this object file
564 here, for convenience when doing the GPDISP relocation. */
565 rel->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
566 rel->address = r_vaddr;
567 rel->addend = gp_value;
568 break;
569
570 case ALPHA_R_NW_RELOC:
571 /* If this is SETGP, we set the addend to 0. Otherwise we set
572 the addend to the size of the .lita section (this is
573 r_symndx) plus 1. We have already set the address of the
574 reloc to r_vaddr. */
575 if (r_size == ALPHA_R_NW_RELOC_SETGP)
576 {
577 gp_value = r_vaddr;
578 rel->addend = 0;
579 }
580 else if (r_size == ALPHA_R_NW_RELOC_LITA)
581 {
582 lita_address = r_vaddr;
583 rel->addend = r_symndx + 1;
584 }
585 else
586 BFD_ASSERT (0);
587 rel->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
588 break;
589
590 default:
591 break;
592 }
593
594 if (r_type == ALPHA_R_NW_RELOC)
595 rel->howto = &nlm32_alpha_nw_howto;
596 else
597 rel->howto = &nlm32_alpha_howto_table[r_type];
598
599 return true;
600 }
601
602 /* Mangle Alpha NLM relocs for output. */
603
604 static boolean
605 nlm_alpha_mangle_relocs (abfd, sec, data, offset, count)
606 bfd *abfd;
607 asection *sec;
608 PTR data;
609 bfd_vma offset;
610 bfd_size_type count;
611 {
612 return true;
613 }
614
615 /* Read an ALPHA NLM import record */
616
617 static boolean
618 nlm_alpha_read_import (abfd, sym)
619 bfd *abfd;
620 nlmNAME(symbol_type) *sym;
621 {
622 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
623 bfd_size_type rcount; /* number of relocs */
624 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
625 unsigned char symlength; /* length of symbol name */
626
627 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
628 != sizeof (symlength))
629 return false;
630 sym -> symbol.the_bfd = abfd;
631 sym -> symbol.name = bfd_alloc (abfd, symlength + 1);
632 if (!sym -> symbol.name)
633 {
634 bfd_set_error (bfd_error_no_memory);
635 return false;
636 }
637 if (bfd_read ((PTR) sym -> symbol.name, symlength, 1, abfd)
638 != symlength)
639 return false;
640 sym -> symbol.flags = 0;
641 sym -> symbol.value = 0;
642 sym -> symbol.section = &bfd_und_section;
643 if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
644 return faflse;
645 rcount = bfd_h_get_32 (abfd, temp);
646 nlm_relocs = ((struct nlm_relent *)
647 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
648 if (!nlm_relocs)
649 {
650 bfd_set_error (bfd_error_no_memory);
651 return false;
652 }
653 sym -> relocs = nlm_relocs;
654 sym -> rcnt = 0;
655 while (sym -> rcnt < rcount)
656 {
657 asection *section;
658
659 if (nlm_alpha_read_reloc (abfd, sym, &section,
660 &nlm_relocs -> reloc)
661 == false)
662 return false;
663 nlm_relocs -> section = section;
664 nlm_relocs++;
665 sym -> rcnt++;
666 }
667
668 return true;
669 }
670
671 /* Write an Alpha NLM reloc. */
672
673 static boolean
674 nlm_alpha_write_import (abfd, sec, rel)
675 bfd *abfd;
676 asection *sec;
677 arelent *rel;
678 {
679 asymbol *sym;
680 bfd_vma r_vaddr;
681 long r_symndx;
682 int r_type, r_extern, r_offset, r_size;
683 struct nlm32_alpha_external_reloc ext;
684
685 sym = *rel->sym_ptr_ptr;
686
687 /* Get values for the relocation fields. */
688 r_type = rel->howto->type;
689 if (r_type != ALPHA_R_NW_RELOC)
690 {
691 r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
692 if ((sec->flags & SEC_CODE) == 0)
693 r_vaddr += bfd_section_size (abfd,
694 bfd_get_section_by_name (abfd,
695 NLM_CODE_NAME));
696 if (bfd_get_section (sym) == &bfd_und_section)
697 {
698 r_extern = 1;
699 r_symndx = 0;
700 }
701 else
702 {
703 r_extern = 0;
704 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
705 r_symndx = ALPHA_RELOC_SECTION_TEXT;
706 else
707 r_symndx = ALPHA_RELOC_SECTION_DATA;
708 }
709 r_offset = 0;
710 r_size = 0;
711
712 switch (r_type)
713 {
714 case ALPHA_R_LITUSE:
715 case ALPHA_R_GPDISP:
716 r_symndx = rel->addend;
717 break;
718
719 case ALPHA_R_OP_STORE:
720 r_size = rel->addend & 0xff;
721 r_offset = (rel->addend >> 8) & 0xff;
722 break;
723
724 case ALPHA_R_OP_PUSH:
725 case ALPHA_R_OP_PSUB:
726 case ALPHA_R_OP_PRSHIFT:
727 r_vaddr = rel->addend;
728 break;
729
730 case ALPHA_R_IGNORE:
731 r_vaddr = rel->address;
732 break;
733
734 default:
735 break;
736 }
737 }
738 else
739 {
740 /* r_type == ALPHA_R_NW_RELOC */
741 r_vaddr = rel->address;
742 if (rel->addend == 0)
743 {
744 r_symndx = 0;
745 r_size = ALPHA_R_NW_RELOC_SETGP;
746 }
747 else
748 {
749 r_symndx = rel->addend - 1;
750 r_size = ALPHA_R_NW_RELOC_LITA;
751 }
752 r_extern = 0;
753 r_offset = 0;
754 }
755
756 /* Swap out the relocation fields. */
757 bfd_h_put_64 (abfd, r_vaddr, (bfd_byte *) ext.r_vaddr);
758 bfd_h_put_32 (abfd, r_symndx, (bfd_byte *) ext.r_symndx);
759
760 BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false);
761
762 ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
763 & RELOC_BITS0_TYPE_LITTLE);
764 ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
765 | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
766 & RELOC_BITS1_OFFSET_LITTLE));
767 ext.r_bits[2] = 0;
768 ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
769 & RELOC_BITS3_SIZE_LITTLE);
770
771 /* Write out the relocation. */
772 if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
773 return false;
774
775 return true;
776 }
777 \f
778 /* Alpha NetWare does not use the high bit to determine whether a
779 public symbol is in the code segment or the data segment. Instead,
780 it just uses the address. The set_public_section and
781 get_public_offset routines override the default code which uses the
782 high bit. */
783
784 /* Set the section for a public symbol. */
785
786 static boolean
787 nlm_alpha_set_public_section (abfd, sym)
788 bfd *abfd;
789 nlmNAME(symbol_type) *sym;
790 {
791 asection *code_sec, *data_sec;
792
793 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
794 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
795 if (sym->symbol.value < bfd_section_size (abfd, code_sec))
796 {
797 sym->symbol.section = code_sec;
798 sym->symbol.flags |= BSF_FUNCTION;
799 }
800 else
801 {
802 sym->symbol.section = data_sec;
803 sym->symbol.value -= bfd_section_size (abfd, code_sec);
804 /* The data segment had better be aligned. */
805 BFD_ASSERT ((bfd_section_size (abfd, code_sec) & 0xf) == 0);
806 }
807 return true;
808 }
809
810 /* Get the offset to write out for a public symbol. */
811
812 static bfd_vma
813 nlm_alpha_get_public_offset (abfd, sym)
814 bfd *abfd;
815 asymbol *sym;
816 {
817 return bfd_asymbol_value (sym);
818 }
819 \f
820 /* Write an Alpha NLM external symbol. */
821
822 static boolean
823 nlm_alpha_write_external (abfd, count, sym, relocs)
824 bfd *abfd;
825 bfd_size_type count;
826 asymbol *sym;
827 struct reloc_and_sec *relocs;
828 {
829 int i;
830 bfd_byte len;
831 unsigned char temp[NLM_TARGET_LONG_SIZE];
832 arelent r;
833
834 len = strlen (sym->name);
835 if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
836 || bfd_write (sym->name, len, 1, abfd) != len)
837 return false;
838
839 bfd_put_32 (abfd, count + 2, temp);
840 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
841 return false;
842
843 /* The first two relocs for each external symbol are the .lita
844 address and the GP value. */
845 r.sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
846 r.howto = &nlm32_alpha_nw_howto;
847
848 r.address = nlm_alpha_backend_data (abfd)->lita_address;
849 r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
850 if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
851 return false;
852
853 r.address = nlm_alpha_backend_data (abfd)->gp;
854 r.addend = 0;
855 if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
856 return false;
857
858 for (i = 0; i < count; i++)
859 {
860 if (nlm_alpha_write_import (abfd, relocs[i].sec,
861 relocs[i].rel) == false)
862 return false;
863 }
864
865 return true;
866 }
867
868 #include "nlmswap.h"
869
870 static const struct nlm_backend_data nlm32_alpha_backend =
871 {
872 "NetWare Alpha Module \032",
873 sizeof (Nlm32_alpha_External_Fixed_Header),
874 sizeof (struct nlm32_alpha_external_prefix_header),
875 bfd_arch_alpha,
876 0,
877 true, /* no uninitialized data permitted by Alpha NetWare. */
878 nlm_alpha_backend_object_p,
879 nlm_alpha_write_prefix,
880 nlm_alpha_read_reloc,
881 nlm_alpha_mangle_relocs,
882 nlm_alpha_read_import,
883 nlm_alpha_write_import,
884 nlm_alpha_set_public_section,
885 nlm_alpha_get_public_offset,
886 nlm_swap_fixed_header_in,
887 nlm_swap_fixed_header_out,
888 nlm_alpha_write_external,
889 0, /* write_export */
890 };
891
892 #define TARGET_LITTLE_NAME "nlm32-alpha"
893 #define TARGET_LITTLE_SYM nlmNAME(alpha_vec)
894 #define TARGET_BACKEND_DATA &nlm32_alpha_backend
895
896 #include "nlm-target.h"