1/* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2   Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3   2007 Free Software Foundation, Inc.
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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "bfd.h"
23#include "sysdep.h"
24#include "libbfd.h"
25
26/* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
27   old format.  */
28
29#define ARCH_SIZE 32
30
31#include "nlm/ppc-ext.h"
32#define Nlm_External_Fixed_Header	Nlm32_powerpc_External_Fixed_Header
33
34#include "libnlm.h"
35
36#ifdef OLDFORMAT
37
38/* The prefix header is only used in the old format.  */
39
40/* PowerPC NLM's have a prefix header before the standard NLM.  This
41   function reads it in, verifies the version, and seeks the bfd to
42   the location before the regular NLM header.  */
43
44static bfd_boolean
45nlm_powerpc_backend_object_p (bfd *abfd)
46{
47  struct nlm32_powerpc_external_prefix_header s;
48
49  if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
50    return FALSE;
51
52  if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
53      || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
54    return FALSE;
55
56  return TRUE;
57}
58
59/* Write out the prefix.  */
60
61static bfd_boolean
62nlm_powerpc_write_prefix (bfd *abfd)
63{
64  struct nlm32_powerpc_external_prefix_header s;
65
66  memset (&s, 0, sizeof s);
67  memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
68  H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
69  H_PUT_32 (abfd, 0, s.origins);
70
71  /* FIXME: What should we do about the date?  */
72
73  if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
74    return FALSE;
75
76  return TRUE;
77}
78
79/* This reloc handling is only applicable to the old format.  */
80
81/* How to process the various reloc types.  PowerPC NLMs use XCOFF
82   reloc types, and I have just copied the XCOFF reloc table here.  */
83
84static reloc_howto_type nlm_powerpc_howto_table[] =
85{
86  /* Standard 32 bit relocation.  */
87  HOWTO (0,	                /* Type.  */
88	 0,	                /* Rightshift.  */
89	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
90	 32,	                /* Bitsize.  */
91	 FALSE,	                /* PC relative.  */
92	 0,	                /* Bitpos.  */
93	 complain_overflow_bitfield, /* Complain_on_overflow.  */
94	 0,		        /* Special_function.  */
95	 "R_POS",               /* Name.  */
96	 TRUE,	                /* Partial_inplace.  */
97	 0xffffffff,            /* Source mask.  */
98	 0xffffffff,            /* Dest mask.  */
99	 FALSE),                /* PC rel offset.  */
100
101  /* 32 bit relocation, but store negative value.  */
102  HOWTO (1,	                /* Type.  */
103	 0,	                /* Rightshift.  */
104	 -2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
105	 32,	                /* Bitsize.  */
106	 FALSE,	                /* PC relative.  */
107	 0,	                /* Bitpos.  */
108	 complain_overflow_bitfield, /* Complain_on_overflow.  */
109	 0,		        /* Special_function.  */
110	 "R_NEG",               /* Name.  */
111	 TRUE,	                /* Partial_inplace.  */
112	 0xffffffff,            /* Source mask.  */
113	 0xffffffff,            /* Dest mask.  */
114	 FALSE),                /* PC rel offset.  */
115
116  /* 32 bit PC relative relocation.  */
117  HOWTO (2,	                /* Type.  */
118	 0,	                /* Rightshift.  */
119	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
120	 32,	                /* Bitsize.  */
121	 TRUE,	                /* PC relative.  */
122	 0,	                /* Bitpos.  */
123	 complain_overflow_signed, /* Complain_on_overflow.  */
124	 0,		        /* Special_function.  */
125	 "R_REL",               /* Name.  */
126	 TRUE,	                /* Partial_inplace.  */
127	 0xffffffff,            /* Source mask.  */
128	 0xffffffff,            /* Dest mask.  */
129	 FALSE),                /* PC rel offset.  */
130
131  /* 16 bit TOC relative relocation.  */
132  HOWTO (3,	                /* Type.  */
133	 0,	                /* Rightshift.  */
134	 1,	                /* Size (0 = byte, 1 = short, 2 = long).  */
135	 16,	                /* Bitsize.  */
136	 FALSE,	                /* PC relative.  */
137	 0,	                /* Bitpos.  */
138	 complain_overflow_signed, /* Complain_on_overflow.  */
139	 0,		        /* Special_function.  */
140	 "R_TOC",               /* Name.  */
141	 TRUE,	                /* Partial_inplace.  */
142	 0xffff,	        /* Source mask.  */
143	 0xffff,        	/* Dest mask.  */
144	 FALSE),                /* PC rel offset.  */
145
146  /* I don't really know what this is.  */
147  HOWTO (4,	                /* Type.  */
148	 1,	                /* Rightshift.  */
149	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
150	 32,	                /* Bitsize.  */
151	 FALSE,	                /* PC relative.  */
152	 0,	                /* Bitpos.  */
153	 complain_overflow_bitfield, /* Complain_on_overflow.  */
154	 0,		        /* Special_function.  */
155	 "R_RTB",               /* Name.  */
156	 TRUE,	                /* Partial_inplace.  */
157	 0xffffffff,	        /* Source mask.  */
158	 0xffffffff,        	/* Dest mask.  */
159	 FALSE),                /* PC rel offset.  */
160
161  /* External TOC relative symbol.  */
162  HOWTO (5,	                /* Type.  */
163	 0,	                /* Rightshift.  */
164	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
165	 16,	                /* Bitsize.  */
166	 FALSE,	                /* PC relative.  */
167	 0,	                /* Bitpos.  */
168	 complain_overflow_bitfield, /* Complain_on_overflow.  */
169	 0,		        /* Special_function.  */
170	 "R_GL",                /* Name.  */
171	 TRUE,	                /* Partial_inplace.  */
172	 0xffff,	        /* Source mask.  */
173	 0xffff,        	/* Dest mask.  */
174	 FALSE),                /* PC rel offset.  */
175
176  /* Local TOC relative symbol.  */
177  HOWTO (6,	                /* Type.  */
178	 0,	                /* Rightshift.  */
179	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
180	 16,	                /* Bitsize.  */
181	 FALSE,	                /* PC relative.  */
182	 0,	                /* Bitpos.  */
183	 complain_overflow_bitfield, /* Complain_on_overflow.  */
184	 0,		        /* Special_function.  */
185	 "R_TCL",               /* Name.  */
186	 TRUE,	                /* Partial_inplace.  */
187	 0xffff,	        /* Source mask.  */
188	 0xffff,        	/* Dest mask.  */
189	 FALSE),                /* PC rel offset.  */
190
191  { 7 },
192
193  /* Non modifiable absolute branch.  */
194  HOWTO (8,	                /* Type.  */
195	 0,	                /* Rightshift.  */
196	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
197	 26,	                /* Bitsize.  */
198	 FALSE,	                /* PC relative.  */
199	 0,	                /* Bitpos.  */
200	 complain_overflow_bitfield, /* Complain_on_overflow.  */
201	 0,		        /* Special_function.  */
202	 "R_BA",                /* Name.  */
203	 TRUE,	                /* Partial_inplace.  */
204	 0x3fffffc,	        /* Source mask.  */
205	 0x3fffffc,        	/* Dest mask.  */
206	 FALSE),                /* PC rel offset.  */
207
208  { 9 },
209
210  /* Non modifiable relative branch.  */
211  HOWTO (0xa,	                /* Type.  */
212	 0,	                /* Rightshift.  */
213	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
214	 26,	                /* Bitsize.  */
215	 TRUE,	                /* PC relative.  */
216	 0,	                /* Bitpos.  */
217	 complain_overflow_signed, /* Complain_on_overflow.  */
218	 0,		        /* Special_function.  */
219	 "R_BR",                /* Name.  */
220	 TRUE,	                /* Partial_inplace.  */
221	 0x3fffffc,	        /* Source mask.  */
222	 0x3fffffc,        	/* Dest mask.  */
223	 FALSE),                /* PC rel offset.  */
224
225  { 0xb },
226
227  /* Indirect load.  */
228  HOWTO (0xc,	                /* Type.  */
229	 0,	                /* Rightshift.  */
230	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
231	 16,	                /* Bitsize.  */
232	 FALSE,	                /* PC relative.  */
233	 0,	                /* Bitpos.  */
234	 complain_overflow_bitfield, /* Complain_on_overflow.  */
235	 0,		        /* Special_function.  */
236	 "R_RL",                /* Name.  */
237	 TRUE,	                /* Partial_inplace.  */
238	 0xffff,	        /* Source mask.  */
239	 0xffff,        	/* Dest mask.  */
240	 FALSE),                /* PC rel offset.  */
241
242  /* Load address.  */
243  HOWTO (0xd,	                /* Type.  */
244	 0,	                /* Rightshift.  */
245	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
246	 16,	                /* Bitsize.  */
247	 FALSE,	                /* PC relative.  */
248	 0,	                /* Bitpos.  */
249	 complain_overflow_bitfield, /* Complain_on_overflow.  */
250	 0,		        /* Special_function.  */
251	 "R_RLA",               /* Name.  */
252	 TRUE,	                /* Partial_inplace.  */
253	 0xffff,	        /* Source mask.  */
254	 0xffff,        	/* Dest mask.  */
255	 FALSE),                /* PC rel offset.  */
256
257  { 0xe },
258
259  /* Non-relocating reference.  */
260  HOWTO (0xf,	                /* Type.  */
261	 0,	                /* Rightshift.  */
262	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
263	 32,	                /* Bitsize.  */
264	 FALSE,	                /* PC relative.  */
265	 0,	                /* Bitpos.  */
266	 complain_overflow_bitfield, /* Complain_on_overflow.  */
267	 0,		        /* Special_function.  */
268	 "R_REF",               /* Name.  */
269	 FALSE,	                /* Partial_inplace.  */
270	 0,		        /* Source mask.  */
271	 0,     	   	/* Dest mask.  */
272	 FALSE),                /* PC rel offset.  */
273
274  { 0x10 },
275  { 0x11 },
276
277  /* TOC relative indirect load.  */
278  HOWTO (0x12,	                /* Type.  */
279	 0,	                /* Rightshift.  */
280	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
281	 16,	                /* Bitsize.  */
282	 FALSE,	                /* PC relative.  */
283	 0,	                /* Bitpos.  */
284	 complain_overflow_bitfield, /* Complain_on_overflow.  */
285	 0,		        /* Special_function.  */
286	 "R_TRL",               /* Name.  */
287	 TRUE,	                /* Partial_inplace.  */
288	 0xffff,	        /* Source mask.  */
289	 0xffff,        	/* Dest mask.  */
290	 FALSE),                /* PC rel offset.  */
291
292  /* TOC relative load address.  */
293  HOWTO (0x13,	                /* Type.  */
294	 0,	                /* Rightshift.  */
295	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
296	 16,	                /* Bitsize.  */
297	 FALSE,	                /* PC relative.  */
298	 0,	                /* Bitpos.  */
299	 complain_overflow_bitfield, /* Complain_on_overflow.  */
300	 0,		        /* Special_function.  */
301	 "R_TRLA",              /* Name.  */
302	 TRUE,	                /* Partial_inplace.  */
303	 0xffff,	        /* Source mask.  */
304	 0xffff,        	/* Dest mask.  */
305	 FALSE),                /* PC rel offset.  */
306
307  /* Modifiable relative branch.  */
308  HOWTO (0x14,	                /* Type.  */
309	 1,	                /* Rightshift.  */
310	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
311	 32,	                /* Bitsize.  */
312	 FALSE,	                /* PC relative.  */
313	 0,	                /* Bitpos.  */
314	 complain_overflow_bitfield, /* Complain_on_overflow.  */
315	 0,		        /* Special_function.  */
316	 "R_RRTBI",             /* Name.  */
317	 TRUE,	                /* Partial_inplace.  */
318	 0xffffffff,	        /* Source mask.  */
319	 0xffffffff,        	/* Dest mask.  */
320	 FALSE),                /* PC rel offset.  */
321
322  /* Modifiable absolute branch.  */
323  HOWTO (0x15,	                /* Type.  */
324	 1,	                /* Rightshift.  */
325	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
326	 32,	                /* Bitsize.  */
327	 FALSE,	                /* PC relative.  */
328	 0,	                /* Bitpos.  */
329	 complain_overflow_bitfield, /* Complain_on_overflow.  */
330	 0,		        /* Special_function.  */
331	 "R_RRTBA",             /* Name.  */
332	 TRUE,	                /* Partial_inplace.  */
333	 0xffffffff,	        /* Source mask.  */
334	 0xffffffff,        	/* Dest mask.  */
335	 FALSE),                /* PC rel offset.  */
336
337  /* Modifiable call absolute indirect.  */
338  HOWTO (0x16,	                /* Type.  */
339	 0,	                /* Rightshift.  */
340	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
341	 16,	                /* Bitsize.  */
342	 FALSE,	                /* PC relative.  */
343	 0,	                /* Bitpos.  */
344	 complain_overflow_bitfield, /* Complain_on_overflow.  */
345	 0,		        /* Special_function.  */
346	 "R_CAI",               /* Name.  */
347	 TRUE,	                /* Partial_inplace.  */
348	 0xffff,	        /* Source mask.  */
349	 0xffff,        	/* Dest mask.  */
350	 FALSE),                /* PC rel offset.  */
351
352  /* Modifiable call relative.  */
353  HOWTO (0x17,	                /* Type.  */
354	 0,	                /* Rightshift.  */
355	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
356	 16,	                /* Bitsize.  */
357	 FALSE,	                /* PC relative.  */
358	 0,	                /* Bitpos.  */
359	 complain_overflow_bitfield, /* Complain_on_overflow.  */
360	 0,		        /* Special_function.  */
361	 "R_REL",               /* Name.  */
362	 TRUE,	                /* Partial_inplace.  */
363	 0xffff,	        /* Source mask.  */
364	 0xffff,        	/* Dest mask.  */
365	 FALSE),                /* PC rel offset.  */
366
367  /* Modifiable branch absolute.  */
368  HOWTO (0x18,	                /* Type.  */
369	 0,	                /* Rightshift.  */
370	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
371	 16,	                /* Bitsize.  */
372	 FALSE,	                /* PC relative.  */
373	 0,	                /* Bitpos.  */
374	 complain_overflow_bitfield, /* Complain_on_overflow.  */
375	 0,		        /* Special_function.  */
376	 "R_RBA",               /* Name.  */
377	 TRUE,	                /* Partial_inplace.  */
378	 0xffff,	        /* Source mask.  */
379	 0xffff,        	/* Dest mask.  */
380	 FALSE),                /* PC rel offset.  */
381
382  /* Modifiable branch absolute.  */
383  HOWTO (0x19,	                /* Type.  */
384	 0,	                /* Rightshift.  */
385	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
386	 16,	                /* Bitsize.  */
387	 FALSE,	                /* PC relative.  */
388	 0,	                /* Bitpos.  */
389	 complain_overflow_bitfield, /* Complain_on_overflow.  */
390	 0,		        /* Special_function.  */
391	 "R_RBAC",              /* Name.  */
392	 TRUE,	                /* Partial_inplace.  */
393	 0xffff,	        /* Source mask.  */
394	 0xffff,        	/* Dest mask.  */
395	 FALSE),                /* PC rel offset.  */
396
397  /* Modifiable branch relative.  */
398  HOWTO (0x1a,	                /* Type.  */
399	 0,	                /* Rightshift.  */
400	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
401	 26,	                /* Bitsize.  */
402	 FALSE,	                /* PC relative.  */
403	 0,	                /* Bitpos.  */
404	 complain_overflow_signed, /* Complain_on_overflow.  */
405	 0,		        /* Special_function.  */
406	 "R_REL",               /* Name.  */
407	 TRUE,	                /* Partial_inplace.  */
408	 0xffff,	        /* Source mask.  */
409	 0xffff,        	/* Dest mask.  */
410	 FALSE),                /* PC rel offset.  */
411
412  /* Modifiable branch absolute.  */
413  HOWTO (0x1b,	                /* Type.  */
414	 0,	                /* Rightshift.  */
415	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
416	 16,	                /* Bitsize.  */
417	 FALSE,	                /* PC relative.  */
418	 0,	                /* Bitpos.  */
419	 complain_overflow_bitfield, /* Complain_on_overflow.  */
420	 0,		        /* Special_function.  */
421	 "R_REL",               /* Name.  */
422	 TRUE,	                /* Partial_inplace.  */
423	 0xffff,	        /* Source mask.  */
424	 0xffff,        	/* Dest mask.  */
425	 FALSE)                 /* PC rel offset.  */
426};
427
428#define HOWTO_COUNT (sizeof nlm_powerpc_howto_table		\
429		     / sizeof nlm_powerpc_howto_table[0])
430
431/* Read a PowerPC NLM reloc.  */
432
433static bfd_boolean
434nlm_powerpc_read_reloc (bfd *abfd,
435			nlmNAME (symbol_type) *sym,
436			asection **secp,
437			arelent *rel)
438{
439  struct nlm32_powerpc_external_reloc ext;
440  bfd_vma l_vaddr;
441  unsigned long l_symndx;
442  int l_rtype;
443  int l_rsecnm;
444  asection *code_sec, *data_sec, *bss_sec;
445
446  /* Read the reloc from the file.  */
447  if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
448    return FALSE;
449
450  /* Swap in the fields.  */
451  l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
452  l_symndx = H_GET_32 (abfd, ext.l_symndx);
453  l_rtype = H_GET_16 (abfd, ext.l_rtype);
454  l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
455
456  /* Get the sections now, for convenience.  */
457  code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
458  data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
459  bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
460
461  /* Work out the arelent fields.  */
462  if (sym != NULL)
463    /* This is an import.  sym_ptr_ptr is filled in by
464       nlm_canonicalize_reloc.  */
465    rel->sym_ptr_ptr = NULL;
466  else
467    {
468      asection *sec;
469
470      if (l_symndx == 0)
471	sec = code_sec;
472      else if (l_symndx == 1)
473	sec = data_sec;
474      else if (l_symndx == 2)
475	sec = bss_sec;
476      else
477	{
478	  bfd_set_error (bfd_error_bad_value);
479	  return FALSE;
480	}
481
482      rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
483    }
484
485  rel->addend = 0;
486
487  BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
488
489  rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
490
491  BFD_ASSERT (rel->howto->name != NULL
492	      && ((l_rtype & 0x8000) != 0
493		  ? (rel->howto->complain_on_overflow
494		     == complain_overflow_signed)
495		  : (rel->howto->complain_on_overflow
496		     == complain_overflow_bitfield))
497	      && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
498
499  if (l_rsecnm == 0)
500    *secp = code_sec;
501  else if (l_rsecnm == 1)
502    {
503      *secp = data_sec;
504      l_vaddr -= code_sec->size;
505    }
506  else
507    {
508      bfd_set_error (bfd_error_bad_value);
509      return FALSE;
510    }
511
512  rel->address = l_vaddr;
513
514  return TRUE;
515}
516
517#else /* not OLDFORMAT */
518
519/* There is only one type of reloc in a PowerPC NLM.  */
520
521static reloc_howto_type nlm_powerpc_howto =
522  HOWTO (0,			/* Type.  */
523	 0,			/* Rightshift.  */
524	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
525	 32,			/* Bitsize.  */
526	 FALSE,			/* PC relative.  */
527	 0,			/* Bitpos.  */
528	 complain_overflow_bitfield, /* Complain_on_overflow.  */
529	 0,			/* Special_function.  */
530	 "32",			/* Name.  */
531	 TRUE,			/* Partial_inplace.  */
532	 0xffffffff,		/* Source mask.  */
533	 0xffffffff,		/* Dest mask.  */
534	 FALSE);		/* PC rel_offset.  */
535
536/* Read a PowerPC NLM reloc.  */
537
538static bfd_boolean
539nlm_powerpc_read_reloc (bfd *abfd,
540			nlmNAME (symbol_type) *sym,
541			asection **secp,
542			arelent *rel)
543{
544  bfd_byte temp[4];
545  bfd_vma val;
546  const char *name;
547
548  if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
549    return FALSE;
550
551  val = bfd_get_32 (abfd, temp);
552
553  /* The value is a word offset into either the code or data segment.
554     This is the location which needs to be adjusted.
555
556     The high bit is 0 if the value is an offset into the data
557     segment, or 1 if the value is an offset into the text segment.
558
559     If this is a relocation fixup rather than an imported symbol (the
560     sym argument is NULL), then the second most significant bit is 0
561     if the address of the data segment should be added to the
562     location addressed by the value, or 1 if the address of the text
563     segment should be added.
564
565     If this is an imported symbol, the second most significant bit is
566     not used and must be 0.  */
567
568  if ((val & NLM_HIBIT) == 0)
569    name = NLM_INITIALIZED_DATA_NAME;
570  else
571    {
572      name = NLM_CODE_NAME;
573      val &=~ NLM_HIBIT;
574    }
575  *secp = bfd_get_section_by_name (abfd, name);
576
577  if (sym == NULL)
578    {
579      if ((val & (NLM_HIBIT >> 1)) == 0)
580	name = NLM_INITIALIZED_DATA_NAME;
581      else
582	{
583	  name = NLM_CODE_NAME;
584	  val &=~ (NLM_HIBIT >> 1);
585	}
586      rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
587    }
588
589  rel->howto   = & nlm_powerpc_howto;
590  rel->address = val << 2;
591  rel->addend  = 0;
592
593  return TRUE;
594}
595
596#endif /* not OLDFORMAT */
597
598/* Mangle PowerPC NLM relocs for output.  */
599
600static bfd_boolean
601nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
602			   asection *sec ATTRIBUTE_UNUSED,
603			   const void * data ATTRIBUTE_UNUSED,
604			   bfd_vma offset ATTRIBUTE_UNUSED,
605			   bfd_size_type count ATTRIBUTE_UNUSED)
606{
607  return TRUE;
608}
609
610/* Read a PowerPC NLM import record */
611
612static bfd_boolean
613nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
614{
615  struct nlm_relent *nlm_relocs;	/* Relocation records for symbol.  */
616  bfd_size_type rcount;			/* Number of relocs.  */
617  bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* Temporary 32-bit value.  */
618  unsigned char symlength;		/* Length of symbol name.  */
619  char *name;
620
621  if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
622      != sizeof (symlength))
623    return FALSE;
624  sym -> symbol.the_bfd = abfd;
625  name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
626  if (name == NULL)
627    return FALSE;
628  if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
629    return FALSE;
630  name[symlength] = '\0';
631  sym -> symbol.name = name;
632  sym -> symbol.flags = 0;
633  sym -> symbol.value = 0;
634  sym -> symbol.section = bfd_und_section_ptr;
635  if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
636      != sizeof (temp))
637    return FALSE;
638  rcount = H_GET_32 (abfd, temp);
639  nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
640  if (nlm_relocs == NULL)
641    return FALSE;
642  sym -> relocs = nlm_relocs;
643  sym -> rcnt = 0;
644  while (sym -> rcnt < rcount)
645    {
646      asection *section;
647
648      if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
649	return FALSE;
650      nlm_relocs -> section = section;
651      nlm_relocs++;
652      sym -> rcnt++;
653    }
654  return TRUE;
655}
656
657#ifndef OLDFORMAT
658
659/* Write a PowerPC NLM reloc.  */
660
661static bfd_boolean
662nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
663{
664  asymbol *sym;
665  bfd_vma val;
666  bfd_byte temp[4];
667
668  /* PowerPC NetWare only supports one kind of reloc.  */
669  if (rel->addend != 0
670      || rel->howto == NULL
671      || rel->howto->rightshift != 0
672      || rel->howto->size != 2
673      || rel->howto->bitsize != 32
674      || rel->howto->bitpos != 0
675      || rel->howto->pc_relative
676      || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
677      || rel->howto->dst_mask != 0xffffffff)
678    {
679      bfd_set_error (bfd_error_invalid_operation);
680      return FALSE;
681    }
682
683  sym = *rel->sym_ptr_ptr;
684
685  /* The value we write out is the offset into the appropriate
686     segment, rightshifted by two.  This offset is the section vma,
687     adjusted by the vma of the lowest section in that segment, plus
688     the address of the relocation.  */
689  val = bfd_get_section_vma (abfd, sec) + rel->address;
690  if ((val & 3) != 0)
691    {
692      bfd_set_error (bfd_error_bad_value);
693      return FALSE;
694    }
695  val >>= 2;
696
697  /* The high bit is 0 if the reloc is in the data section, or 1 if
698     the reloc is in the code section.  */
699  if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
700    val -= nlm_get_data_low (abfd);
701  else
702    {
703      val -= nlm_get_text_low (abfd);
704      val |= NLM_HIBIT;
705    }
706
707  if (! bfd_is_und_section (bfd_get_section (sym)))
708    {
709      /* This is an internal relocation fixup.  The second most
710	 significant bit is 0 if this is a reloc against the data
711	 segment, or 1 if it is a reloc against the text segment.  */
712      if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
713	val |= NLM_HIBIT >> 1;
714    }
715
716  bfd_put_32 (abfd, val, temp);
717  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
718    return FALSE;
719
720  return TRUE;
721}
722
723#else /* OLDFORMAT */
724
725/* This is used for the reloc handling in the old format.  */
726
727/* Write a PowerPC NLM reloc.  */
728
729static bfd_boolean
730nlm_powerpc_write_reloc (bfd *abfd,
731			 asection *sec,
732			 arelent *rel,
733			 int indx)
734{
735  struct nlm32_powerpc_external_reloc ext;
736  asection *code_sec, *data_sec, *bss_sec;
737  asymbol *sym;
738  asection *symsec;
739  unsigned long l_symndx;
740  int l_rtype;
741  int l_rsecnm;
742  reloc_howto_type *howto;
743  bfd_size_type address;
744
745  /* Get the sections now, for convenience.  */
746  code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
747  data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
748  bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
749
750  sym = *rel->sym_ptr_ptr;
751  symsec = bfd_get_section (sym);
752  if (indx != -1)
753    {
754      BFD_ASSERT (bfd_is_und_section (symsec));
755      l_symndx = indx + 3;
756    }
757  else
758    {
759      if (symsec == code_sec)
760	l_symndx = 0;
761      else if (symsec == data_sec)
762	l_symndx = 1;
763      else if (symsec == bss_sec)
764	l_symndx = 2;
765      else
766	{
767	  bfd_set_error (bfd_error_bad_value);
768	  return FALSE;
769	}
770    }
771
772  H_PUT_32 (abfd, l_symndx, ext.l_symndx);
773
774  for (howto = nlm_powerpc_howto_table;
775       howto < nlm_powerpc_howto_table + HOWTO_COUNT;
776       howto++)
777    {
778      if (howto->rightshift == rel->howto->rightshift
779	  && howto->size == rel->howto->size
780	  && howto->bitsize == rel->howto->bitsize
781	  && howto->pc_relative == rel->howto->pc_relative
782	  && howto->bitpos == rel->howto->bitpos
783	  && (howto->partial_inplace == rel->howto->partial_inplace
784	      || (! rel->howto->partial_inplace
785		  && rel->addend == 0))
786	  && (howto->src_mask == rel->howto->src_mask
787	      || (rel->howto->src_mask == 0
788		  && rel->addend == 0))
789	  && howto->dst_mask == rel->howto->dst_mask
790	  && howto->pcrel_offset == rel->howto->pcrel_offset)
791	break;
792    }
793  if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
794    {
795      bfd_set_error (bfd_error_bad_value);
796      return FALSE;
797    }
798
799  l_rtype = howto->type;
800  if (howto->complain_on_overflow == complain_overflow_signed)
801    l_rtype |= 0x8000;
802  l_rtype |= (howto->bitsize - 1) << 8;
803  H_PUT_16 (abfd, l_rtype, ext.l_rtype);
804
805  address = rel->address;
806
807  if (sec == code_sec)
808    l_rsecnm = 0;
809  else if (sec == data_sec)
810    {
811      l_rsecnm = 1;
812      address += code_sec->size;
813    }
814  else
815    {
816      bfd_set_error (bfd_error_bad_value);
817      return FALSE;
818    }
819
820  H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
821  H_PUT_32 (abfd, address, ext.l_vaddr);
822
823  if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
824    return FALSE;
825
826  return TRUE;
827}
828
829/* Write a PowerPC NLM import.  */
830
831static bfd_boolean
832nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
833{
834  return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
835}
836
837#endif /* OLDFORMAT */
838
839/* Write a PowerPC NLM external symbol.  This routine keeps a static
840   count of the symbol index.  FIXME: I don't know if this is
841   necessary, and the index never gets reset.  */
842
843static bfd_boolean
844nlm_powerpc_write_external (bfd *abfd,
845			    bfd_size_type count,
846			    asymbol *sym,
847			    struct reloc_and_sec *relocs)
848{
849  unsigned int i;
850  bfd_byte len;
851  unsigned char temp[NLM_TARGET_LONG_SIZE];
852#ifdef OLDFORMAT
853  static int indx;
854#endif
855
856  len = strlen (sym->name);
857  if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
858       != sizeof (bfd_byte))
859      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
860    return FALSE;
861
862  bfd_put_32 (abfd, count, temp);
863  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
864    return FALSE;
865
866  for (i = 0; i < count; i++)
867    {
868#ifndef OLDFORMAT
869      if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
870	return FALSE;
871#else
872      if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
873				     relocs[i].rel, indx))
874	return FALSE;
875#endif
876    }
877
878#ifdef OLDFORMAT
879  ++indx;
880#endif
881
882  return TRUE;
883}
884
885#ifndef OLDFORMAT
886
887/* PowerPC Netware uses a word offset, not a byte offset, for public
888   symbols.  */
889
890/* Set the section for a public symbol.  */
891
892static bfd_boolean
893nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
894{
895  if (sym->symbol.value & NLM_HIBIT)
896    {
897      sym->symbol.value &= ~NLM_HIBIT;
898      sym->symbol.flags |= BSF_FUNCTION;
899      sym->symbol.section =
900	bfd_get_section_by_name (abfd, NLM_CODE_NAME);
901    }
902  else
903    sym->symbol.section =
904      bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
905
906  sym->symbol.value <<= 2;
907
908  return TRUE;
909}
910
911/* Get the offset to write out for a public symbol.  */
912
913static bfd_vma
914nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
915{
916  bfd_vma offset;
917  asection *sec;
918
919  offset = bfd_asymbol_value (sym);
920  sec = bfd_get_section (sym);
921  if (sec->flags & SEC_CODE)
922    {
923      offset -= nlm_get_text_low (abfd);
924      offset |= NLM_HIBIT;
925    }
926  else if (sec->flags & (SEC_DATA | SEC_ALLOC))
927    {
928      /* SEC_ALLOC is for the .bss section.  */
929      offset -= nlm_get_data_low (abfd);
930    }
931  else
932    {
933      /* We can't handle an exported symbol that is not in the code or
934	 data segment.  */
935      bfd_set_error (bfd_error_invalid_operation);
936      /* FIXME: No way to return error.  */
937      abort ();
938    }
939
940  return offset;
941}
942
943#endif /* ! defined (OLDFORMAT) */
944
945#include "nlmswap.h"
946
947static const struct nlm_backend_data nlm32_powerpc_backend =
948{
949  "NetWare PowerPC Module \032",
950  sizeof (Nlm32_powerpc_External_Fixed_Header),
951#ifndef OLDFORMAT
952  0,	/* Optional_prefix_size.  */
953#else
954  sizeof (struct nlm32_powerpc_external_prefix_header),
955#endif
956  bfd_arch_powerpc,
957  0,
958  FALSE,
959#ifndef OLDFORMAT
960  0,	/* Backend_object_p.  */
961  0,	/* Write_prefix.  */
962#else
963  nlm_powerpc_backend_object_p,
964  nlm_powerpc_write_prefix,
965#endif
966  nlm_powerpc_read_reloc,
967  nlm_powerpc_mangle_relocs,
968  nlm_powerpc_read_import,
969  nlm_powerpc_write_import,
970#ifndef OLDFORMAT
971  nlm_powerpc_set_public_section,
972  nlm_powerpc_get_public_offset,
973#else
974  0,	/* Set_public_section.  */
975  0,	/* Get_public_offset.  */
976#endif
977  nlm_swap_fixed_header_in,
978  nlm_swap_fixed_header_out,
979  nlm_powerpc_write_external,
980  0,	/* Write_export.  */
981};
982
983#define TARGET_BIG_NAME			"nlm32-powerpc"
984#define TARGET_BIG_SYM			nlmNAME (powerpc_vec)
985#define TARGET_BACKEND_DATA		& nlm32_powerpc_backend
986
987#include "nlm-target.h"
988