s/boolean/bfd_boolean/ s/true/TRUE/ s/false/FALSE/. Simplify
[deliverable/binutils-gdb.git] / bfd / nlm32-alpha.c
CommitLineData
252b5132 1/* Support for 32-bit Alpha NLM (NetWare Loadable Module)
82e51918 2 Copyright 1993, 1994, 2000, 2001, 2002 Free Software Foundation, Inc.
252b5132
RH
3 Written by Ian Lance Taylor, Cygnus Support.
4
5This file is part of BFD, the Binary File Descriptor library.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
b34976b6 36static bfd_boolean nlm_alpha_backend_object_p
252b5132 37 PARAMS ((bfd *));
b34976b6 38static bfd_boolean nlm_alpha_write_prefix
252b5132 39 PARAMS ((bfd *));
b34976b6 40static bfd_boolean nlm_alpha_read_reloc
252b5132 41 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
b34976b6 42static bfd_boolean nlm_alpha_mangle_relocs
252b5132 43 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
b34976b6 44static bfd_boolean nlm_alpha_read_import
252b5132 45 PARAMS ((bfd *, nlmNAME(symbol_type) *));
b34976b6 46static bfd_boolean nlm_alpha_write_import
252b5132 47 PARAMS ((bfd *, asection *, arelent *));
b34976b6 48static bfd_boolean nlm_alpha_set_public_section
252b5132
RH
49 PARAMS ((bfd *, nlmNAME(symbol_type) *));
50static bfd_vma nlm_alpha_get_public_offset
51 PARAMS ((bfd *, asymbol *));
b34976b6 52static bfd_boolean nlm_alpha_write_external
252b5132
RH
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
b34976b6 59static bfd_boolean
252b5132
RH
60nlm_alpha_backend_object_p (abfd)
61 bfd *abfd;
62{
63 struct nlm32_alpha_external_prefix_header s;
dc810e39 64 file_ptr size;
252b5132 65
dc810e39 66 if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6 67 return FALSE;
252b5132 68
dc810e39 69 if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
b34976b6 70 return FALSE;
252b5132
RH
71
72 /* FIXME: Should we check the format number? */
73
74 /* Skip to the end of the header. */
dc810e39 75 size = H_GET_32 (abfd, s.size);
252b5132 76 if (bfd_seek (abfd, size, SEEK_SET) != 0)
b34976b6 77 return FALSE;
252b5132 78
b34976b6 79 return TRUE;
252b5132
RH
80}
81
82/* Write out the prefix. */
83
b34976b6 84static bfd_boolean
252b5132
RH
85nlm_alpha_write_prefix (abfd)
86 bfd *abfd;
87{
88 struct nlm32_alpha_external_prefix_header s;
89
90 memset (&s, 0, sizeof s);
dc810e39
AM
91 H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
92 H_PUT_32 (abfd, 2, s.format);
93 H_PUT_32 (abfd, sizeof s, s.size);
94 if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6
AM
95 return FALSE;
96 return TRUE;
252b5132
RH
97}
98\f
99/* How to process the various reloc types. */
100
101static 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 */
b34976b6 110 FALSE, /* pc_relative */
252b5132
RH
111 0, /* bitpos */
112 complain_overflow_dont, /* complain_on_overflow */
113 0, /* special_function */
114 "IGNORE", /* name */
b34976b6 115 FALSE, /* partial_inplace */
252b5132
RH
116 0, /* src_mask */
117 0, /* dst_mask */
b34976b6 118 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 125 FALSE, /* pc_relative */
252b5132
RH
126 0, /* bitpos */
127 complain_overflow_bitfield, /* complain_on_overflow */
128 0, /* special_function */
129 "REFLONG", /* name */
b34976b6 130 TRUE, /* partial_inplace */
252b5132
RH
131 0xffffffff, /* src_mask */
132 0xffffffff, /* dst_mask */
b34976b6 133 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 140 FALSE, /* pc_relative */
252b5132
RH
141 0, /* bitpos */
142 complain_overflow_bitfield, /* complain_on_overflow */
143 0, /* special_function */
144 "REFQUAD", /* name */
b34976b6 145 TRUE, /* partial_inplace */
252b5132
RH
146 0xffffffffffffffff, /* src_mask */
147 0xffffffffffffffff, /* dst_mask */
b34976b6 148 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 157 FALSE, /* pc_relative */
252b5132
RH
158 0, /* bitpos */
159 complain_overflow_bitfield, /* complain_on_overflow */
160 0, /* special_function */
161 "GPREL32", /* name */
b34976b6 162 TRUE, /* partial_inplace */
252b5132
RH
163 0xffffffff, /* src_mask */
164 0xffffffff, /* dst_mask */
b34976b6 165 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 174 FALSE, /* pc_relative */
252b5132
RH
175 0, /* bitpos */
176 complain_overflow_signed, /* complain_on_overflow */
177 0, /* special_function */
178 "LITERAL", /* name */
b34976b6 179 TRUE, /* partial_inplace */
252b5132
RH
180 0xffff, /* src_mask */
181 0xffff, /* dst_mask */
b34976b6 182 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 197 FALSE, /* pc_relative */
252b5132
RH
198 0, /* bitpos */
199 complain_overflow_dont, /* complain_on_overflow */
200 0, /* special_function */
201 "LITUSE", /* name */
b34976b6 202 FALSE, /* partial_inplace */
252b5132
RH
203 0, /* src_mask */
204 0, /* dst_mask */
b34976b6 205 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 222 TRUE, /* pc_relative */
252b5132
RH
223 0, /* bitpos */
224 complain_overflow_dont, /* complain_on_overflow */
225 0, /* special_function */
226 "GPDISP", /* name */
b34976b6 227 TRUE, /* partial_inplace */
252b5132
RH
228 0xffff, /* src_mask */
229 0xffff, /* dst_mask */
b34976b6 230 TRUE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 240 TRUE, /* pc_relative */
252b5132
RH
241 0, /* bitpos */
242 complain_overflow_signed, /* complain_on_overflow */
243 0, /* special_function */
244 "BRADDR", /* name */
b34976b6 245 FALSE, /* partial_inplace */
252b5132
RH
246 0, /* src_mask */
247 0x1fffff, /* dst_mask */
b34976b6 248 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 255 FALSE, /* pc_relative */
252b5132
RH
256 0, /* bitpos */
257 complain_overflow_dont, /* complain_on_overflow */
258 0, /* special_function */
259 "HINT", /* name */
b34976b6 260 TRUE, /* partial_inplace */
252b5132
RH
261 0x3fff, /* src_mask */
262 0x3fff, /* dst_mask */
b34976b6 263 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 270 TRUE, /* pc_relative */
252b5132
RH
271 0, /* bitpos */
272 complain_overflow_signed, /* complain_on_overflow */
273 0, /* special_function */
274 "SREL16", /* name */
b34976b6 275 TRUE, /* partial_inplace */
252b5132
RH
276 0xffff, /* src_mask */
277 0xffff, /* dst_mask */
b34976b6 278 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 285 TRUE, /* pc_relative */
252b5132
RH
286 0, /* bitpos */
287 complain_overflow_signed, /* complain_on_overflow */
288 0, /* special_function */
289 "SREL32", /* name */
b34976b6 290 TRUE, /* partial_inplace */
252b5132
RH
291 0xffffffff, /* src_mask */
292 0xffffffff, /* dst_mask */
b34976b6 293 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 300 TRUE, /* pc_relative */
252b5132
RH
301 0, /* bitpos */
302 complain_overflow_signed, /* complain_on_overflow */
303 0, /* special_function */
304 "SREL64", /* name */
b34976b6 305 TRUE, /* partial_inplace */
252b5132
RH
306 0xffffffffffffffff, /* src_mask */
307 0xffffffffffffffff, /* dst_mask */
b34976b6 308 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 315 FALSE, /* pc_relative */
252b5132
RH
316 0, /* bitpos */
317 complain_overflow_dont, /* complain_on_overflow */
318 0, /* special_function */
319 "OP_PUSH", /* name */
b34976b6 320 FALSE, /* partial_inplace */
252b5132
RH
321 0, /* src_mask */
322 0, /* dst_mask */
b34976b6 323 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 331 FALSE, /* pc_relative */
252b5132
RH
332 0, /* bitpos */
333 complain_overflow_dont, /* complain_on_overflow */
334 0, /* special_function */
335 "OP_STORE", /* name */
b34976b6 336 FALSE, /* partial_inplace */
252b5132
RH
337 0, /* src_mask */
338 0xffffffffffffffff, /* dst_mask */
b34976b6 339 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 347 FALSE, /* pc_relative */
252b5132
RH
348 0, /* bitpos */
349 complain_overflow_dont, /* complain_on_overflow */
350 0, /* special_function */
351 "OP_PSUB", /* name */
b34976b6 352 FALSE, /* partial_inplace */
252b5132
RH
353 0, /* src_mask */
354 0, /* dst_mask */
b34976b6 355 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 363 FALSE, /* pc_relative */
252b5132
RH
364 0, /* bitpos */
365 complain_overflow_dont, /* complain_on_overflow */
366 0, /* special_function */
367 "OP_PRSHIFT", /* name */
b34976b6 368 FALSE, /* partial_inplace */
252b5132
RH
369 0, /* src_mask */
370 0, /* dst_mask */
b34976b6 371 FALSE), /* pcrel_offset */
252b5132
RH
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 */
b34976b6 378 FALSE, /* pc_relative */
252b5132
RH
379 0, /* bitpos */
380 complain_overflow_dont, /* complain_on_overflow */
381 0, /* special_function */
382 "GPVALUE", /* name */
b34976b6 383 FALSE, /* partial_inplace */
252b5132
RH
384 0, /* src_mask */
385 0, /* dst_mask */
b34976b6 386 FALSE) /* pcrel_offset */
252b5132
RH
387};
388
389static 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 */
b34976b6 394 FALSE, /* pc_relative */
252b5132
RH
395 0, /* bitpos */
396 complain_overflow_dont, /* complain_on_overflow */
397 0, /* special_function */
398 "NW_RELOC", /* name */
b34976b6 399 FALSE, /* partial_inplace */
252b5132
RH
400 0, /* src_mask */
401 0, /* dst_mask */
b34976b6 402 FALSE); /* pcrel_offset */
252b5132
RH
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
b34976b6 408static bfd_boolean
252b5132
RH
409nlm_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. */
dc810e39 424 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 425 return FALSE;
252b5132
RH
426
427 /* Swap in the reloc information. */
dc810e39
AM
428 r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
429 r_symndx = H_GET_32 (abfd, ext.r_symndx);
252b5132
RH
430
431 BFD_ASSERT (bfd_little_endian (abfd));
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_ptr->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_ptr->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_ptr->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_ptr->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_ptr->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
b34976b6 599 return TRUE;
252b5132
RH
600}
601
602/* Mangle Alpha NLM relocs for output. */
603
b34976b6 604static bfd_boolean
252b5132 605nlm_alpha_mangle_relocs (abfd, sec, data, offset, count)
56fc028e
AJ
606 bfd *abfd ATTRIBUTE_UNUSED;
607 asection *sec ATTRIBUTE_UNUSED;
608 PTR data ATTRIBUTE_UNUSED;
609 bfd_vma offset ATTRIBUTE_UNUSED;
610 bfd_size_type count ATTRIBUTE_UNUSED;
252b5132 611{
b34976b6 612 return TRUE;
252b5132
RH
613}
614
615/* Read an ALPHA NLM import record */
616
b34976b6 617static bfd_boolean
252b5132
RH
618nlm_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 char *name;
dc810e39 627 bfd_size_type amt;
252b5132 628
dc810e39 629 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
252b5132 630 != sizeof (symlength))
b34976b6 631 return FALSE;
252b5132 632 sym -> symbol.the_bfd = abfd;
dc810e39 633 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
252b5132 634 if (name == NULL)
b34976b6 635 return FALSE;
dc810e39 636 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
b34976b6 637 return FALSE;
252b5132
RH
638 name[symlength] = '\0';
639 sym -> symbol.name = name;
640 sym -> symbol.flags = 0;
641 sym -> symbol.value = 0;
642 sym -> symbol.section = bfd_und_section_ptr;
dc810e39
AM
643 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
644 != sizeof (temp))
b34976b6 645 return FALSE;
dc810e39
AM
646 rcount = H_GET_32 (abfd, temp);
647 amt = rcount * sizeof (struct nlm_relent);
648 nlm_relocs = (struct nlm_relent *) bfd_alloc (abfd, amt);
252b5132 649 if (!nlm_relocs)
b34976b6 650 return FALSE;
252b5132
RH
651 sym -> relocs = nlm_relocs;
652 sym -> rcnt = 0;
653 while (sym -> rcnt < rcount)
654 {
655 asection *section;
1518639e 656
82e51918 657 if (! nlm_alpha_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
b34976b6 658 return FALSE;
252b5132
RH
659 nlm_relocs -> section = section;
660 nlm_relocs++;
661 sym -> rcnt++;
662 }
663
b34976b6 664 return TRUE;
252b5132
RH
665}
666
667/* Write an Alpha NLM reloc. */
668
b34976b6 669static bfd_boolean
252b5132
RH
670nlm_alpha_write_import (abfd, sec, rel)
671 bfd *abfd;
672 asection *sec;
673 arelent *rel;
674{
675 asymbol *sym;
676 bfd_vma r_vaddr;
677 long r_symndx;
678 int r_type, r_extern, r_offset, r_size;
679 struct nlm32_alpha_external_reloc ext;
680
681 sym = *rel->sym_ptr_ptr;
682
683 /* Get values for the relocation fields. */
684 r_type = rel->howto->type;
685 if (r_type != ALPHA_R_NW_RELOC)
686 {
687 r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
688 if ((sec->flags & SEC_CODE) == 0)
689 r_vaddr += bfd_section_size (abfd,
690 bfd_get_section_by_name (abfd,
691 NLM_CODE_NAME));
692 if (bfd_is_und_section (bfd_get_section (sym)))
693 {
694 r_extern = 1;
695 r_symndx = 0;
696 }
697 else
698 {
699 r_extern = 0;
700 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
701 r_symndx = ALPHA_RELOC_SECTION_TEXT;
702 else
703 r_symndx = ALPHA_RELOC_SECTION_DATA;
704 }
705 r_offset = 0;
706 r_size = 0;
707
708 switch (r_type)
709 {
710 case ALPHA_R_LITUSE:
711 case ALPHA_R_GPDISP:
712 r_symndx = rel->addend;
713 break;
714
715 case ALPHA_R_OP_STORE:
716 r_size = rel->addend & 0xff;
717 r_offset = (rel->addend >> 8) & 0xff;
718 break;
719
720 case ALPHA_R_OP_PUSH:
721 case ALPHA_R_OP_PSUB:
722 case ALPHA_R_OP_PRSHIFT:
723 r_vaddr = rel->addend;
724 break;
725
726 case ALPHA_R_IGNORE:
727 r_vaddr = rel->address;
728 break;
729
730 default:
731 break;
732 }
733 }
734 else
735 {
736 /* r_type == ALPHA_R_NW_RELOC */
737 r_vaddr = rel->address;
738 if (rel->addend == 0)
739 {
740 r_symndx = 0;
741 r_size = ALPHA_R_NW_RELOC_SETGP;
742 }
743 else
744 {
745 r_symndx = rel->addend - 1;
746 r_size = ALPHA_R_NW_RELOC_LITA;
747 }
748 r_extern = 0;
749 r_offset = 0;
750 }
751
752 /* Swap out the relocation fields. */
dc810e39
AM
753 H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
754 H_PUT_32 (abfd, r_symndx, ext.r_symndx);
252b5132
RH
755
756 BFD_ASSERT (bfd_little_endian (abfd));
757
758 ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
759 & RELOC_BITS0_TYPE_LITTLE);
760 ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
761 | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
762 & RELOC_BITS1_OFFSET_LITTLE));
763 ext.r_bits[2] = 0;
764 ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
765 & RELOC_BITS3_SIZE_LITTLE);
766
767 /* Write out the relocation. */
dc810e39 768 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 769 return FALSE;
252b5132 770
b34976b6 771 return TRUE;
252b5132
RH
772}
773\f
774/* Alpha NetWare does not use the high bit to determine whether a
775 public symbol is in the code segment or the data segment. Instead,
776 it just uses the address. The set_public_section and
777 get_public_offset routines override the default code which uses the
778 high bit. */
779
780/* Set the section for a public symbol. */
781
b34976b6 782static bfd_boolean
252b5132
RH
783nlm_alpha_set_public_section (abfd, sym)
784 bfd *abfd;
785 nlmNAME(symbol_type) *sym;
786{
787 asection *code_sec, *data_sec;
788
789 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
790 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
791 if (sym->symbol.value < bfd_section_size (abfd, code_sec))
792 {
793 sym->symbol.section = code_sec;
794 sym->symbol.flags |= BSF_FUNCTION;
795 }
796 else
797 {
798 sym->symbol.section = data_sec;
799 sym->symbol.value -= bfd_section_size (abfd, code_sec);
800 /* The data segment had better be aligned. */
801 BFD_ASSERT ((bfd_section_size (abfd, code_sec) & 0xf) == 0);
802 }
b34976b6 803 return TRUE;
252b5132
RH
804}
805
806/* Get the offset to write out for a public symbol. */
807
808static bfd_vma
809nlm_alpha_get_public_offset (abfd, sym)
56fc028e 810 bfd *abfd ATTRIBUTE_UNUSED;
252b5132
RH
811 asymbol *sym;
812{
813 return bfd_asymbol_value (sym);
814}
815\f
816/* Write an Alpha NLM external symbol. */
817
b34976b6 818static bfd_boolean
252b5132
RH
819nlm_alpha_write_external (abfd, count, sym, relocs)
820 bfd *abfd;
821 bfd_size_type count;
822 asymbol *sym;
823 struct reloc_and_sec *relocs;
824{
5d964dfa 825 bfd_size_type i;
252b5132
RH
826 bfd_byte len;
827 unsigned char temp[NLM_TARGET_LONG_SIZE];
828 arelent r;
829
830 len = strlen (sym->name);
dc810e39
AM
831 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
832 != sizeof (bfd_byte))
833 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
b34976b6 834 return FALSE;
252b5132
RH
835
836 bfd_put_32 (abfd, count + 2, temp);
dc810e39 837 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
b34976b6 838 return FALSE;
252b5132
RH
839
840 /* The first two relocs for each external symbol are the .lita
841 address and the GP value. */
842 r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
843 r.howto = &nlm32_alpha_nw_howto;
844
845 r.address = nlm_alpha_backend_data (abfd)->lita_address;
846 r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
82e51918 847 if (! nlm_alpha_write_import (abfd, (asection *) NULL, &r))
b34976b6 848 return FALSE;
252b5132
RH
849
850 r.address = nlm_alpha_backend_data (abfd)->gp;
851 r.addend = 0;
82e51918 852 if (! nlm_alpha_write_import (abfd, (asection *) NULL, &r))
b34976b6 853 return FALSE;
252b5132
RH
854
855 for (i = 0; i < count; i++)
856 {
82e51918 857 if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
b34976b6 858 return FALSE;
252b5132
RH
859 }
860
b34976b6 861 return TRUE;
252b5132
RH
862}
863
864#include "nlmswap.h"
865
866static const struct nlm_backend_data nlm32_alpha_backend =
867{
868 "NetWare Alpha Module \032",
869 sizeof (Nlm32_alpha_External_Fixed_Header),
870 sizeof (struct nlm32_alpha_external_prefix_header),
871 bfd_arch_alpha,
872 0,
b34976b6 873 TRUE, /* no uninitialized data permitted by Alpha NetWare. */
252b5132
RH
874 nlm_alpha_backend_object_p,
875 nlm_alpha_write_prefix,
876 nlm_alpha_read_reloc,
877 nlm_alpha_mangle_relocs,
878 nlm_alpha_read_import,
879 nlm_alpha_write_import,
880 nlm_alpha_set_public_section,
881 nlm_alpha_get_public_offset,
882 nlm_swap_fixed_header_in,
883 nlm_swap_fixed_header_out,
884 nlm_alpha_write_external,
885 0, /* write_export */
886};
887
888#define TARGET_LITTLE_NAME "nlm32-alpha"
889#define TARGET_LITTLE_SYM nlmNAME(alpha_vec)
890#define TARGET_BACKEND_DATA &nlm32_alpha_backend
891
892#include "nlm-target.h"
This page took 0.212252 seconds and 4 git commands to generate.