OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [bfd/] [nlm32-alpha.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2
   Copyright 1993, 1994, 2000, 2001 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., 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
 
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
 
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
 
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 (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
 
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 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;
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
  char *name;
627
 
628
  if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
629
      != sizeof (symlength))
630
    return false;
631
  sym -> symbol.the_bfd = abfd;
632
  name = bfd_alloc (abfd, symlength + 1);
633
  if (name == NULL)
634
    return false;
635
  if (bfd_read (name, symlength, 1, abfd) != symlength)
636
    return false;
637
  name[symlength] = '\0';
638
  sym -> symbol.name = name;
639
  sym -> symbol.flags = 0;
640
  sym -> symbol.value = 0;
641
  sym -> symbol.section = bfd_und_section_ptr;
642
  if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
643
    return false;
644
  rcount = bfd_h_get_32 (abfd, temp);
645
  nlm_relocs = ((struct nlm_relent *)
646
                bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
647
  if (!nlm_relocs)
648
    return false;
649
  sym -> relocs = nlm_relocs;
650
  sym -> rcnt = 0;
651
  while (sym -> rcnt < rcount)
652
    {
653
      asection *section;
654
 
655
      if (nlm_alpha_read_reloc (abfd, sym, &section,
656
                                &nlm_relocs -> reloc)
657
          == false)
658
        return false;
659
      nlm_relocs -> section = section;
660
      nlm_relocs++;
661
      sym -> rcnt++;
662
    }
663
 
664
  return true;
665
}
666
 
667
/* Write an Alpha NLM reloc.  */
668
 
669
static boolean
670
nlm_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.  */
753
  bfd_h_put_64 (abfd, r_vaddr, (bfd_byte *) ext.r_vaddr);
754
  bfd_h_put_32 (abfd, r_symndx, (bfd_byte *) ext.r_symndx);
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.  */
768
  if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
769
    return false;
770
 
771
  return true;
772
}
773
 
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
 
782
static boolean
783
nlm_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
    }
803
  return true;
804
}
805
 
806
/* Get the offset to write out for a public symbol.  */
807
 
808
static bfd_vma
809
nlm_alpha_get_public_offset (abfd, sym)
810
     bfd *abfd ATTRIBUTE_UNUSED;
811
     asymbol *sym;
812
{
813
  return bfd_asymbol_value (sym);
814
}
815
 
816
/* Write an Alpha NLM external symbol.  */
817
 
818
static boolean
819
nlm_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
{
825
  int i;
826
  bfd_byte len;
827
  unsigned char temp[NLM_TARGET_LONG_SIZE];
828
  arelent r;
829
 
830
  len = strlen (sym->name);
831
  if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof (bfd_byte))
832
      || bfd_write (sym->name, len, 1, abfd) != len)
833
    return false;
834
 
835
  bfd_put_32 (abfd, count + 2, temp);
836
  if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
837
    return false;
838
 
839
  /* The first two relocs for each external symbol are the .lita
840
     address and the GP value.  */
841
  r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
842
  r.howto = &nlm32_alpha_nw_howto;
843
 
844
  r.address = nlm_alpha_backend_data (abfd)->lita_address;
845
  r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
846
  if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
847
    return false;
848
 
849
  r.address = nlm_alpha_backend_data (abfd)->gp;
850
  r.addend = 0;
851
  if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
852
    return false;
853
 
854
  for (i = 0; i < count; i++)
855
    {
856
      if (nlm_alpha_write_import (abfd, relocs[i].sec,
857
                                  relocs[i].rel) == false)
858
        return false;
859
    }
860
 
861
  return true;
862
}
863
 
864
#include "nlmswap.h"
865
 
866
static 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,
873
  true, /* no uninitialized data permitted by Alpha NetWare.  */
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"

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.