Home | History | Annotate | Download | only in bfd
      1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
      2    Copyright (C) 1994-2014 Free Software Foundation, Inc.
      3 
      4    This file is part of BFD, the Binary File Descriptor library.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include "bfd.h"
     23 #include "libbfd.h"
     24 
     25 /* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
     26    old format.  */
     27 
     28 #define ARCH_SIZE 32
     29 
     30 #include "nlm/ppc-ext.h"
     31 #define Nlm_External_Fixed_Header	Nlm32_powerpc_External_Fixed_Header
     32 
     33 #include "libnlm.h"
     34 
     35 #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 
     44 static bfd_boolean
     45 nlm_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 
     61 static bfd_boolean
     62 nlm_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 
     84 static 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 
    433 static bfd_boolean
    434 nlm_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 
    521 static 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 
    538 static bfd_boolean
    539 nlm_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 
    600 static bfd_boolean
    601 nlm_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 
    612 static bfd_boolean
    613 nlm_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 
    661 static bfd_boolean
    662 nlm_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 
    729 static bfd_boolean
    730 nlm_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 
    831 static bfd_boolean
    832 nlm_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 
    843 static bfd_boolean
    844 nlm_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
    887 
    888 /* PowerPC Netware uses a word offset, not a byte offset, for public
    889    symbols.  */
    890 
    891 /* Set the section for a public symbol.  */
    892 
    893 static bfd_boolean
    894 nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
    895 {
    896   if (sym->symbol.value & NLM_HIBIT)
    897     {
    898       sym->symbol.value &= ~NLM_HIBIT;
    899       sym->symbol.flags |= BSF_FUNCTION;
    900       sym->symbol.section =
    901 	bfd_get_section_by_name (abfd, NLM_CODE_NAME);
    902     }
    903   else
    904     sym->symbol.section =
    905       bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
    906 
    907   sym->symbol.value <<= 2;
    908 
    909   return TRUE;
    910 }
    911 
    912 /* Get the offset to write out for a public symbol.  */
    913 
    914 static bfd_vma
    915 nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
    916 {
    917   bfd_vma offset;
    918   asection *sec;
    919 
    920   offset = bfd_asymbol_value (sym);
    921   sec = bfd_get_section (sym);
    922   if (sec->flags & SEC_CODE)
    923     {
    924       offset -= nlm_get_text_low (abfd);
    925       offset |= NLM_HIBIT;
    926     }
    927   else if (sec->flags & (SEC_DATA | SEC_ALLOC))
    928     {
    929       /* SEC_ALLOC is for the .bss section.  */
    930       offset -= nlm_get_data_low (abfd);
    931     }
    932   else
    933     {
    934       /* We can't handle an exported symbol that is not in the code or
    935 	 data segment.  */
    936       bfd_set_error (bfd_error_invalid_operation);
    937       /* FIXME: No way to return error.  */
    938       abort ();
    939     }
    940 
    941   return offset;
    942 }
    943 
    944 #endif /* ! defined (OLDFORMAT) */
    945 
    946 #include "nlmswap.h"
    948 
    949 static const struct nlm_backend_data nlm32_powerpc_backend =
    950 {
    951   "NetWare PowerPC Module \032",
    952   sizeof (Nlm32_powerpc_External_Fixed_Header),
    953 #ifndef OLDFORMAT
    954   0,	/* Optional_prefix_size.  */
    955 #else
    956   sizeof (struct nlm32_powerpc_external_prefix_header),
    957 #endif
    958   bfd_arch_powerpc,
    959   0,
    960   FALSE,
    961 #ifndef OLDFORMAT
    962   0,	/* Backend_object_p.  */
    963   0,	/* Write_prefix.  */
    964 #else
    965   nlm_powerpc_backend_object_p,
    966   nlm_powerpc_write_prefix,
    967 #endif
    968   nlm_powerpc_read_reloc,
    969   nlm_powerpc_mangle_relocs,
    970   nlm_powerpc_read_import,
    971   nlm_powerpc_write_import,
    972 #ifndef OLDFORMAT
    973   nlm_powerpc_set_public_section,
    974   nlm_powerpc_get_public_offset,
    975 #else
    976   0,	/* Set_public_section.  */
    977   0,	/* Get_public_offset.  */
    978 #endif
    979   nlm_swap_fixed_header_in,
    980   nlm_swap_fixed_header_out,
    981   nlm_powerpc_write_external,
    982   0,	/* Write_export.  */
    983 };
    984 
    985 #define TARGET_BIG_NAME			"nlm32-powerpc"
    986 #define TARGET_BIG_SYM			powerpc_nlm32_vec
    987 #define TARGET_BACKEND_DATA		& nlm32_powerpc_backend
    988 
    989 #include "nlm-target.h"
    990