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