This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / bfd / nlm32-sparc.c
1 /* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2    Copyright (C) 1993, 1994, 1995, 1999 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23
24 #define ARCH_SIZE 32
25
26 #include "nlm/sparc32-ext.h"
27 #define Nlm_External_Fixed_Header       Nlm32_sparc_External_Fixed_Header
28
29 #include "libnlm.h"
30
31 static boolean nlm_sparc_read_reloc
32   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
33 static boolean nlm_sparc_write_reloc
34   PARAMS ((bfd *, asection *, arelent *));
35 static boolean nlm_sparc_mangle_relocs
36   PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
37 static boolean nlm_sparc_read_import
38   PARAMS ((bfd *, nlmNAME(symbol_type) *));
39 static boolean nlm_sparc_write_import
40   PARAMS ((bfd *, asection *, arelent *));
41 static boolean nlm_sparc_write_external
42   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
43
44 enum reloc_type
45   {
46     R_SPARC_NONE = 0,
47     R_SPARC_8,          R_SPARC_16,             R_SPARC_32, 
48     R_SPARC_DISP8,      R_SPARC_DISP16,         R_SPARC_DISP32, 
49     R_SPARC_WDISP30,    R_SPARC_WDISP22,
50     R_SPARC_HI22,       R_SPARC_22,
51     R_SPARC_13,         R_SPARC_LO10,
52     R_SPARC_GOT10,      R_SPARC_GOT13,          R_SPARC_GOT22,
53     R_SPARC_PC10,       R_SPARC_PC22,
54     R_SPARC_WPLT30,
55     R_SPARC_COPY,
56     R_SPARC_GLOB_DAT,   R_SPARC_JMP_SLOT,
57     R_SPARC_RELATIVE,
58     R_SPARC_UA32,
59     R_SPARC_max
60   };
61
62 #if 0
63 static CONST char *CONST reloc_type_names[] =
64 {
65   "R_SPARC_NONE",
66   "R_SPARC_8",          "R_SPARC_16",           "R_SPARC_32",
67   "R_SPARC_DISP8",      "R_SPARC_DISP16",       "R_SPARC_DISP32",
68   "R_SPARC_WDISP30",    "R_SPARC_WDISP22",
69   "R_SPARC_HI22",       "R_SPARC_22",
70   "R_SPARC_13",         "R_SPARC_LO10",
71   "R_SPARC_GOT10",      "R_SPARC_GOT13",        "R_SPARC_GOT22",
72   "R_SPARC_PC10",       "R_SPARC_PC22",
73   "R_SPARC_WPLT30",
74   "R_SPARC_COPY",
75   "R_SPARC_GLOB_DAT",   "R_SPARC_JMP_SLOT",
76   "R_SPARC_RELATIVE",
77   "R_SPARC_UA32",
78 };
79 #endif
80
81 static reloc_howto_type nlm32_sparc_howto_table[] = 
82 {
83   HOWTO(R_SPARC_NONE,    0,0, 0,false,0,complain_overflow_dont,    0,"R_SPARC_NONE",    false,0,0x00000000,true),
84   HOWTO(R_SPARC_8,       0,0, 8,false,0,complain_overflow_bitfield,0,"R_SPARC_8",       false,0,0x000000ff,true),
85   HOWTO(R_SPARC_16,      0,1,16,false,0,complain_overflow_bitfield,0,"R_SPARC_16",      false,0,0x0000ffff,true),
86   HOWTO(R_SPARC_32,      0,2,32,false,0,complain_overflow_bitfield,0,"R_SPARC_32",      false,0,0xffffffff,true),
87   HOWTO(R_SPARC_DISP8,   0,0, 8,true, 0,complain_overflow_signed,  0,"R_SPARC_DISP8",   false,0,0x000000ff,true),
88   HOWTO(R_SPARC_DISP16,  0,1,16,true, 0,complain_overflow_signed,  0,"R_SPARC_DISP16",  false,0,0x0000ffff,true),
89   HOWTO(R_SPARC_DISP32,  0,2,32,true, 0,complain_overflow_signed,  0,"R_SPARC_DISP32",  false,0,0x00ffffff,true),
90   HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed,  0,"R_SPARC_WDISP30", false,0,0x3fffffff,true),
91   HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed,  0,"R_SPARC_WDISP22", false,0,0x003fffff,true),
92   HOWTO(R_SPARC_HI22,   10,2,22,false,0,complain_overflow_dont,    0,"R_SPARC_HI22",    false,0,0x003fffff,true),
93   HOWTO(R_SPARC_22,      0,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_22",      false,0,0x003fffff,true),
94   HOWTO(R_SPARC_13,      0,2,13,false,0,complain_overflow_bitfield,0,"R_SPARC_13",      false,0,0x00001fff,true),
95   HOWTO(R_SPARC_LO10,    0,2,10,false,0,complain_overflow_dont,    0,"R_SPARC_LO10",    false,0,0x000003ff,true),
96   HOWTO(R_SPARC_GOT10,   0,2,10,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT10",   false,0,0x000003ff,true),
97   HOWTO(R_SPARC_GOT13,   0,2,13,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT13",   false,0,0x00001fff,true),
98   HOWTO(R_SPARC_GOT22,  10,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT22",   false,0,0x003fffff,true),
99   HOWTO(R_SPARC_PC10,    0,2,10,false,0,complain_overflow_bitfield,0,"R_SPARC_PC10",    false,0,0x000003ff,true),
100   HOWTO(R_SPARC_PC22,    0,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_PC22",    false,0,0x003fffff,true),
101   HOWTO(R_SPARC_WPLT30,  0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_WPLT30",  false,0,0x00000000,true),
102   HOWTO(R_SPARC_COPY,    0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_COPY",    false,0,0x00000000,true),
103   HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_GLOB_DAT",false,0,0x00000000,true),
104   HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_JMP_SLOT",false,0,0x00000000,true),
105   HOWTO(R_SPARC_RELATIVE,0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_RELATIVE",false,0,0x00000000,true),
106   HOWTO(R_SPARC_UA32,    0,0,00,false,0,complain_overflow_dont,    0,"R_SPARC_UA32",    false,0,0x00000000,true),
107 };
108
109 /* Read a NetWare sparc reloc.  */
110
111 struct nlm32_sparc_reloc_ext {
112   unsigned char offset[4];
113   unsigned char addend[4];
114   unsigned char type[1];
115   unsigned char pad1[3];
116 };
117
118 static boolean
119 nlm_sparc_read_reloc (abfd, sym, secp, rel)
120      bfd *abfd;
121      nlmNAME(symbol_type) *sym ATTRIBUTE_UNUSED;
122      asection **secp;
123      arelent *rel;
124 {
125   bfd_vma val, addend;
126   unsigned int index;
127   unsigned int type;
128   struct nlm32_sparc_reloc_ext tmp_reloc;
129   asection *code_sec, *data_sec;
130
131   if (bfd_read (&tmp_reloc, 12, 1, abfd) != 12)
132     return false;
133
134   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
135   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
136
137   *secp = code_sec;
138
139   val = bfd_get_32 (abfd, tmp_reloc.offset);
140   addend = bfd_get_32 (abfd, tmp_reloc.addend);
141   type = bfd_get_8 (abfd, tmp_reloc.type);
142
143   rel->address = val;
144   rel->addend = addend;
145   rel->howto = NULL;
146
147   for (index = 0;
148        index < sizeof(nlm32_sparc_howto_table) / sizeof(reloc_howto_type);
149        index++)
150     if (nlm32_sparc_howto_table[index].type == type) {
151       rel->howto = &nlm32_sparc_howto_table[index];
152       break;
153     }
154
155 #ifdef DEBUG
156   fprintf (stderr, "%s:  address = %08lx, addend = %08lx, type = %d, howto = %08lx\n",
157            __FUNCTION__, rel->address, rel->addend, type, rel->howto);
158 #endif
159   return true;
160
161 }
162
163 /* Write a NetWare sparc reloc.  */
164
165 static boolean
166 nlm_sparc_write_reloc (abfd, sec, rel)
167      bfd *abfd;
168      asection *sec;
169      arelent *rel;
170 {
171   bfd_vma val;
172   struct nlm32_sparc_reloc_ext tmp_reloc;
173   unsigned int index;
174   int type = -1;
175   reloc_howto_type *tmp;
176
177   
178   for (index = 0;
179        index < sizeof (nlm32_sparc_howto_table) / sizeof(reloc_howto_type);
180        index++) {
181     tmp = &nlm32_sparc_howto_table[index];
182
183     if (tmp->rightshift == rel->howto->rightshift
184         && tmp->size == rel->howto->size
185         && tmp->bitsize == rel->howto->bitsize
186         && tmp->pc_relative == rel->howto->pc_relative
187         && tmp->bitpos == rel->howto->bitpos
188         && tmp->src_mask == rel->howto->src_mask
189         && tmp->dst_mask == rel->howto->dst_mask) {
190       type = tmp->type;
191       break;
192     }
193   }
194   if (type == -1)
195     abort();
196
197   /*
198    * Netware wants a list of relocs for each address.
199    * Format is:
200    *    long    offset
201    *    long    addend
202    *    char    type
203    * That should be it.
204    */
205
206   /* The value we write out is the offset into the appropriate
207      segment.  This offset is the section vma, adjusted by the vma of
208      the lowest section in that segment, plus the address of the
209      relocation.  */
210 #if 0
211   val = bfd_get_section_vma (abfd, (*rel->sym_ptr_ptr)->section) + rel->address;
212 #else
213   val = bfd_get_section_vma (abfd, sec) + rel->address;
214 #endif
215
216 #ifdef DEBUG
217   fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %d\n",
218            __FUNCTION__, val, rel->addend, rel->howto->type);
219 #endif
220   bfd_put_32 (abfd, val, tmp_reloc.offset);
221   bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
222   bfd_put_8 (abfd, (short)(rel->howto->type), tmp_reloc.type);
223
224   if (bfd_write (&tmp_reloc, 12, 1, abfd) != 12)
225     return false;
226
227   return true;
228 }
229
230 /* Mangle relocs for SPARC NetWare.  We can just use the standard
231    SPARC relocs.  */
232
233 static boolean
234 nlm_sparc_mangle_relocs (abfd, sec, data, offset, count)
235      bfd *abfd ATTRIBUTE_UNUSED;
236      asection *sec ATTRIBUTE_UNUSED;
237      PTR data ATTRIBUTE_UNUSED;
238      bfd_vma offset ATTRIBUTE_UNUSED;
239      bfd_size_type count ATTRIBUTE_UNUSED;
240 {
241   return true;
242 }
243
244 /* Read a NetWare sparc import record */
245 static boolean
246 nlm_sparc_read_import (abfd, sym)
247      bfd *abfd;
248      nlmNAME(symbol_type) *sym;
249 {
250   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
251   bfd_size_type rcount;                 /* number of relocs */
252   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
253   unsigned char symlength;              /* length of symbol name */
254   char *name;
255   
256   /*
257    * First, read in the number of relocation
258    * entries for this symbol
259    */
260   if (bfd_read ((PTR) temp, 4, 1, abfd) != 4)
261     return false;
262   
263   rcount = bfd_get_32 (abfd, temp);
264   
265   /*
266    * Next, read in the length of the symbol
267    */
268   
269   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
270       != sizeof (symlength))
271     return false;
272   sym -> symbol.the_bfd = abfd;
273   name = bfd_alloc (abfd, symlength + 1);
274   if (name == NULL)
275     return false;
276   
277   /*
278    * Then read in the symbol
279    */
280   
281   if (bfd_read (name, symlength, 1, abfd) != symlength)
282     return false;
283   name[symlength] = '\0';
284   sym -> symbol.name = name;
285   sym -> symbol.flags = 0;
286   sym -> symbol.value = 0;
287   sym -> symbol.section = bfd_und_section_ptr;
288   
289   /*
290    * Next, start reading in the relocs.
291    */
292   
293   nlm_relocs = ((struct nlm_relent *)
294                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
295   if (!nlm_relocs)
296     return false;
297   sym -> relocs = nlm_relocs;
298   sym -> rcnt = 0;
299   while (sym -> rcnt < rcount)
300     {
301       asection *section;
302       
303       if (nlm_sparc_read_reloc (abfd, sym, &section,
304                               &nlm_relocs -> reloc)
305           == false)
306         return false;
307       nlm_relocs -> section = section;
308       nlm_relocs++;
309       sym -> rcnt++;
310     }
311   return true;
312 }
313
314 static boolean
315 nlm_sparc_write_import (abfd, sec, rel)
316      bfd *abfd;
317      asection *sec;
318      arelent *rel;
319 {
320   char temp[4];
321   asection *code, *data, *bss, *symsec;
322   bfd_vma base;
323
324   code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
325   data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
326   bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
327   symsec = (*rel->sym_ptr_ptr)->section;
328
329   if (symsec == code) {
330     base = 0;
331   } else if (symsec == data) {
332     base = bfd_section_size (abfd, code);
333   } else if (symsec == bss) {
334     base = bfd_section_size (abfd, code) + bfd_section_size (abfd, data);
335   } else
336     base = 0;
337
338 #ifdef DEBUG
339   fprintf (stderr, "%s:  <%x, 1>\n\t",
340            __FUNCTION__, base + (*rel->sym_ptr_ptr)->value);
341 #endif
342   bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
343   if (bfd_write ((PTR)temp, 4, 1, abfd) != 4)
344     return false;
345   bfd_put_32 (abfd, 1, temp);
346   if (bfd_write ((PTR)temp, 4, 1, abfd) != 4)
347     return false;
348   if (nlm_sparc_write_reloc (abfd, sec, rel) == false)
349     return false;
350   return true;
351 }
352
353 /* Write out an external reference.  */
354
355 static boolean
356 nlm_sparc_write_external (abfd, count, sym, relocs)
357      bfd *abfd;
358      bfd_size_type count;
359      asymbol *sym;
360      struct reloc_and_sec *relocs;
361 {
362   unsigned int i;
363   bfd_byte len;
364   unsigned char temp[NLM_TARGET_LONG_SIZE];
365
366   bfd_put_32 (abfd, count, temp);
367   if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
368     return false;
369
370   len = strlen (sym->name);
371   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
372       || bfd_write (sym->name, len, 1, abfd) != len)
373     return false;
374
375   for (i = 0; i < count; i++)
376     {
377       if (nlm_sparc_write_reloc (abfd, relocs[i].sec,
378                                  relocs[i].rel) == false)
379         return false;
380     }
381
382   return true;
383 }
384
385 static boolean
386 nlm_sparc_write_export (abfd, sym, value)
387      bfd *abfd;
388      asymbol *sym;
389      bfd_vma value;
390 {
391   bfd_byte len;
392   bfd_byte temp[4];
393
394 #ifdef DEBUG
395   fprintf (stderr, "%s: <%x, %d, %s>\n",
396            __FUNCTION__, value, strlen (sym->name), sym->name);
397 #endif
398   bfd_put_32 (abfd, value, temp);
399   len = strlen (sym->name);
400
401   if (bfd_write (temp, 4, 1, abfd) != 4
402       || bfd_write (&len, 1, 1, abfd) != 1
403       || bfd_write (sym->name, len, 1, abfd) != len)
404     return false;
405
406   return true;
407 }
408
409 #undef nlm_swap_fixed_header_in
410 #undef nlm_swap_fixed_header_out
411
412 #include "nlmswap.h"
413
414 static const struct nlm_backend_data nlm32_sparc_backend =
415 {
416   "NetWare SPARC Module   \032",
417   sizeof (Nlm32_sparc_External_Fixed_Header),
418   0,    /* optional_prefix_size */
419   bfd_arch_sparc,
420   0,
421   false,
422   0,    /* backend_object_p */
423   0,    /* write_prefix_func */
424   nlm_sparc_read_reloc,
425   nlm_sparc_mangle_relocs,
426   nlm_sparc_read_import,
427   nlm_sparc_write_import,
428   0,    /* set_public_section */
429   0,    /* get_public_offset */
430   nlm_swap_fixed_header_in,
431   nlm_swap_fixed_header_out,
432   nlm_sparc_write_external,
433   nlm_sparc_write_export
434 };
435
436 #define TARGET_BIG_NAME         "nlm32-sparc"
437 #define TARGET_BIG_SYM          nlmNAME(sparc_vec)
438 #define TARGET_BACKEND_DATA             &nlm32_sparc_backend
439
440 #include "nlm-target.h"