150472Speter/* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
237Srgrimes   Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004,
337Srgrimes   2005 Free Software Foundation, Inc.
437Srgrimes
537Srgrimes   This file is part of BFD, the Binary File Descriptor library.
637Srgrimes
737Srgrimes   This program is free software; you can redistribute it and/or modify
837Srgrimes   it under the terms of the GNU General Public License as published by
937Srgrimes   the Free Software Foundation; either version 2 of the License, or
109306Sbde   (at your option) any later version.
1137Srgrimes
12646Sdg   This program is distributed in the hope that it will be useful,
139306Sbde   but WITHOUT ANY WARRANTY; without even the implied warranty of
14646Sdg   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
156489Sjoerg   GNU General Public License for more details.
166489Sjoerg
176489Sjoerg   You should have received a copy of the GNU General Public License
186489Sjoerg   along with this program; if not, write to the Free Software
196489Sjoerg   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
209306Sbde
219306Sbde#include "bfd.h"
22119915Syar#include "sysdep.h"
23646Sdg#include "libbfd.h"
24646Sdg
25646Sdg/* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
26119915Syar   old format.  */
27646Sdg
28646Sdg#define ARCH_SIZE 32
29646Sdg
30646Sdg#include "nlm/ppc-ext.h"
31646Sdg#define Nlm_External_Fixed_Header	Nlm32_powerpc_External_Fixed_Header
32646Sdg
336489Sjoerg#include "libnlm.h"
34646Sdg
35119915Syar#ifdef OLDFORMAT
36119915Syar
37646Sdg/* The prefix header is only used in the old format.  */
3837Srgrimes
3970164Sphk/* PowerPC NLM's have a prefix header before the standard NLM.  This
4070164Sphk   function reads it in, verifies the version, and seeks the bfd to
4137Srgrimes   the location before the regular NLM header.  */
4237Srgrimes
4337Srgrimesstatic bfd_boolean
4437Srgrimesnlm_powerpc_backend_object_p (bfd *abfd)
4537Srgrimes{
4637Srgrimes  struct nlm32_powerpc_external_prefix_header s;
4737Srgrimes
4837Srgrimes  if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
4937Srgrimes    return FALSE;
5037Srgrimes
5137Srgrimes  if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
5237Srgrimes      || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
53862Sache    return FALSE;
5437Srgrimes
55862Sache  return TRUE;
5637Srgrimes}
57862Sache
5837Srgrimes/* Write out the prefix.  */
59862Sache
6037Srgrimesstatic bfd_boolean
61862Sachenlm_powerpc_write_prefix (bfd *abfd)
6237Srgrimes{
63862Sache  struct nlm32_powerpc_external_prefix_header s;
6437Srgrimes
65862Sache  memset (&s, 0, sizeof s);
6637Srgrimes  memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
67862Sache  H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
6837Srgrimes  H_PUT_32 (abfd, 0, s.origins);
69862Sache
7037Srgrimes  /* FIXME: What should we do about the date?  */
71862Sache
72154Srgrimes  if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
73862Sache    return FALSE;
74154Srgrimes
75862Sache  return TRUE;
76154Srgrimes}
77862Sache
7837818Sphk/* This reloc handling is only applicable to the old format.  */
7937818Sphk
8037Srgrimes/* How to process the various reloc types.  PowerPC NLMs use XCOFF
8137Srgrimes   reloc types, and I have just copied the XCOFF reloc table here.  */
8229610Sjoerg
8329610Sjoergstatic reloc_howto_type nlm_powerpc_howto_table[] =
8429610Sjoerg{
8529610Sjoerg  /* Standard 32 bit relocation.  */
8629610Sjoerg  HOWTO (0,	                /* Type.  */
8729610Sjoerg	 0,	                /* Rightshift.  */
8829610Sjoerg	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
8929610Sjoerg	 32,	                /* Bitsize.  */
9029610Sjoerg	 FALSE,	                /* PC relative.  */
9129610Sjoerg	 0,	                /* Bitpos.  */
9229610Sjoerg	 complain_overflow_bitfield, /* Complain_on_overflow.  */
9329610Sjoerg	 0,		        /* Special_function.  */
9429610Sjoerg	 "R_POS",               /* Name.  */
9529610Sjoerg	 TRUE,	                /* Partial_inplace.  */
9629610Sjoerg	 0xffffffff,            /* Source mask.  */
9729610Sjoerg	 0xffffffff,            /* Dest mask.  */
9829610Sjoerg	 FALSE),                /* PC rel offset.  */
9929610Sjoerg
10029610Sjoerg  /* 32 bit relocation, but store negative value.  */
10129610Sjoerg  HOWTO (1,	                /* Type.  */
10237Srgrimes	 0,	                /* Rightshift.  */
10337Srgrimes	 -2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
10437Srgrimes	 32,	                /* Bitsize.  */
10537Srgrimes	 FALSE,	                /* PC relative.  */
10637Srgrimes	 0,	                /* Bitpos.  */
10737Srgrimes	 complain_overflow_bitfield, /* Complain_on_overflow.  */
10837Srgrimes	 0,		        /* Special_function.  */
10937Srgrimes	 "R_NEG",               /* Name.  */
11037Srgrimes	 TRUE,	                /* Partial_inplace.  */
11137Srgrimes	 0xffffffff,            /* Source mask.  */
11237Srgrimes	 0xffffffff,            /* Dest mask.  */
11337Srgrimes	 FALSE),                /* PC rel offset.  */
11437Srgrimes
11537Srgrimes  /* 32 bit PC relative relocation.  */
11637Srgrimes  HOWTO (2,	                /* Type.  */
11737Srgrimes	 0,	                /* Rightshift.  */
11837Srgrimes	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
11937Srgrimes	 32,	                /* Bitsize.  */
12037Srgrimes	 TRUE,	                /* PC relative.  */
12137Srgrimes	 0,	                /* Bitpos.  */
12237Srgrimes	 complain_overflow_signed, /* Complain_on_overflow.  */
12337Srgrimes	 0,		        /* Special_function.  */
12437Srgrimes	 "R_REL",               /* Name.  */
12537Srgrimes	 TRUE,	                /* Partial_inplace.  */
12637Srgrimes	 0xffffffff,            /* Source mask.  */
12737Srgrimes	 0xffffffff,            /* Dest mask.  */
12837Srgrimes	 FALSE),                /* PC rel offset.  */
12937Srgrimes
13037Srgrimes  /* 16 bit TOC relative relocation.  */
13137Srgrimes  HOWTO (3,	                /* Type.  */
13237Srgrimes	 0,	                /* Rightshift.  */
13337Srgrimes	 1,	                /* Size (0 = byte, 1 = short, 2 = long).  */
13437Srgrimes	 16,	                /* Bitsize.  */
13537Srgrimes	 FALSE,	                /* PC relative.  */
13637Srgrimes	 0,	                /* Bitpos.  */
137289Srgrimes	 complain_overflow_signed, /* Complain_on_overflow.  */
13837Srgrimes	 0,		        /* Special_function.  */
13937Srgrimes	 "R_TOC",               /* Name.  */
14037Srgrimes	 TRUE,	                /* Partial_inplace.  */
14137Srgrimes	 0xffff,	        /* Source mask.  */
14237Srgrimes	 0xffff,        	/* Dest mask.  */
14337Srgrimes	 FALSE),                /* PC rel offset.  */
14437Srgrimes
14537Srgrimes  /* I don't really know what this is.  */
14637Srgrimes  HOWTO (4,	                /* Type.  */
14737Srgrimes	 1,	                /* Rightshift.  */
14837Srgrimes	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
14937Srgrimes	 32,	                /* Bitsize.  */
15037Srgrimes	 FALSE,	                /* PC relative.  */
15137Srgrimes	 0,	                /* Bitpos.  */
15237Srgrimes	 complain_overflow_bitfield, /* Complain_on_overflow.  */
15337Srgrimes	 0,		        /* Special_function.  */
15437Srgrimes	 "R_RTB",               /* Name.  */
15537Srgrimes	 TRUE,	                /* Partial_inplace.  */
15637Srgrimes	 0xffffffff,	        /* Source mask.  */
15737Srgrimes	 0xffffffff,        	/* Dest mask.  */
15837Srgrimes	 FALSE),                /* PC rel offset.  */
15937Srgrimes
16037Srgrimes  /* External TOC relative symbol.  */
16137Srgrimes  HOWTO (5,	                /* Type.  */
16237Srgrimes	 0,	                /* Rightshift.  */
16337Srgrimes	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
16437Srgrimes	 16,	                /* Bitsize.  */
1651096Sache	 FALSE,	                /* PC relative.  */
16637Srgrimes	 0,	                /* Bitpos.  */
16737Srgrimes	 complain_overflow_bitfield, /* Complain_on_overflow.  */
16837Srgrimes	 0,		        /* Special_function.  */
16937Srgrimes	 "R_GL",                /* Name.  */
17037Srgrimes	 TRUE,	                /* Partial_inplace.  */
17137Srgrimes	 0xffff,	        /* Source mask.  */
17237Srgrimes	 0xffff,        	/* Dest mask.  */
17337Srgrimes	 FALSE),                /* PC rel offset.  */
17437Srgrimes
17537Srgrimes  /* Local TOC relative symbol.  */
17637Srgrimes  HOWTO (6,	                /* Type.  */
17737Srgrimes	 0,	                /* Rightshift.  */
17837Srgrimes	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
17937Srgrimes	 16,	                /* Bitsize.  */
18037Srgrimes	 FALSE,	                /* PC relative.  */
18137Srgrimes	 0,	                /* Bitpos.  */
18237Srgrimes	 complain_overflow_bitfield, /* Complain_on_overflow.  */
18337Srgrimes	 0,		        /* Special_function.  */
18437Srgrimes	 "R_TCL",               /* Name.  */
18537Srgrimes	 TRUE,	                /* Partial_inplace.  */
18637Srgrimes	 0xffff,	        /* Source mask.  */
18737Srgrimes	 0xffff,        	/* Dest mask.  */
18837Srgrimes	 FALSE),                /* PC rel offset.  */
18937Srgrimes
19037Srgrimes  { 7 },
19137Srgrimes
19237Srgrimes  /* Non modifiable absolute branch.  */
19337Srgrimes  HOWTO (8,	                /* Type.  */
19437Srgrimes	 0,	                /* Rightshift.  */
19537Srgrimes	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
19637Srgrimes	 26,	                /* Bitsize.  */
19737Srgrimes	 FALSE,	                /* PC relative.  */
19837Srgrimes	 0,	                /* Bitpos.  */
19937Srgrimes	 complain_overflow_bitfield, /* Complain_on_overflow.  */
20061513Sphk	 0,		        /* Special_function.  */
20161513Sphk	 "R_BA",                /* Name.  */
20261513Sphk	 TRUE,	                /* Partial_inplace.  */
20361513Sphk	 0x3fffffc,	        /* Source mask.  */
20461513Sphk	 0x3fffffc,        	/* Dest mask.  */
20561513Sphk	 FALSE),                /* PC rel offset.  */
20661513Sphk
20782700Smurray  { 9 },
208130151Sschweikh
20982700Smurray  /* Non modifiable relative branch.  */
21082700Smurray  HOWTO (0xa,	                /* Type.  */
21182700Smurray	 0,	                /* Rightshift.  */
21282700Smurray	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
21382700Smurray	 26,	                /* Bitsize.  */
214154685Smatteo	 TRUE,	                /* PC relative.  */
215154685Smatteo	 0,	                /* Bitpos.  */
21682700Smurray	 complain_overflow_signed, /* Complain_on_overflow.  */
21782700Smurray	 0,		        /* Special_function.  */
21882700Smurray	 "R_BR",                /* Name.  */
21982700Smurray	 TRUE,	                /* Partial_inplace.  */
22082700Smurray	 0x3fffffc,	        /* Source mask.  */
22182700Smurray	 0x3fffffc,        	/* Dest mask.  */
22282700Smurray	 FALSE),                /* PC rel offset.  */
22382700Smurray
224  { 0xb },
225
226  /* Indirect load.  */
227  HOWTO (0xc,	                /* Type.  */
228	 0,	                /* Rightshift.  */
229	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
230	 16,	                /* Bitsize.  */
231	 FALSE,	                /* PC relative.  */
232	 0,	                /* Bitpos.  */
233	 complain_overflow_bitfield, /* Complain_on_overflow.  */
234	 0,		        /* Special_function.  */
235	 "R_RL",                /* Name.  */
236	 TRUE,	                /* Partial_inplace.  */
237	 0xffff,	        /* Source mask.  */
238	 0xffff,        	/* Dest mask.  */
239	 FALSE),                /* PC rel offset.  */
240
241  /* Load address.  */
242  HOWTO (0xd,	                /* Type.  */
243	 0,	                /* Rightshift.  */
244	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
245	 16,	                /* Bitsize.  */
246	 FALSE,	                /* PC relative.  */
247	 0,	                /* Bitpos.  */
248	 complain_overflow_bitfield, /* Complain_on_overflow.  */
249	 0,		        /* Special_function.  */
250	 "R_RLA",               /* Name.  */
251	 TRUE,	                /* Partial_inplace.  */
252	 0xffff,	        /* Source mask.  */
253	 0xffff,        	/* Dest mask.  */
254	 FALSE),                /* PC rel offset.  */
255
256  { 0xe },
257
258  /* Non-relocating reference.  */
259  HOWTO (0xf,	                /* Type.  */
260	 0,	                /* Rightshift.  */
261	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
262	 32,	                /* Bitsize.  */
263	 FALSE,	                /* PC relative.  */
264	 0,	                /* Bitpos.  */
265	 complain_overflow_bitfield, /* Complain_on_overflow.  */
266	 0,		        /* Special_function.  */
267	 "R_REF",               /* Name.  */
268	 FALSE,	                /* Partial_inplace.  */
269	 0,		        /* Source mask.  */
270	 0,     	   	/* Dest mask.  */
271	 FALSE),                /* PC rel offset.  */
272
273  { 0x10 },
274  { 0x11 },
275
276  /* TOC relative indirect load.  */
277  HOWTO (0x12,	                /* Type.  */
278	 0,	                /* Rightshift.  */
279	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
280	 16,	                /* Bitsize.  */
281	 FALSE,	                /* PC relative.  */
282	 0,	                /* Bitpos.  */
283	 complain_overflow_bitfield, /* Complain_on_overflow.  */
284	 0,		        /* Special_function.  */
285	 "R_TRL",               /* Name.  */
286	 TRUE,	                /* Partial_inplace.  */
287	 0xffff,	        /* Source mask.  */
288	 0xffff,        	/* Dest mask.  */
289	 FALSE),                /* PC rel offset.  */
290
291  /* TOC relative load address.  */
292  HOWTO (0x13,	                /* Type.  */
293	 0,	                /* Rightshift.  */
294	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
295	 16,	                /* Bitsize.  */
296	 FALSE,	                /* PC relative.  */
297	 0,	                /* Bitpos.  */
298	 complain_overflow_bitfield, /* Complain_on_overflow.  */
299	 0,		        /* Special_function.  */
300	 "R_TRLA",              /* Name.  */
301	 TRUE,	                /* Partial_inplace.  */
302	 0xffff,	        /* Source mask.  */
303	 0xffff,        	/* Dest mask.  */
304	 FALSE),                /* PC rel offset.  */
305
306  /* Modifiable relative branch.  */
307  HOWTO (0x14,	                /* Type.  */
308	 1,	                /* Rightshift.  */
309	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
310	 32,	                /* Bitsize.  */
311	 FALSE,	                /* PC relative.  */
312	 0,	                /* Bitpos.  */
313	 complain_overflow_bitfield, /* Complain_on_overflow.  */
314	 0,		        /* Special_function.  */
315	 "R_RRTBI",             /* Name.  */
316	 TRUE,	                /* Partial_inplace.  */
317	 0xffffffff,	        /* Source mask.  */
318	 0xffffffff,        	/* Dest mask.  */
319	 FALSE),                /* PC rel offset.  */
320
321  /* Modifiable absolute branch.  */
322  HOWTO (0x15,	                /* Type.  */
323	 1,	                /* Rightshift.  */
324	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
325	 32,	                /* Bitsize.  */
326	 FALSE,	                /* PC relative.  */
327	 0,	                /* Bitpos.  */
328	 complain_overflow_bitfield, /* Complain_on_overflow.  */
329	 0,		        /* Special_function.  */
330	 "R_RRTBA",             /* Name.  */
331	 TRUE,	                /* Partial_inplace.  */
332	 0xffffffff,	        /* Source mask.  */
333	 0xffffffff,        	/* Dest mask.  */
334	 FALSE),                /* PC rel offset.  */
335
336  /* Modifiable call absolute indirect.  */
337  HOWTO (0x16,	                /* Type.  */
338	 0,	                /* Rightshift.  */
339	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
340	 16,	                /* Bitsize.  */
341	 FALSE,	                /* PC relative.  */
342	 0,	                /* Bitpos.  */
343	 complain_overflow_bitfield, /* Complain_on_overflow.  */
344	 0,		        /* Special_function.  */
345	 "R_CAI",               /* Name.  */
346	 TRUE,	                /* Partial_inplace.  */
347	 0xffff,	        /* Source mask.  */
348	 0xffff,        	/* Dest mask.  */
349	 FALSE),                /* PC rel offset.  */
350
351  /* Modifiable call relative.  */
352  HOWTO (0x17,	                /* Type.  */
353	 0,	                /* Rightshift.  */
354	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
355	 16,	                /* Bitsize.  */
356	 FALSE,	                /* PC relative.  */
357	 0,	                /* Bitpos.  */
358	 complain_overflow_bitfield, /* Complain_on_overflow.  */
359	 0,		        /* Special_function.  */
360	 "R_REL",               /* Name.  */
361	 TRUE,	                /* Partial_inplace.  */
362	 0xffff,	        /* Source mask.  */
363	 0xffff,        	/* Dest mask.  */
364	 FALSE),                /* PC rel offset.  */
365
366  /* Modifiable branch absolute.  */
367  HOWTO (0x18,	                /* Type.  */
368	 0,	                /* Rightshift.  */
369	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
370	 16,	                /* Bitsize.  */
371	 FALSE,	                /* PC relative.  */
372	 0,	                /* Bitpos.  */
373	 complain_overflow_bitfield, /* Complain_on_overflow.  */
374	 0,		        /* Special_function.  */
375	 "R_RBA",               /* Name.  */
376	 TRUE,	                /* Partial_inplace.  */
377	 0xffff,	        /* Source mask.  */
378	 0xffff,        	/* Dest mask.  */
379	 FALSE),                /* PC rel offset.  */
380
381  /* Modifiable branch absolute.  */
382  HOWTO (0x19,	                /* Type.  */
383	 0,	                /* Rightshift.  */
384	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
385	 16,	                /* Bitsize.  */
386	 FALSE,	                /* PC relative.  */
387	 0,	                /* Bitpos.  */
388	 complain_overflow_bitfield, /* Complain_on_overflow.  */
389	 0,		        /* Special_function.  */
390	 "R_RBAC",              /* Name.  */
391	 TRUE,	                /* Partial_inplace.  */
392	 0xffff,	        /* Source mask.  */
393	 0xffff,        	/* Dest mask.  */
394	 FALSE),                /* PC rel offset.  */
395
396  /* Modifiable branch relative.  */
397  HOWTO (0x1a,	                /* Type.  */
398	 0,	                /* Rightshift.  */
399	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
400	 26,	                /* Bitsize.  */
401	 FALSE,	                /* PC relative.  */
402	 0,	                /* Bitpos.  */
403	 complain_overflow_signed, /* Complain_on_overflow.  */
404	 0,		        /* Special_function.  */
405	 "R_REL",               /* Name.  */
406	 TRUE,	                /* Partial_inplace.  */
407	 0xffff,	        /* Source mask.  */
408	 0xffff,        	/* Dest mask.  */
409	 FALSE),                /* PC rel offset.  */
410
411  /* Modifiable branch absolute.  */
412  HOWTO (0x1b,	                /* Type.  */
413	 0,	                /* Rightshift.  */
414	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
415	 16,	                /* Bitsize.  */
416	 FALSE,	                /* PC relative.  */
417	 0,	                /* Bitpos.  */
418	 complain_overflow_bitfield, /* Complain_on_overflow.  */
419	 0,		        /* Special_function.  */
420	 "R_REL",               /* Name.  */
421	 TRUE,	                /* Partial_inplace.  */
422	 0xffff,	        /* Source mask.  */
423	 0xffff,        	/* Dest mask.  */
424	 FALSE)                 /* PC rel offset.  */
425};
426
427#define HOWTO_COUNT (sizeof nlm_powerpc_howto_table		\
428		     / sizeof nlm_powerpc_howto_table[0])
429
430/* Read a PowerPC NLM reloc.  */
431
432static bfd_boolean
433nlm_powerpc_read_reloc (bfd *abfd,
434			nlmNAME (symbol_type) *sym,
435			asection **secp,
436			arelent *rel)
437{
438  struct nlm32_powerpc_external_reloc ext;
439  bfd_vma l_vaddr;
440  unsigned long l_symndx;
441  int l_rtype;
442  int l_rsecnm;
443  asection *code_sec, *data_sec, *bss_sec;
444
445  /* Read the reloc from the file.  */
446  if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
447    return FALSE;
448
449  /* Swap in the fields.  */
450  l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
451  l_symndx = H_GET_32 (abfd, ext.l_symndx);
452  l_rtype = H_GET_16 (abfd, ext.l_rtype);
453  l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
454
455  /* Get the sections now, for convenience.  */
456  code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
457  data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
458  bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
459
460  /* Work out the arelent fields.  */
461  if (sym != NULL)
462    /* This is an import.  sym_ptr_ptr is filled in by
463       nlm_canonicalize_reloc.  */
464    rel->sym_ptr_ptr = NULL;
465  else
466    {
467      asection *sec;
468
469      if (l_symndx == 0)
470	sec = code_sec;
471      else if (l_symndx == 1)
472	sec = data_sec;
473      else if (l_symndx == 2)
474	sec = bss_sec;
475      else
476	{
477	  bfd_set_error (bfd_error_bad_value);
478	  return FALSE;
479	}
480
481      rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
482    }
483
484  rel->addend = 0;
485
486  BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
487
488  rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
489
490  BFD_ASSERT (rel->howto->name != NULL
491	      && ((l_rtype & 0x8000) != 0
492		  ? (rel->howto->complain_on_overflow
493		     == complain_overflow_signed)
494		  : (rel->howto->complain_on_overflow
495		     == complain_overflow_bitfield))
496	      && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
497
498  if (l_rsecnm == 0)
499    *secp = code_sec;
500  else if (l_rsecnm == 1)
501    {
502      *secp = data_sec;
503      l_vaddr -= code_sec->size;
504    }
505  else
506    {
507      bfd_set_error (bfd_error_bad_value);
508      return FALSE;
509    }
510
511  rel->address = l_vaddr;
512
513  return TRUE;
514}
515
516#else /* not OLDFORMAT */
517
518/* There is only one type of reloc in a PowerPC NLM.  */
519
520static reloc_howto_type nlm_powerpc_howto =
521  HOWTO (0,			/* Type.  */
522	 0,			/* Rightshift.  */
523	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
524	 32,			/* Bitsize.  */
525	 FALSE,			/* PC relative.  */
526	 0,			/* Bitpos.  */
527	 complain_overflow_bitfield, /* Complain_on_overflow.  */
528	 0,			/* Special_function.  */
529	 "32",			/* Name.  */
530	 TRUE,			/* Partial_inplace.  */
531	 0xffffffff,		/* Source mask.  */
532	 0xffffffff,		/* Dest mask.  */
533	 FALSE);		/* PC rel_offset.  */
534
535/* Read a PowerPC NLM reloc.  */
536
537static bfd_boolean
538nlm_powerpc_read_reloc (bfd *abfd,
539			nlmNAME (symbol_type) *sym,
540			asection **secp,
541			arelent *rel)
542{
543  bfd_byte temp[4];
544  bfd_vma val;
545  const char *name;
546
547  if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
548    return FALSE;
549
550  val = bfd_get_32 (abfd, temp);
551
552  /* The value is a word offset into either the code or data segment.
553     This is the location which needs to be adjusted.
554
555     The high bit is 0 if the value is an offset into the data
556     segment, or 1 if the value is an offset into the text segment.
557
558     If this is a relocation fixup rather than an imported symbol (the
559     sym argument is NULL), then the second most significant bit is 0
560     if the address of the data segment should be added to the
561     location addressed by the value, or 1 if the address of the text
562     segment should be added.
563
564     If this is an imported symbol, the second most significant bit is
565     not used and must be 0.  */
566
567  if ((val & NLM_HIBIT) == 0)
568    name = NLM_INITIALIZED_DATA_NAME;
569  else
570    {
571      name = NLM_CODE_NAME;
572      val &=~ NLM_HIBIT;
573    }
574  *secp = bfd_get_section_by_name (abfd, name);
575
576  if (sym == NULL)
577    {
578      if ((val & (NLM_HIBIT >> 1)) == 0)
579	name = NLM_INITIALIZED_DATA_NAME;
580      else
581	{
582	  name = NLM_CODE_NAME;
583	  val &=~ (NLM_HIBIT >> 1);
584	}
585      rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
586    }
587
588  rel->howto   = & nlm_powerpc_howto;
589  rel->address = val << 2;
590  rel->addend  = 0;
591
592  return TRUE;
593}
594
595#endif /* not OLDFORMAT */
596
597/* Mangle PowerPC NLM relocs for output.  */
598
599static bfd_boolean
600nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
601			   asection *sec ATTRIBUTE_UNUSED,
602			   const void * data ATTRIBUTE_UNUSED,
603			   bfd_vma offset ATTRIBUTE_UNUSED,
604			   bfd_size_type count ATTRIBUTE_UNUSED)
605{
606  return TRUE;
607}
608
609/* Read a PowerPC NLM import record */
610
611static bfd_boolean
612nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
613{
614  struct nlm_relent *nlm_relocs;	/* Relocation records for symbol.  */
615  bfd_size_type rcount;			/* Number of relocs.  */
616  bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* Temporary 32-bit value.  */
617  unsigned char symlength;		/* Length of symbol name.  */
618  char *name;
619
620  if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
621      != sizeof (symlength))
622    return FALSE;
623  sym -> symbol.the_bfd = abfd;
624  name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
625  if (name == NULL)
626    return FALSE;
627  if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
628    return FALSE;
629  name[symlength] = '\0';
630  sym -> symbol.name = name;
631  sym -> symbol.flags = 0;
632  sym -> symbol.value = 0;
633  sym -> symbol.section = bfd_und_section_ptr;
634  if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
635      != sizeof (temp))
636    return FALSE;
637  rcount = H_GET_32 (abfd, temp);
638  nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
639  if (nlm_relocs == NULL)
640    return FALSE;
641  sym -> relocs = nlm_relocs;
642  sym -> rcnt = 0;
643  while (sym -> rcnt < rcount)
644    {
645      asection *section;
646
647      if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
648	return FALSE;
649      nlm_relocs -> section = section;
650      nlm_relocs++;
651      sym -> rcnt++;
652    }
653  return TRUE;
654}
655
656#ifndef OLDFORMAT
657
658/* Write a PowerPC NLM reloc.  */
659
660static bfd_boolean
661nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
662{
663  asymbol *sym;
664  bfd_vma val;
665  bfd_byte temp[4];
666
667  /* PowerPC NetWare only supports one kind of reloc.  */
668  if (rel->addend != 0
669      || rel->howto == NULL
670      || rel->howto->rightshift != 0
671      || rel->howto->size != 2
672      || rel->howto->bitsize != 32
673      || rel->howto->bitpos != 0
674      || rel->howto->pc_relative
675      || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
676      || rel->howto->dst_mask != 0xffffffff)
677    {
678      bfd_set_error (bfd_error_invalid_operation);
679      return FALSE;
680    }
681
682  sym = *rel->sym_ptr_ptr;
683
684  /* The value we write out is the offset into the appropriate
685     segment, rightshifted by two.  This offset is the section vma,
686     adjusted by the vma of the lowest section in that segment, plus
687     the address of the relocation.  */
688  val = bfd_get_section_vma (abfd, sec) + rel->address;
689  if ((val & 3) != 0)
690    {
691      bfd_set_error (bfd_error_bad_value);
692      return FALSE;
693    }
694  val >>= 2;
695
696  /* The high bit is 0 if the reloc is in the data section, or 1 if
697     the reloc is in the code section.  */
698  if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
699    val -= nlm_get_data_low (abfd);
700  else
701    {
702      val -= nlm_get_text_low (abfd);
703      val |= NLM_HIBIT;
704    }
705
706  if (! bfd_is_und_section (bfd_get_section (sym)))
707    {
708      /* This is an internal relocation fixup.  The second most
709	 significant bit is 0 if this is a reloc against the data
710	 segment, or 1 if it is a reloc against the text segment.  */
711      if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
712	val |= NLM_HIBIT >> 1;
713    }
714
715  bfd_put_32 (abfd, val, temp);
716  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
717    return FALSE;
718
719  return TRUE;
720}
721
722#else /* OLDFORMAT */
723
724/* This is used for the reloc handling in the old format.  */
725
726/* Write a PowerPC NLM reloc.  */
727
728static bfd_boolean
729nlm_powerpc_write_reloc (bfd *abfd,
730			 asection *sec,
731			 arelent *rel,
732			 int indx)
733{
734  struct nlm32_powerpc_external_reloc ext;
735  asection *code_sec, *data_sec, *bss_sec;
736  asymbol *sym;
737  asection *symsec;
738  unsigned long l_symndx;
739  int l_rtype;
740  int l_rsecnm;
741  reloc_howto_type *howto;
742  bfd_size_type address;
743
744  /* Get the sections now, for convenience.  */
745  code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
746  data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
747  bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
748
749  sym = *rel->sym_ptr_ptr;
750  symsec = bfd_get_section (sym);
751  if (indx != -1)
752    {
753      BFD_ASSERT (bfd_is_und_section (symsec));
754      l_symndx = indx + 3;
755    }
756  else
757    {
758      if (symsec == code_sec)
759	l_symndx = 0;
760      else if (symsec == data_sec)
761	l_symndx = 1;
762      else if (symsec == bss_sec)
763	l_symndx = 2;
764      else
765	{
766	  bfd_set_error (bfd_error_bad_value);
767	  return FALSE;
768	}
769    }
770
771  H_PUT_32 (abfd, l_symndx, ext.l_symndx);
772
773  for (howto = nlm_powerpc_howto_table;
774       howto < nlm_powerpc_howto_table + HOWTO_COUNT;
775       howto++)
776    {
777      if (howto->rightshift == rel->howto->rightshift
778	  && howto->size == rel->howto->size
779	  && howto->bitsize == rel->howto->bitsize
780	  && howto->pc_relative == rel->howto->pc_relative
781	  && howto->bitpos == rel->howto->bitpos
782	  && (howto->partial_inplace == rel->howto->partial_inplace
783	      || (! rel->howto->partial_inplace
784		  && rel->addend == 0))
785	  && (howto->src_mask == rel->howto->src_mask
786	      || (rel->howto->src_mask == 0
787		  && rel->addend == 0))
788	  && howto->dst_mask == rel->howto->dst_mask
789	  && howto->pcrel_offset == rel->howto->pcrel_offset)
790	break;
791    }
792  if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
793    {
794      bfd_set_error (bfd_error_bad_value);
795      return FALSE;
796    }
797
798  l_rtype = howto->type;
799  if (howto->complain_on_overflow == complain_overflow_signed)
800    l_rtype |= 0x8000;
801  l_rtype |= (howto->bitsize - 1) << 8;
802  H_PUT_16 (abfd, l_rtype, ext.l_rtype);
803
804  address = rel->address;
805
806  if (sec == code_sec)
807    l_rsecnm = 0;
808  else if (sec == data_sec)
809    {
810      l_rsecnm = 1;
811      address += code_sec->size;
812    }
813  else
814    {
815      bfd_set_error (bfd_error_bad_value);
816      return FALSE;
817    }
818
819  H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
820  H_PUT_32 (abfd, address, ext.l_vaddr);
821
822  if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
823    return FALSE;
824
825  return TRUE;
826}
827
828/* Write a PowerPC NLM import.  */
829
830static bfd_boolean
831nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
832{
833  return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
834}
835
836#endif /* OLDFORMAT */
837
838/* Write a PowerPC NLM external symbol.  This routine keeps a static
839   count of the symbol index.  FIXME: I don't know if this is
840   necessary, and the index never gets reset.  */
841
842static bfd_boolean
843nlm_powerpc_write_external (bfd *abfd,
844			    bfd_size_type count,
845			    asymbol *sym,
846			    struct reloc_and_sec *relocs)
847{
848  unsigned int i;
849  bfd_byte len;
850  unsigned char temp[NLM_TARGET_LONG_SIZE];
851#ifdef OLDFORMAT
852  static int indx;
853#endif
854
855  len = strlen (sym->name);
856  if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
857       != sizeof (bfd_byte))
858      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
859    return FALSE;
860
861  bfd_put_32 (abfd, count, temp);
862  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
863    return FALSE;
864
865  for (i = 0; i < count; i++)
866    {
867#ifndef OLDFORMAT
868      if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
869	return FALSE;
870#else
871      if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
872				     relocs[i].rel, indx))
873	return FALSE;
874#endif
875    }
876
877#ifdef OLDFORMAT
878  ++indx;
879#endif
880
881  return TRUE;
882}
883
884#ifndef OLDFORMAT
885
886/* PowerPC Netware uses a word offset, not a byte offset, for public
887   symbols.  */
888
889/* Set the section for a public symbol.  */
890
891static bfd_boolean
892nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
893{
894  if (sym->symbol.value & NLM_HIBIT)
895    {
896      sym->symbol.value &= ~NLM_HIBIT;
897      sym->symbol.flags |= BSF_FUNCTION;
898      sym->symbol.section =
899	bfd_get_section_by_name (abfd, NLM_CODE_NAME);
900    }
901  else
902    sym->symbol.section =
903      bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
904
905  sym->symbol.value <<= 2;
906
907  return TRUE;
908}
909
910/* Get the offset to write out for a public symbol.  */
911
912static bfd_vma
913nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
914{
915  bfd_vma offset;
916  asection *sec;
917
918  offset = bfd_asymbol_value (sym);
919  sec = bfd_get_section (sym);
920  if (sec->flags & SEC_CODE)
921    {
922      offset -= nlm_get_text_low (abfd);
923      offset |= NLM_HIBIT;
924    }
925  else if (sec->flags & (SEC_DATA | SEC_ALLOC))
926    {
927      /* SEC_ALLOC is for the .bss section.  */
928      offset -= nlm_get_data_low (abfd);
929    }
930  else
931    {
932      /* We can't handle an exported symbol that is not in the code or
933	 data segment.  */
934      bfd_set_error (bfd_error_invalid_operation);
935      /* FIXME: No way to return error.  */
936      abort ();
937    }
938
939  return offset;
940}
941
942#endif /* ! defined (OLDFORMAT) */
943
944#include "nlmswap.h"
945
946static const struct nlm_backend_data nlm32_powerpc_backend =
947{
948  "NetWare PowerPC Module \032",
949  sizeof (Nlm32_powerpc_External_Fixed_Header),
950#ifndef OLDFORMAT
951  0,	/* Optional_prefix_size.  */
952#else
953  sizeof (struct nlm32_powerpc_external_prefix_header),
954#endif
955  bfd_arch_powerpc,
956  0,
957  FALSE,
958#ifndef OLDFORMAT
959  0,	/* Backend_object_p.  */
960  0,	/* Write_prefix.  */
961#else
962  nlm_powerpc_backend_object_p,
963  nlm_powerpc_write_prefix,
964#endif
965  nlm_powerpc_read_reloc,
966  nlm_powerpc_mangle_relocs,
967  nlm_powerpc_read_import,
968  nlm_powerpc_write_import,
969#ifndef OLDFORMAT
970  nlm_powerpc_set_public_section,
971  nlm_powerpc_get_public_offset,
972#else
973  0,	/* Set_public_section.  */
974  0,	/* Get_public_offset.  */
975#endif
976  nlm_swap_fixed_header_in,
977  nlm_swap_fixed_header_out,
978  nlm_powerpc_write_external,
979  0,	/* Write_export.  */
980};
981
982#define TARGET_BIG_NAME			"nlm32-powerpc"
983#define TARGET_BIG_SYM			nlmNAME (powerpc_vec)
984#define TARGET_BACKEND_DATA		& nlm32_powerpc_backend
985
986#include "nlm-target.h"
987