xref: /openbsd-src/gnu/usr.bin/binutils/bfd/nlm32-ppc.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2*007c2a45Smiod    Copyright 1994, 1995, 2000, 2001, 2002, 2003
3*007c2a45Smiod    Free Software Foundation, Inc.
42159047fSniklas 
52159047fSniklas This file is part of BFD, the Binary File Descriptor library.
62159047fSniklas 
72159047fSniklas This program is free software; you can redistribute it and/or modify
82159047fSniklas it under the terms of the GNU General Public License as published by
92159047fSniklas the Free Software Foundation; either version 2 of the License, or
102159047fSniklas (at your option) any later version.
112159047fSniklas 
122159047fSniklas This program is distributed in the hope that it will be useful,
132159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
142159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152159047fSniklas GNU General Public License for more details.
162159047fSniklas 
172159047fSniklas You should have received a copy of the GNU General Public License
182159047fSniklas along with this program; if not, write to the Free Software
192159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
202159047fSniklas 
212159047fSniklas #include "bfd.h"
222159047fSniklas #include "sysdep.h"
232159047fSniklas #include "libbfd.h"
242159047fSniklas 
252159047fSniklas /* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
262159047fSniklas    old format.  */
272159047fSniklas 
282159047fSniklas #define ARCH_SIZE 32
292159047fSniklas 
302159047fSniklas #include "nlm/ppc-ext.h"
312159047fSniklas #define Nlm_External_Fixed_Header	Nlm32_powerpc_External_Fixed_Header
322159047fSniklas 
332159047fSniklas #include "libnlm.h"
342159047fSniklas 
352159047fSniklas #ifdef OLDFORMAT
36c074d1c9Sdrahn static bfd_boolean nlm_powerpc_backend_object_p
372159047fSniklas   PARAMS ((bfd *));
38c074d1c9Sdrahn static bfd_boolean nlm_powerpc_write_prefix
392159047fSniklas   PARAMS ((bfd *));
402159047fSniklas #endif
412159047fSniklas 
42c074d1c9Sdrahn static bfd_boolean nlm_powerpc_read_reloc
432159047fSniklas   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
44c074d1c9Sdrahn static bfd_boolean nlm_powerpc_mangle_relocs
45*007c2a45Smiod   PARAMS ((bfd *, asection *, const PTR, bfd_vma, bfd_size_type));
46c074d1c9Sdrahn static bfd_boolean nlm_powerpc_read_import
472159047fSniklas   PARAMS ((bfd *, nlmNAME(symbol_type) *));
482159047fSniklas 
492159047fSniklas #ifdef OLDFORMAT
50c074d1c9Sdrahn static bfd_boolean nlm_powerpc_write_reloc
512159047fSniklas   PARAMS ((bfd *, asection *, arelent *, int));
522159047fSniklas #endif
532159047fSniklas 
54c074d1c9Sdrahn static bfd_boolean nlm_powerpc_write_import
552159047fSniklas   PARAMS ((bfd *, asection *, arelent *));
56c074d1c9Sdrahn static bfd_boolean nlm_powerpc_write_external
572159047fSniklas   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
582159047fSniklas 
592159047fSniklas #ifndef OLDFORMAT
60c074d1c9Sdrahn static bfd_boolean nlm_powerpc_set_public_section
612159047fSniklas   PARAMS ((bfd *, nlmNAME(symbol_type) *));
622159047fSniklas static bfd_vma nlm_powerpc_get_public_offset
632159047fSniklas   PARAMS ((bfd *, asymbol *));
642159047fSniklas #endif
652159047fSniklas 
662159047fSniklas #ifdef OLDFORMAT
672159047fSniklas 
682159047fSniklas /* The prefix header is only used in the old format.  */
692159047fSniklas 
702159047fSniklas /* PowerPC NLM's have a prefix header before the standard NLM.  This
712159047fSniklas    function reads it in, verifies the version, and seeks the bfd to
722159047fSniklas    the location before the regular NLM header.  */
732159047fSniklas 
74c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_backend_object_p(abfd)752159047fSniklas nlm_powerpc_backend_object_p (abfd)
762159047fSniklas      bfd *abfd;
772159047fSniklas {
782159047fSniklas   struct nlm32_powerpc_external_prefix_header s;
792159047fSniklas 
80c074d1c9Sdrahn   if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
81c074d1c9Sdrahn     return FALSE;
822159047fSniklas 
832159047fSniklas   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
84c074d1c9Sdrahn       || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
85c074d1c9Sdrahn     return FALSE;
862159047fSniklas 
87c074d1c9Sdrahn   return TRUE;
882159047fSniklas }
892159047fSniklas 
902159047fSniklas /* Write out the prefix.  */
912159047fSniklas 
92c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_write_prefix(abfd)932159047fSniklas nlm_powerpc_write_prefix (abfd)
942159047fSniklas      bfd *abfd;
952159047fSniklas {
962159047fSniklas   struct nlm32_powerpc_external_prefix_header s;
972159047fSniklas 
982159047fSniklas   memset (&s, 0, sizeof s);
992159047fSniklas   memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
100c074d1c9Sdrahn   H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
101c074d1c9Sdrahn   H_PUT_32 (abfd, 0, s.origins);
1022159047fSniklas 
1032159047fSniklas   /* FIXME: What should we do about the date?  */
1042159047fSniklas 
105c074d1c9Sdrahn   if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
106c074d1c9Sdrahn     return FALSE;
1072159047fSniklas 
108c074d1c9Sdrahn   return TRUE;
1092159047fSniklas }
1102159047fSniklas 
1112159047fSniklas #endif /* OLDFORMAT */
1122159047fSniklas 
1132159047fSniklas #ifndef OLDFORMAT
1142159047fSniklas 
1152159047fSniklas /* There is only one type of reloc in a PowerPC NLM.  */
1162159047fSniklas 
1172159047fSniklas static reloc_howto_type nlm_powerpc_howto =
1182159047fSniklas   HOWTO (0,			/* type */
1192159047fSniklas 	 0,			/* rightshift */
1202159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1212159047fSniklas 	 32,			/* bitsize */
122c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1232159047fSniklas 	 0,			/* bitpos */
1242159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
1252159047fSniklas 	 0,			/* special_function */
1262159047fSniklas 	 "32",			/* name */
127c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1282159047fSniklas 	 0xffffffff,		/* src_mask */
1292159047fSniklas 	 0xffffffff,		/* dst_mask */
130c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
1312159047fSniklas 
1322159047fSniklas /* Read a PowerPC NLM reloc.  */
1332159047fSniklas 
134c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_read_reloc(abfd,sym,secp,rel)1352159047fSniklas nlm_powerpc_read_reloc (abfd, sym, secp, rel)
1362159047fSniklas      bfd *abfd;
1372159047fSniklas      nlmNAME(symbol_type) *sym;
1382159047fSniklas      asection **secp;
1392159047fSniklas      arelent *rel;
1402159047fSniklas {
1412159047fSniklas   bfd_byte temp[4];
1422159047fSniklas   bfd_vma val;
1432159047fSniklas   const char *name;
1442159047fSniklas 
145c074d1c9Sdrahn   if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
146c074d1c9Sdrahn     return FALSE;
1472159047fSniklas 
1482159047fSniklas   val = bfd_get_32 (abfd, temp);
1492159047fSniklas 
1502159047fSniklas   /* The value is a word offset into either the code or data segment.
1512159047fSniklas      This is the location which needs to be adjusted.
1522159047fSniklas 
1532159047fSniklas      The high bit is 0 if the value is an offset into the data
1542159047fSniklas      segment, or 1 if the value is an offset into the text segment.
1552159047fSniklas 
1562159047fSniklas      If this is a relocation fixup rather than an imported symbol (the
1572159047fSniklas      sym argument is NULL), then the second most significant bit is 0
1582159047fSniklas      if the address of the data segment should be added to the
1592159047fSniklas      location addressed by the value, or 1 if the address of the text
1602159047fSniklas      segment should be added.
1612159047fSniklas 
1622159047fSniklas      If this is an imported symbol, the second most significant bit is
1632159047fSniklas      not used and must be 0.  */
1642159047fSniklas 
1652159047fSniklas   if ((val & NLM_HIBIT) == 0)
1662159047fSniklas     name = NLM_INITIALIZED_DATA_NAME;
1672159047fSniklas   else
1682159047fSniklas     {
1692159047fSniklas       name = NLM_CODE_NAME;
1702159047fSniklas       val &=~ NLM_HIBIT;
1712159047fSniklas     }
1722159047fSniklas   *secp = bfd_get_section_by_name (abfd, name);
1732159047fSniklas 
1742159047fSniklas   if (sym == NULL)
1752159047fSniklas     {
1762159047fSniklas       if ((val & (NLM_HIBIT >> 1)) == 0)
1772159047fSniklas 	name = NLM_INITIALIZED_DATA_NAME;
1782159047fSniklas       else
1792159047fSniklas 	{
1802159047fSniklas 	  name = NLM_CODE_NAME;
1812159047fSniklas 	  val &=~ (NLM_HIBIT >> 1);
1822159047fSniklas 	}
1832159047fSniklas       rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
1842159047fSniklas     }
1852159047fSniklas 
1862159047fSniklas   rel->howto = &nlm_powerpc_howto;
1872159047fSniklas 
1882159047fSniklas   rel->address = val << 2;
1892159047fSniklas   rel->addend = 0;
1902159047fSniklas 
191c074d1c9Sdrahn   return TRUE;
1922159047fSniklas }
1932159047fSniklas 
1942159047fSniklas #else /* OLDFORMAT */
1952159047fSniklas 
1962159047fSniklas /* This reloc handling is only applicable to the old format.  */
1972159047fSniklas 
1982159047fSniklas /* How to process the various reloc types.  PowerPC NLMs use XCOFF
1992159047fSniklas    reloc types, and I have just copied the XCOFF reloc table here.  */
2002159047fSniklas 
2012159047fSniklas static reloc_howto_type nlm_powerpc_howto_table[] =
2022159047fSniklas {
2032159047fSniklas   /* Standard 32 bit relocation.  */
2042159047fSniklas   HOWTO (0,	                /* type */
2052159047fSniklas 	 0,	                /* rightshift */
2062159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
2072159047fSniklas 	 32,	                /* bitsize */
208c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2092159047fSniklas 	 0,	                /* bitpos */
2102159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
2112159047fSniklas 	 0,		        /* special_function */
2122159047fSniklas 	 "R_POS",               /* name */
213c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2142159047fSniklas 	 0xffffffff,            /* src_mask */
2152159047fSniklas 	 0xffffffff,            /* dst_mask */
216c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2172159047fSniklas 
2182159047fSniklas   /* 32 bit relocation, but store negative value.  */
2192159047fSniklas   HOWTO (1,	                /* type */
2202159047fSniklas 	 0,	                /* rightshift */
2212159047fSniklas 	 -2,	                /* size (0 = byte, 1 = short, 2 = long) */
2222159047fSniklas 	 32,	                /* bitsize */
223c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2242159047fSniklas 	 0,	                /* bitpos */
2252159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
2262159047fSniklas 	 0,		        /* special_function */
2272159047fSniklas 	 "R_NEG",               /* name */
228c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2292159047fSniklas 	 0xffffffff,            /* src_mask */
2302159047fSniklas 	 0xffffffff,            /* dst_mask */
231c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2322159047fSniklas 
2332159047fSniklas   /* 32 bit PC relative relocation.  */
2342159047fSniklas   HOWTO (2,	                /* type */
2352159047fSniklas 	 0,	                /* rightshift */
2362159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
2372159047fSniklas 	 32,	                /* bitsize */
238c074d1c9Sdrahn 	 TRUE,	                /* pc_relative */
2392159047fSniklas 	 0,	                /* bitpos */
2402159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
2412159047fSniklas 	 0,		        /* special_function */
2422159047fSniklas 	 "R_REL",               /* name */
243c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2442159047fSniklas 	 0xffffffff,            /* src_mask */
2452159047fSniklas 	 0xffffffff,            /* dst_mask */
246c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2472159047fSniklas 
2482159047fSniklas   /* 16 bit TOC relative relocation.  */
2492159047fSniklas   HOWTO (3,	                /* type */
2502159047fSniklas 	 0,	                /* rightshift */
2512159047fSniklas 	 1,	                /* size (0 = byte, 1 = short, 2 = long) */
2522159047fSniklas 	 16,	                /* bitsize */
253c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2542159047fSniklas 	 0,	                /* bitpos */
2552159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
2562159047fSniklas 	 0,		        /* special_function */
2572159047fSniklas 	 "R_TOC",               /* name */
258c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2592159047fSniklas 	 0xffff,	        /* src_mask */
2602159047fSniklas 	 0xffff,        	/* dst_mask */
261c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2622159047fSniklas 
2632159047fSniklas   /* I don't really know what this is.  */
2642159047fSniklas   HOWTO (4,	                /* type */
2652159047fSniklas 	 1,	                /* rightshift */
2662159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
2672159047fSniklas 	 32,	                /* bitsize */
268c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2692159047fSniklas 	 0,	                /* bitpos */
2702159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
2712159047fSniklas 	 0,		        /* special_function */
2722159047fSniklas 	 "R_RTB",               /* name */
273c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2742159047fSniklas 	 0xffffffff,	        /* src_mask */
2752159047fSniklas 	 0xffffffff,        	/* dst_mask */
276c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2772159047fSniklas 
2782159047fSniklas   /* External TOC relative symbol.  */
2792159047fSniklas   HOWTO (5,	                /* type */
2802159047fSniklas 	 0,	                /* rightshift */
2812159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
2822159047fSniklas 	 16,	                /* bitsize */
283c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2842159047fSniklas 	 0,	                /* bitpos */
2852159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
2862159047fSniklas 	 0,		        /* special_function */
2872159047fSniklas 	 "R_GL",                /* name */
288c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
2892159047fSniklas 	 0xffff,	        /* src_mask */
2902159047fSniklas 	 0xffff,        	/* dst_mask */
291c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
2922159047fSniklas 
2932159047fSniklas   /* Local TOC relative symbol.  */
2942159047fSniklas   HOWTO (6,	                /* type */
2952159047fSniklas 	 0,	                /* rightshift */
2962159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
2972159047fSniklas 	 16,	                /* bitsize */
298c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
2992159047fSniklas 	 0,	                /* bitpos */
3002159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
3012159047fSniklas 	 0,		        /* special_function */
3022159047fSniklas 	 "R_TCL",               /* name */
303c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
3042159047fSniklas 	 0xffff,	        /* src_mask */
3052159047fSniklas 	 0xffff,        	/* dst_mask */
306c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3072159047fSniklas 
3082159047fSniklas   { 7 },
3092159047fSniklas 
3102159047fSniklas   /* Non modifiable absolute branch.  */
3112159047fSniklas   HOWTO (8,	                /* type */
3122159047fSniklas 	 0,	                /* rightshift */
3132159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3142159047fSniklas 	 26,	                /* bitsize */
315c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
3162159047fSniklas 	 0,	                /* bitpos */
3172159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
3182159047fSniklas 	 0,		        /* special_function */
3192159047fSniklas 	 "R_BA",                /* name */
320c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
3212159047fSniklas 	 0x3fffffc,	        /* src_mask */
3222159047fSniklas 	 0x3fffffc,        	/* dst_mask */
323c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3242159047fSniklas 
3252159047fSniklas   { 9 },
3262159047fSniklas 
3272159047fSniklas   /* Non modifiable relative branch.  */
3282159047fSniklas   HOWTO (0xa,	                /* type */
3292159047fSniklas 	 0,	                /* rightshift */
3302159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3312159047fSniklas 	 26,	                /* bitsize */
332c074d1c9Sdrahn 	 TRUE,	                /* pc_relative */
3332159047fSniklas 	 0,	                /* bitpos */
3342159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
3352159047fSniklas 	 0,		        /* special_function */
3362159047fSniklas 	 "R_BR",                /* name */
337c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
3382159047fSniklas 	 0x3fffffc,	        /* src_mask */
3392159047fSniklas 	 0x3fffffc,        	/* dst_mask */
340c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3412159047fSniklas 
3422159047fSniklas   { 0xb },
3432159047fSniklas 
3442159047fSniklas   /* Indirect load.  */
3452159047fSniklas   HOWTO (0xc,	                /* type */
3462159047fSniklas 	 0,	                /* rightshift */
3472159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3482159047fSniklas 	 16,	                /* bitsize */
349c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
3502159047fSniklas 	 0,	                /* bitpos */
3512159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
3522159047fSniklas 	 0,		        /* special_function */
3532159047fSniklas 	 "R_RL",                /* name */
354c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
3552159047fSniklas 	 0xffff,	        /* src_mask */
3562159047fSniklas 	 0xffff,        	/* dst_mask */
357c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3582159047fSniklas 
3592159047fSniklas   /* Load address.  */
3602159047fSniklas   HOWTO (0xd,	                /* type */
3612159047fSniklas 	 0,	                /* rightshift */
3622159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3632159047fSniklas 	 16,	                /* bitsize */
364c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
3652159047fSniklas 	 0,	                /* bitpos */
3662159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
3672159047fSniklas 	 0,		        /* special_function */
3682159047fSniklas 	 "R_RLA",               /* name */
369c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
3702159047fSniklas 	 0xffff,	        /* src_mask */
3712159047fSniklas 	 0xffff,        	/* dst_mask */
372c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3732159047fSniklas 
3742159047fSniklas   { 0xe },
3752159047fSniklas 
3762159047fSniklas   /* Non-relocating reference.  */
3772159047fSniklas   HOWTO (0xf,	                /* type */
3782159047fSniklas 	 0,	                /* rightshift */
3792159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3802159047fSniklas 	 32,	                /* bitsize */
381c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
3822159047fSniklas 	 0,	                /* bitpos */
3832159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
3842159047fSniklas 	 0,		        /* special_function */
3852159047fSniklas 	 "R_REF",               /* name */
386c074d1c9Sdrahn 	 FALSE,	                /* partial_inplace */
3872159047fSniklas 	 0,		        /* src_mask */
3882159047fSniklas 	 0,     	   	/* dst_mask */
389c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
3902159047fSniklas 
3912159047fSniklas   { 0x10 },
3922159047fSniklas   { 0x11 },
3932159047fSniklas 
3942159047fSniklas   /* TOC relative indirect load.  */
3952159047fSniklas   HOWTO (0x12,	                /* type */
3962159047fSniklas 	 0,	                /* rightshift */
3972159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
3982159047fSniklas 	 16,	                /* bitsize */
399c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4002159047fSniklas 	 0,	                /* bitpos */
4012159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4022159047fSniklas 	 0,		        /* special_function */
4032159047fSniklas 	 "R_TRL",               /* name */
404c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4052159047fSniklas 	 0xffff,	        /* src_mask */
4062159047fSniklas 	 0xffff,        	/* dst_mask */
407c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4082159047fSniklas 
4092159047fSniklas   /* TOC relative load address.  */
4102159047fSniklas   HOWTO (0x13,	                /* type */
4112159047fSniklas 	 0,	                /* rightshift */
4122159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4132159047fSniklas 	 16,	                /* bitsize */
414c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4152159047fSniklas 	 0,	                /* bitpos */
4162159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4172159047fSniklas 	 0,		        /* special_function */
4182159047fSniklas 	 "R_TRLA",              /* name */
419c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4202159047fSniklas 	 0xffff,	        /* src_mask */
4212159047fSniklas 	 0xffff,        	/* dst_mask */
422c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4232159047fSniklas 
4242159047fSniklas   /* Modifiable relative branch.  */
4252159047fSniklas   HOWTO (0x14,	                /* type */
4262159047fSniklas 	 1,	                /* rightshift */
4272159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4282159047fSniklas 	 32,	                /* bitsize */
429c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4302159047fSniklas 	 0,	                /* bitpos */
4312159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4322159047fSniklas 	 0,		        /* special_function */
4332159047fSniklas 	 "R_RRTBI",             /* name */
434c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4352159047fSniklas 	 0xffffffff,	        /* src_mask */
4362159047fSniklas 	 0xffffffff,        	/* dst_mask */
437c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4382159047fSniklas 
4392159047fSniklas   /* Modifiable absolute branch.  */
4402159047fSniklas   HOWTO (0x15,	                /* type */
4412159047fSniklas 	 1,	                /* rightshift */
4422159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4432159047fSniklas 	 32,	                /* bitsize */
444c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4452159047fSniklas 	 0,	                /* bitpos */
4462159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4472159047fSniklas 	 0,		        /* special_function */
4482159047fSniklas 	 "R_RRTBA",             /* name */
449c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4502159047fSniklas 	 0xffffffff,	        /* src_mask */
4512159047fSniklas 	 0xffffffff,        	/* dst_mask */
452c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4532159047fSniklas 
4542159047fSniklas   /* Modifiable call absolute indirect.  */
4552159047fSniklas   HOWTO (0x16,	                /* type */
4562159047fSniklas 	 0,	                /* rightshift */
4572159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4582159047fSniklas 	 16,	                /* bitsize */
459c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4602159047fSniklas 	 0,	                /* bitpos */
4612159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4622159047fSniklas 	 0,		        /* special_function */
4632159047fSniklas 	 "R_CAI",               /* name */
464c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4652159047fSniklas 	 0xffff,	        /* src_mask */
4662159047fSniklas 	 0xffff,        	/* dst_mask */
467c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4682159047fSniklas 
4692159047fSniklas   /* Modifiable call relative.  */
4702159047fSniklas   HOWTO (0x17,	                /* type */
4712159047fSniklas 	 0,	                /* rightshift */
4722159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4732159047fSniklas 	 16,	                /* bitsize */
474c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4752159047fSniklas 	 0,	                /* bitpos */
4762159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4772159047fSniklas 	 0,		        /* special_function */
4782159047fSniklas 	 "R_REL",               /* name */
479c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4802159047fSniklas 	 0xffff,	        /* src_mask */
4812159047fSniklas 	 0xffff,        	/* dst_mask */
482c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4832159047fSniklas 
4842159047fSniklas   /* Modifiable branch absolute.  */
4852159047fSniklas   HOWTO (0x18,	                /* type */
4862159047fSniklas 	 0,	                /* rightshift */
4872159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
4882159047fSniklas 	 16,	                /* bitsize */
489c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
4902159047fSniklas 	 0,	                /* bitpos */
4912159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
4922159047fSniklas 	 0,		        /* special_function */
4932159047fSniklas 	 "R_RBA",               /* name */
494c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
4952159047fSniklas 	 0xffff,	        /* src_mask */
4962159047fSniklas 	 0xffff,        	/* dst_mask */
497c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
4982159047fSniklas 
4992159047fSniklas   /* Modifiable branch absolute.  */
5002159047fSniklas   HOWTO (0x19,	                /* type */
5012159047fSniklas 	 0,	                /* rightshift */
5022159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
5032159047fSniklas 	 16,	                /* bitsize */
504c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
5052159047fSniklas 	 0,	                /* bitpos */
5062159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
5072159047fSniklas 	 0,		        /* special_function */
5082159047fSniklas 	 "R_RBAC",              /* name */
509c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
5102159047fSniklas 	 0xffff,	        /* src_mask */
5112159047fSniklas 	 0xffff,        	/* dst_mask */
512c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
5132159047fSniklas 
5142159047fSniklas   /* Modifiable branch relative.  */
5152159047fSniklas   HOWTO (0x1a,	                /* type */
5162159047fSniklas 	 0,	                /* rightshift */
5172159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
5182159047fSniklas 	 26,	                /* bitsize */
519c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
5202159047fSniklas 	 0,	                /* bitpos */
5212159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
5222159047fSniklas 	 0,		        /* special_function */
5232159047fSniklas 	 "R_REL",               /* name */
524c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
5252159047fSniklas 	 0xffff,	        /* src_mask */
5262159047fSniklas 	 0xffff,        	/* dst_mask */
527c074d1c9Sdrahn 	 FALSE),                /* pcrel_offset */
5282159047fSniklas 
5292159047fSniklas   /* Modifiable branch absolute.  */
5302159047fSniklas   HOWTO (0x1b,	                /* type */
5312159047fSniklas 	 0,	                /* rightshift */
5322159047fSniklas 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
5332159047fSniklas 	 16,	                /* bitsize */
534c074d1c9Sdrahn 	 FALSE,	                /* pc_relative */
5352159047fSniklas 	 0,	                /* bitpos */
5362159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
5372159047fSniklas 	 0,		        /* special_function */
5382159047fSniklas 	 "R_REL",               /* name */
539c074d1c9Sdrahn 	 TRUE,	                /* partial_inplace */
5402159047fSniklas 	 0xffff,	        /* src_mask */
5412159047fSniklas 	 0xffff,        	/* dst_mask */
542c074d1c9Sdrahn 	 FALSE)                 /* pcrel_offset */
5432159047fSniklas };
5442159047fSniklas 
5452159047fSniklas #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table		\
5462159047fSniklas 		     / sizeof nlm_powerpc_howto_table[0])
5472159047fSniklas 
5482159047fSniklas /* Read a PowerPC NLM reloc.  */
5492159047fSniklas 
550c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_read_reloc(abfd,sym,secp,rel)5512159047fSniklas nlm_powerpc_read_reloc (abfd, sym, secp, rel)
5522159047fSniklas      bfd *abfd;
5532159047fSniklas      nlmNAME(symbol_type) *sym;
5542159047fSniklas      asection **secp;
5552159047fSniklas      arelent *rel;
5562159047fSniklas {
5572159047fSniklas   struct nlm32_powerpc_external_reloc ext;
5582159047fSniklas   bfd_vma l_vaddr;
5592159047fSniklas   unsigned long l_symndx;
5602159047fSniklas   int l_rtype;
5612159047fSniklas   int l_rsecnm;
5622159047fSniklas   asection *code_sec, *data_sec, *bss_sec;
5632159047fSniklas 
5642159047fSniklas   /* Read the reloc from the file.  */
565c074d1c9Sdrahn   if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
566c074d1c9Sdrahn     return FALSE;
5672159047fSniklas 
5682159047fSniklas   /* Swap in the fields.  */
569c074d1c9Sdrahn   l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
570c074d1c9Sdrahn   l_symndx = H_GET_32 (abfd, ext.l_symndx);
571c074d1c9Sdrahn   l_rtype = H_GET_16 (abfd, ext.l_rtype);
572c074d1c9Sdrahn   l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
5732159047fSniklas 
5742159047fSniklas   /* Get the sections now, for convenience.  */
5752159047fSniklas   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
5762159047fSniklas   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
5772159047fSniklas   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
5782159047fSniklas 
5792159047fSniklas   /* Work out the arelent fields.  */
5802159047fSniklas   if (sym != NULL)
5812159047fSniklas     {
5822159047fSniklas       /* This is an import.  sym_ptr_ptr is filled in by
5832159047fSniklas 	 nlm_canonicalize_reloc.  */
5842159047fSniklas       rel->sym_ptr_ptr = NULL;
5852159047fSniklas     }
5862159047fSniklas   else
5872159047fSniklas     {
5882159047fSniklas       asection *sec;
5892159047fSniklas 
5902159047fSniklas       if (l_symndx == 0)
5912159047fSniklas 	sec = code_sec;
5922159047fSniklas       else if (l_symndx == 1)
5932159047fSniklas 	sec = data_sec;
5942159047fSniklas       else if (l_symndx == 2)
5952159047fSniklas 	sec = bss_sec;
5962159047fSniklas       else
5972159047fSniklas 	{
5982159047fSniklas 	  bfd_set_error (bfd_error_bad_value);
599c074d1c9Sdrahn 	  return FALSE;
6002159047fSniklas 	}
6012159047fSniklas 
6022159047fSniklas       rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
6032159047fSniklas     }
6042159047fSniklas 
6052159047fSniklas   rel->addend = 0;
6062159047fSniklas 
6072159047fSniklas   BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
6082159047fSniklas 
6092159047fSniklas   rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
6102159047fSniklas 
6112159047fSniklas   BFD_ASSERT (rel->howto->name != NULL
6122159047fSniklas 	      && ((l_rtype & 0x8000) != 0
6132159047fSniklas 		  ? (rel->howto->complain_on_overflow
6142159047fSniklas 		     == complain_overflow_signed)
6152159047fSniklas 		  : (rel->howto->complain_on_overflow
6162159047fSniklas 		     == complain_overflow_bitfield))
6172159047fSniklas 	      && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
6182159047fSniklas 
6192159047fSniklas   if (l_rsecnm == 0)
6202159047fSniklas     *secp = code_sec;
6212159047fSniklas   else if (l_rsecnm == 1)
6222159047fSniklas     {
6232159047fSniklas       *secp = data_sec;
6242159047fSniklas       l_vaddr -= bfd_section_size (abfd, code_sec);
6252159047fSniklas     }
6262159047fSniklas   else
6272159047fSniklas     {
6282159047fSniklas       bfd_set_error (bfd_error_bad_value);
629c074d1c9Sdrahn       return FALSE;
6302159047fSniklas     }
6312159047fSniklas 
6322159047fSniklas   rel->address = l_vaddr;
6332159047fSniklas 
634c074d1c9Sdrahn   return TRUE;
6352159047fSniklas }
6362159047fSniklas 
6372159047fSniklas #endif /* OLDFORMAT */
6382159047fSniklas 
6392159047fSniklas /* Mangle PowerPC NLM relocs for output.  */
6402159047fSniklas 
641c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_mangle_relocs(abfd,sec,data,offset,count)6422159047fSniklas nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
643b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
644b305b0f1Sespie      asection *sec ATTRIBUTE_UNUSED;
645*007c2a45Smiod      const PTR data ATTRIBUTE_UNUSED;
646b305b0f1Sespie      bfd_vma offset ATTRIBUTE_UNUSED;
647b305b0f1Sespie      bfd_size_type count ATTRIBUTE_UNUSED;
6482159047fSniklas {
649c074d1c9Sdrahn   return TRUE;
6502159047fSniklas }
6512159047fSniklas 
6522159047fSniklas /* Read a PowerPC NLM import record */
6532159047fSniklas 
654c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_read_import(abfd,sym)6552159047fSniklas nlm_powerpc_read_import (abfd, sym)
6562159047fSniklas      bfd *abfd;
6572159047fSniklas      nlmNAME(symbol_type) *sym;
6582159047fSniklas {
6592159047fSniklas   struct nlm_relent *nlm_relocs;	/* relocation records for symbol */
6602159047fSniklas   bfd_size_type rcount;			/* number of relocs */
6612159047fSniklas   bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* temporary 32-bit value */
6622159047fSniklas   unsigned char symlength;		/* length of symbol name */
6632159047fSniklas   char *name;
6642159047fSniklas 
665c074d1c9Sdrahn   if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
6662159047fSniklas       != sizeof (symlength))
667c074d1c9Sdrahn     return FALSE;
6682159047fSniklas   sym -> symbol.the_bfd = abfd;
669c074d1c9Sdrahn   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
6702159047fSniklas   if (name == NULL)
671c074d1c9Sdrahn     return FALSE;
672c074d1c9Sdrahn   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
673c074d1c9Sdrahn     return FALSE;
6742159047fSniklas   name[symlength] = '\0';
6752159047fSniklas   sym -> symbol.name = name;
6762159047fSniklas   sym -> symbol.flags = 0;
6772159047fSniklas   sym -> symbol.value = 0;
6782159047fSniklas   sym -> symbol.section = bfd_und_section_ptr;
679c074d1c9Sdrahn   if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
680c074d1c9Sdrahn       != sizeof (temp))
681c074d1c9Sdrahn     return FALSE;
682c074d1c9Sdrahn   rcount = H_GET_32 (abfd, temp);
6832159047fSniklas   nlm_relocs = ((struct nlm_relent *)
6842159047fSniklas 		bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
6852159047fSniklas   if (nlm_relocs == (struct nlm_relent *) NULL)
686c074d1c9Sdrahn     return FALSE;
6872159047fSniklas   sym -> relocs = nlm_relocs;
6882159047fSniklas   sym -> rcnt = 0;
6892159047fSniklas   while (sym -> rcnt < rcount)
6902159047fSniklas     {
6912159047fSniklas       asection *section;
6922159047fSniklas 
693c074d1c9Sdrahn       if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
694c074d1c9Sdrahn 	return FALSE;
6952159047fSniklas       nlm_relocs -> section = section;
6962159047fSniklas       nlm_relocs++;
6972159047fSniklas       sym -> rcnt++;
6982159047fSniklas     }
699c074d1c9Sdrahn   return TRUE;
7002159047fSniklas }
7012159047fSniklas 
7022159047fSniklas #ifndef OLDFORMAT
7032159047fSniklas 
7042159047fSniklas /* Write a PowerPC NLM reloc.  */
7052159047fSniklas 
706c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_write_import(abfd,sec,rel)7072159047fSniklas nlm_powerpc_write_import (abfd, sec, rel)
7082159047fSniklas      bfd *abfd;
7092159047fSniklas      asection *sec;
7102159047fSniklas      arelent *rel;
7112159047fSniklas {
7122159047fSniklas   asymbol *sym;
7132159047fSniklas   bfd_vma val;
7142159047fSniklas   bfd_byte temp[4];
7152159047fSniklas 
7162159047fSniklas   /* PowerPC NetWare only supports one kind of reloc.  */
7172159047fSniklas   if (rel->addend != 0
7182159047fSniklas       || rel->howto == NULL
7192159047fSniklas       || rel->howto->rightshift != 0
7202159047fSniklas       || rel->howto->size != 2
7212159047fSniklas       || rel->howto->bitsize != 32
7222159047fSniklas       || rel->howto->bitpos != 0
7232159047fSniklas       || rel->howto->pc_relative
7242159047fSniklas       || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
7252159047fSniklas       || rel->howto->dst_mask != 0xffffffff)
7262159047fSniklas     {
7272159047fSniklas       bfd_set_error (bfd_error_invalid_operation);
728c074d1c9Sdrahn       return FALSE;
7292159047fSniklas     }
7302159047fSniklas 
7312159047fSniklas   sym = *rel->sym_ptr_ptr;
7322159047fSniklas 
7332159047fSniklas   /* The value we write out is the offset into the appropriate
7342159047fSniklas      segment, rightshifted by two.  This offset is the section vma,
7352159047fSniklas      adjusted by the vma of the lowest section in that segment, plus
7362159047fSniklas      the address of the relocation.  */
7372159047fSniklas   val = bfd_get_section_vma (abfd, sec) + rel->address;
7382159047fSniklas   if ((val & 3) != 0)
7392159047fSniklas     {
7402159047fSniklas       bfd_set_error (bfd_error_bad_value);
741c074d1c9Sdrahn       return FALSE;
7422159047fSniklas     }
7432159047fSniklas   val >>= 2;
7442159047fSniklas 
7452159047fSniklas   /* The high bit is 0 if the reloc is in the data section, or 1 if
7462159047fSniklas      the reloc is in the code section.  */
7472159047fSniklas   if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
7482159047fSniklas     val -= nlm_get_data_low (abfd);
7492159047fSniklas   else
7502159047fSniklas     {
7512159047fSniklas       val -= nlm_get_text_low (abfd);
7522159047fSniklas       val |= NLM_HIBIT;
7532159047fSniklas     }
7542159047fSniklas 
7552159047fSniklas   if (! bfd_is_und_section (bfd_get_section (sym)))
7562159047fSniklas     {
7572159047fSniklas       /* This is an internal relocation fixup.  The second most
7582159047fSniklas 	 significant bit is 0 if this is a reloc against the data
7592159047fSniklas 	 segment, or 1 if it is a reloc against the text segment.  */
7602159047fSniklas       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
7612159047fSniklas 	val |= NLM_HIBIT >> 1;
7622159047fSniklas     }
7632159047fSniklas 
7642159047fSniklas   bfd_put_32 (abfd, val, temp);
765c074d1c9Sdrahn   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
766c074d1c9Sdrahn     return FALSE;
7672159047fSniklas 
768c074d1c9Sdrahn   return TRUE;
7692159047fSniklas }
7702159047fSniklas 
7712159047fSniklas #else /* OLDFORMAT */
7722159047fSniklas 
7732159047fSniklas /* This is used for the reloc handling in the old format.  */
7742159047fSniklas 
7752159047fSniklas /* Write a PowerPC NLM reloc.  */
7762159047fSniklas 
777c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_write_reloc(abfd,sec,rel,indx)7782159047fSniklas nlm_powerpc_write_reloc (abfd, sec, rel, indx)
7792159047fSniklas      bfd *abfd;
7802159047fSniklas      asection *sec;
7812159047fSniklas      arelent *rel;
7822159047fSniklas      int indx;
7832159047fSniklas {
7842159047fSniklas   struct nlm32_powerpc_external_reloc ext;
7852159047fSniklas   asection *code_sec, *data_sec, *bss_sec;
7862159047fSniklas   asymbol *sym;
7872159047fSniklas   asection *symsec;
7882159047fSniklas   unsigned long l_symndx;
7892159047fSniklas   int l_rtype;
7902159047fSniklas   int l_rsecnm;
7912159047fSniklas   reloc_howto_type *howto;
7922159047fSniklas   bfd_size_type address;
7932159047fSniklas 
7942159047fSniklas   /* Get the sections now, for convenience.  */
7952159047fSniklas   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
7962159047fSniklas   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
7972159047fSniklas   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
7982159047fSniklas 
7992159047fSniklas   sym = *rel->sym_ptr_ptr;
8002159047fSniklas   symsec = bfd_get_section (sym);
8012159047fSniklas   if (indx != -1)
8022159047fSniklas     {
8032159047fSniklas       BFD_ASSERT (bfd_is_und_section (symsec));
8042159047fSniklas       l_symndx = indx + 3;
8052159047fSniklas     }
8062159047fSniklas   else
8072159047fSniklas     {
8082159047fSniklas       if (symsec == code_sec)
8092159047fSniklas 	l_symndx = 0;
8102159047fSniklas       else if (symsec == data_sec)
8112159047fSniklas 	l_symndx = 1;
8122159047fSniklas       else if (symsec == bss_sec)
8132159047fSniklas 	l_symndx = 2;
8142159047fSniklas       else
8152159047fSniklas 	{
8162159047fSniklas 	  bfd_set_error (bfd_error_bad_value);
817c074d1c9Sdrahn 	  return FALSE;
8182159047fSniklas 	}
8192159047fSniklas     }
8202159047fSniklas 
821c074d1c9Sdrahn   H_PUT_32 (abfd, l_symndx, ext.l_symndx);
8222159047fSniklas 
8232159047fSniklas   for (howto = nlm_powerpc_howto_table;
8242159047fSniklas        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
8252159047fSniklas        howto++)
8262159047fSniklas     {
8272159047fSniklas       if (howto->rightshift == rel->howto->rightshift
8282159047fSniklas 	  && howto->size == rel->howto->size
8292159047fSniklas 	  && howto->bitsize == rel->howto->bitsize
8302159047fSniklas 	  && howto->pc_relative == rel->howto->pc_relative
8312159047fSniklas 	  && howto->bitpos == rel->howto->bitpos
8322159047fSniklas 	  && (howto->partial_inplace == rel->howto->partial_inplace
8332159047fSniklas 	      || (! rel->howto->partial_inplace
8342159047fSniklas 		  && rel->addend == 0))
8352159047fSniklas 	  && (howto->src_mask == rel->howto->src_mask
8362159047fSniklas 	      || (rel->howto->src_mask == 0
8372159047fSniklas 		  && rel->addend == 0))
8382159047fSniklas 	  && howto->dst_mask == rel->howto->dst_mask
8392159047fSniklas 	  && howto->pcrel_offset == rel->howto->pcrel_offset)
8402159047fSniklas 	break;
8412159047fSniklas     }
8422159047fSniklas   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
8432159047fSniklas     {
8442159047fSniklas       bfd_set_error (bfd_error_bad_value);
845c074d1c9Sdrahn       return FALSE;
8462159047fSniklas     }
8472159047fSniklas 
8482159047fSniklas   l_rtype = howto->type;
8492159047fSniklas   if (howto->complain_on_overflow == complain_overflow_signed)
8502159047fSniklas     l_rtype |= 0x8000;
8512159047fSniklas   l_rtype |= (howto->bitsize - 1) << 8;
852c074d1c9Sdrahn   H_PUT_16 (abfd, l_rtype, ext.l_rtype);
8532159047fSniklas 
8542159047fSniklas   address = rel->address;
8552159047fSniklas 
8562159047fSniklas   if (sec == code_sec)
8572159047fSniklas     l_rsecnm = 0;
8582159047fSniklas   else if (sec == data_sec)
8592159047fSniklas     {
8602159047fSniklas       l_rsecnm = 1;
8612159047fSniklas       address += bfd_section_size (abfd, code_sec);
8622159047fSniklas     }
8632159047fSniklas   else
8642159047fSniklas     {
8652159047fSniklas       bfd_set_error (bfd_error_bad_value);
866c074d1c9Sdrahn       return FALSE;
8672159047fSniklas     }
8682159047fSniklas 
869c074d1c9Sdrahn   H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
870c074d1c9Sdrahn   H_PUT_32 (abfd, address, ext.l_vaddr);
8712159047fSniklas 
872c074d1c9Sdrahn   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
873c074d1c9Sdrahn     return FALSE;
8742159047fSniklas 
875c074d1c9Sdrahn   return TRUE;
8762159047fSniklas }
8772159047fSniklas 
8782159047fSniklas /* Write a PowerPC NLM import.  */
8792159047fSniklas 
880c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_write_import(abfd,sec,rel)8812159047fSniklas nlm_powerpc_write_import (abfd, sec, rel)
8822159047fSniklas      bfd *abfd;
8832159047fSniklas      asection *sec;
8842159047fSniklas      arelent *rel;
8852159047fSniklas {
8862159047fSniklas   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
8872159047fSniklas }
8882159047fSniklas 
8892159047fSniklas #endif /* OLDFORMAT */
8902159047fSniklas 
8912159047fSniklas /* Write a PowerPC NLM external symbol.  This routine keeps a static
8922159047fSniklas    count of the symbol index.  FIXME: I don't know if this is
8932159047fSniklas    necessary, and the index never gets reset.  */
8942159047fSniklas 
895c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_write_external(abfd,count,sym,relocs)8962159047fSniklas nlm_powerpc_write_external (abfd, count, sym, relocs)
8972159047fSniklas      bfd *abfd;
8982159047fSniklas      bfd_size_type count;
8992159047fSniklas      asymbol *sym;
9002159047fSniklas      struct reloc_and_sec *relocs;
9012159047fSniklas {
9022159047fSniklas   unsigned int i;
9032159047fSniklas   bfd_byte len;
9042159047fSniklas   unsigned char temp[NLM_TARGET_LONG_SIZE];
9052159047fSniklas #ifdef OLDFORMAT
9062159047fSniklas   static int indx;
9072159047fSniklas #endif
9082159047fSniklas 
9092159047fSniklas   len = strlen (sym->name);
910c074d1c9Sdrahn   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
911c074d1c9Sdrahn        != sizeof (bfd_byte))
912c074d1c9Sdrahn       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
913c074d1c9Sdrahn     return FALSE;
9142159047fSniklas 
9152159047fSniklas   bfd_put_32 (abfd, count, temp);
916c074d1c9Sdrahn   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
917c074d1c9Sdrahn     return FALSE;
9182159047fSniklas 
9192159047fSniklas   for (i = 0; i < count; i++)
9202159047fSniklas     {
9212159047fSniklas #ifndef OLDFORMAT
9222159047fSniklas       if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
923c074d1c9Sdrahn 	return FALSE;
9242159047fSniklas #else
9252159047fSniklas       if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
9262159047fSniklas 				     relocs[i].rel, indx))
927c074d1c9Sdrahn 	return FALSE;
9282159047fSniklas #endif
9292159047fSniklas     }
9302159047fSniklas 
9312159047fSniklas #ifdef OLDFORMAT
9322159047fSniklas   ++indx;
9332159047fSniklas #endif
9342159047fSniklas 
935c074d1c9Sdrahn   return TRUE;
9362159047fSniklas }
9372159047fSniklas 
9382159047fSniklas #ifndef OLDFORMAT
9392159047fSniklas 
9402159047fSniklas /* PowerPC Netware uses a word offset, not a byte offset, for public
9412159047fSniklas    symbols.  */
9422159047fSniklas 
9432159047fSniklas /* Set the section for a public symbol.  */
9442159047fSniklas 
945c074d1c9Sdrahn static bfd_boolean
nlm_powerpc_set_public_section(abfd,sym)9462159047fSniklas nlm_powerpc_set_public_section (abfd, sym)
9472159047fSniklas      bfd *abfd;
9482159047fSniklas      nlmNAME(symbol_type) *sym;
9492159047fSniklas {
9502159047fSniklas   if (sym->symbol.value & NLM_HIBIT)
9512159047fSniklas     {
9522159047fSniklas       sym->symbol.value &= ~NLM_HIBIT;
9532159047fSniklas       sym->symbol.flags |= BSF_FUNCTION;
9542159047fSniklas       sym->symbol.section =
9552159047fSniklas 	bfd_get_section_by_name (abfd, NLM_CODE_NAME);
9562159047fSniklas     }
9572159047fSniklas   else
9582159047fSniklas     {
9592159047fSniklas       sym->symbol.section =
9602159047fSniklas 	bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
9612159047fSniklas     }
9622159047fSniklas 
9632159047fSniklas   sym->symbol.value <<= 2;
9642159047fSniklas 
965c074d1c9Sdrahn   return TRUE;
9662159047fSniklas }
9672159047fSniklas 
9682159047fSniklas /* Get the offset to write out for a public symbol.  */
9692159047fSniklas 
9702159047fSniklas static bfd_vma
nlm_powerpc_get_public_offset(abfd,sym)9712159047fSniklas nlm_powerpc_get_public_offset (abfd, sym)
9722159047fSniklas      bfd *abfd;
9732159047fSniklas      asymbol *sym;
9742159047fSniklas {
9752159047fSniklas   bfd_vma offset;
9762159047fSniklas   asection *sec;
9772159047fSniklas 
9782159047fSniklas   offset = bfd_asymbol_value (sym);
9792159047fSniklas   sec = bfd_get_section (sym);
9802159047fSniklas   if (sec->flags & SEC_CODE)
9812159047fSniklas     {
9822159047fSniklas       offset -= nlm_get_text_low (abfd);
9832159047fSniklas       offset |= NLM_HIBIT;
9842159047fSniklas     }
9852159047fSniklas   else if (sec->flags & (SEC_DATA | SEC_ALLOC))
9862159047fSniklas     {
9872159047fSniklas       /* SEC_ALLOC is for the .bss section.  */
9882159047fSniklas       offset -= nlm_get_data_low (abfd);
9892159047fSniklas     }
9902159047fSniklas   else
9912159047fSniklas     {
9922159047fSniklas       /* We can't handle an exported symbol that is not in the code or
9932159047fSniklas 	 data segment.  */
9942159047fSniklas       bfd_set_error (bfd_error_invalid_operation);
9952159047fSniklas       /* FIXME: No way to return error.  */
9962159047fSniklas       abort ();
9972159047fSniklas     }
9982159047fSniklas 
9992159047fSniklas   return offset;
10002159047fSniklas }
10012159047fSniklas 
10022159047fSniklas #endif /* ! defined (OLDFORMAT) */
10032159047fSniklas 
10042159047fSniklas #include "nlmswap.h"
10052159047fSniklas 
10062159047fSniklas static const struct nlm_backend_data nlm32_powerpc_backend =
10072159047fSniklas {
10082159047fSniklas   "NetWare PowerPC Module \032",
10092159047fSniklas   sizeof (Nlm32_powerpc_External_Fixed_Header),
10102159047fSniklas #ifndef OLDFORMAT
10112159047fSniklas   0,	/* optional_prefix_size */
10122159047fSniklas #else
10132159047fSniklas   sizeof (struct nlm32_powerpc_external_prefix_header),
10142159047fSniklas #endif
10152159047fSniklas   bfd_arch_powerpc,
10162159047fSniklas   0,
1017c074d1c9Sdrahn   FALSE,
10182159047fSniklas #ifndef OLDFORMAT
10192159047fSniklas   0,	/* backend_object_p */
10202159047fSniklas   0,	/* write_prefix */
10212159047fSniklas #else
10222159047fSniklas   nlm_powerpc_backend_object_p,
10232159047fSniklas   nlm_powerpc_write_prefix,
10242159047fSniklas #endif
10252159047fSniklas   nlm_powerpc_read_reloc,
10262159047fSniklas   nlm_powerpc_mangle_relocs,
10272159047fSniklas   nlm_powerpc_read_import,
10282159047fSniklas   nlm_powerpc_write_import,
10292159047fSniklas #ifndef OLDFORMAT
10302159047fSniklas   nlm_powerpc_set_public_section,
10312159047fSniklas   nlm_powerpc_get_public_offset,
10322159047fSniklas #else
10332159047fSniklas   0,	/* set_public_section */
10342159047fSniklas   0,	/* get_public_offset */
10352159047fSniklas #endif
10362159047fSniklas   nlm_swap_fixed_header_in,
10372159047fSniklas   nlm_swap_fixed_header_out,
10382159047fSniklas   nlm_powerpc_write_external,
10392159047fSniklas   0,	/* write_export */
10402159047fSniklas };
10412159047fSniklas 
10422159047fSniklas #define TARGET_BIG_NAME			"nlm32-powerpc"
10432159047fSniklas #define TARGET_BIG_SYM			nlmNAME(powerpc_vec)
10442159047fSniklas #define TARGET_BACKEND_DATA		&nlm32_powerpc_backend
10452159047fSniklas 
10462159047fSniklas #include "nlm-target.h"
1047