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
36 
37 /* The prefix header is only used in the old format.  */
38 
39 /* PowerPC NLM's have a prefix header before the standard NLM.  This
40    function reads it in, verifies the version, and seeks the bfd to
41    the location before the regular NLM header.  */
42 
43 static bfd_boolean
nlm_powerpc_backend_object_p(bfd * abfd)44 nlm_powerpc_backend_object_p (bfd *abfd)
45 {
46   struct nlm32_powerpc_external_prefix_header s;
47 
48   if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
49     return FALSE;
50 
51   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
52       || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
53     return FALSE;
54 
55   return TRUE;
56 }
57 
58 /* Write out the prefix.  */
59 
60 static bfd_boolean
nlm_powerpc_write_prefix(bfd * abfd)61 nlm_powerpc_write_prefix (bfd *abfd)
62 {
63   struct nlm32_powerpc_external_prefix_header s;
64 
65   memset (&s, 0, sizeof s);
66   memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
67   H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
68   H_PUT_32 (abfd, 0, s.origins);
69 
70   /* FIXME: What should we do about the date?  */
71 
72   if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
73     return FALSE;
74 
75   return TRUE;
76 }
77 
78 /* This reloc handling is only applicable to the old format.  */
79 
80 /* How to process the various reloc types.  PowerPC NLMs use XCOFF
81    reloc types, and I have just copied the XCOFF reloc table here.  */
82 
83 static reloc_howto_type nlm_powerpc_howto_table[] =
84 {
85   /* Standard 32 bit relocation.  */
86   HOWTO (0,	                /* Type.  */
87 	 0,	                /* Rightshift.  */
88 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
89 	 32,	                /* Bitsize.  */
90 	 FALSE,	                /* PC relative.  */
91 	 0,	                /* Bitpos.  */
92 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
93 	 0,		        /* Special_function.  */
94 	 "R_POS",               /* Name.  */
95 	 TRUE,	                /* Partial_inplace.  */
96 	 0xffffffff,            /* Source mask.  */
97 	 0xffffffff,            /* Dest mask.  */
98 	 FALSE),                /* PC rel offset.  */
99 
100   /* 32 bit relocation, but store negative value.  */
101   HOWTO (1,	                /* Type.  */
102 	 0,	                /* Rightshift.  */
103 	 -2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
104 	 32,	                /* Bitsize.  */
105 	 FALSE,	                /* PC relative.  */
106 	 0,	                /* Bitpos.  */
107 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
108 	 0,		        /* Special_function.  */
109 	 "R_NEG",               /* Name.  */
110 	 TRUE,	                /* Partial_inplace.  */
111 	 0xffffffff,            /* Source mask.  */
112 	 0xffffffff,            /* Dest mask.  */
113 	 FALSE),                /* PC rel offset.  */
114 
115   /* 32 bit PC relative relocation.  */
116   HOWTO (2,	                /* Type.  */
117 	 0,	                /* Rightshift.  */
118 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
119 	 32,	                /* Bitsize.  */
120 	 TRUE,	                /* PC relative.  */
121 	 0,	                /* Bitpos.  */
122 	 complain_overflow_signed, /* Complain_on_overflow.  */
123 	 0,		        /* Special_function.  */
124 	 "R_REL",               /* Name.  */
125 	 TRUE,	                /* Partial_inplace.  */
126 	 0xffffffff,            /* Source mask.  */
127 	 0xffffffff,            /* Dest mask.  */
128 	 FALSE),                /* PC rel offset.  */
129 
130   /* 16 bit TOC relative relocation.  */
131   HOWTO (3,	                /* Type.  */
132 	 0,	                /* Rightshift.  */
133 	 1,	                /* Size (0 = byte, 1 = short, 2 = long).  */
134 	 16,	                /* Bitsize.  */
135 	 FALSE,	                /* PC relative.  */
136 	 0,	                /* Bitpos.  */
137 	 complain_overflow_signed, /* Complain_on_overflow.  */
138 	 0,		        /* Special_function.  */
139 	 "R_TOC",               /* Name.  */
140 	 TRUE,	                /* Partial_inplace.  */
141 	 0xffff,	        /* Source mask.  */
142 	 0xffff,        	/* Dest mask.  */
143 	 FALSE),                /* PC rel offset.  */
144 
145   /* I don't really know what this is.  */
146   HOWTO (4,	                /* Type.  */
147 	 1,	                /* Rightshift.  */
148 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
149 	 32,	                /* Bitsize.  */
150 	 FALSE,	                /* PC relative.  */
151 	 0,	                /* Bitpos.  */
152 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
153 	 0,		        /* Special_function.  */
154 	 "R_RTB",               /* Name.  */
155 	 TRUE,	                /* Partial_inplace.  */
156 	 0xffffffff,	        /* Source mask.  */
157 	 0xffffffff,        	/* Dest mask.  */
158 	 FALSE),                /* PC rel offset.  */
159 
160   /* External TOC relative symbol.  */
161   HOWTO (5,	                /* Type.  */
162 	 0,	                /* Rightshift.  */
163 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
164 	 16,	                /* Bitsize.  */
165 	 FALSE,	                /* PC relative.  */
166 	 0,	                /* Bitpos.  */
167 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
168 	 0,		        /* Special_function.  */
169 	 "R_GL",                /* Name.  */
170 	 TRUE,	                /* Partial_inplace.  */
171 	 0xffff,	        /* Source mask.  */
172 	 0xffff,        	/* Dest mask.  */
173 	 FALSE),                /* PC rel offset.  */
174 
175   /* Local TOC relative symbol.  */
176   HOWTO (6,	                /* Type.  */
177 	 0,	                /* Rightshift.  */
178 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
179 	 16,	                /* Bitsize.  */
180 	 FALSE,	                /* PC relative.  */
181 	 0,	                /* Bitpos.  */
182 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
183 	 0,		        /* Special_function.  */
184 	 "R_TCL",               /* Name.  */
185 	 TRUE,	                /* Partial_inplace.  */
186 	 0xffff,	        /* Source mask.  */
187 	 0xffff,        	/* Dest mask.  */
188 	 FALSE),                /* PC rel offset.  */
189 
190   { 7 },
191 
192   /* Non modifiable absolute branch.  */
193   HOWTO (8,	                /* Type.  */
194 	 0,	                /* Rightshift.  */
195 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
196 	 26,	                /* Bitsize.  */
197 	 FALSE,	                /* PC relative.  */
198 	 0,	                /* Bitpos.  */
199 	 complain_overflow_bitfield, /* Complain_on_overflow.  */
200 	 0,		        /* Special_function.  */
201 	 "R_BA",                /* Name.  */
202 	 TRUE,	                /* Partial_inplace.  */
203 	 0x3fffffc,	        /* Source mask.  */
204 	 0x3fffffc,        	/* Dest mask.  */
205 	 FALSE),                /* PC rel offset.  */
206 
207   { 9 },
208 
209   /* Non modifiable relative branch.  */
210   HOWTO (0xa,	                /* Type.  */
211 	 0,	                /* Rightshift.  */
212 	 2,	                /* Size (0 = byte, 1 = short, 2 = long).  */
213 	 26,	                /* Bitsize.  */
214 	 TRUE,	                /* PC relative.  */
215 	 0,	                /* Bitpos.  */
216 	 complain_overflow_signed, /* Complain_on_overflow.  */
217 	 0,		        /* Special_function.  */
218 	 "R_BR",                /* Name.  */
219 	 TRUE,	                /* Partial_inplace.  */
220 	 0x3fffffc,	        /* Source mask.  */
221 	 0x3fffffc,        	/* Dest mask.  */
222 	 FALSE),                /* PC rel offset.  */
223 
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 
432 static bfd_boolean
nlm_powerpc_read_reloc(bfd * abfd,nlmNAME (symbol_type)* sym,asection ** secp,arelent * rel)433 nlm_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 
520 static 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 
537 static bfd_boolean
nlm_powerpc_read_reloc(bfd * abfd,nlmNAME (symbol_type)* sym,asection ** secp,arelent * rel)538 nlm_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 
599 static bfd_boolean
nlm_powerpc_mangle_relocs(bfd * abfd ATTRIBUTE_UNUSED,asection * sec ATTRIBUTE_UNUSED,const void * data ATTRIBUTE_UNUSED,bfd_vma offset ATTRIBUTE_UNUSED,bfd_size_type count ATTRIBUTE_UNUSED)600 nlm_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 
611 static bfd_boolean
nlm_powerpc_read_import(bfd * abfd,nlmNAME (symbol_type)* sym)612 nlm_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 
660 static bfd_boolean
nlm_powerpc_write_import(bfd * abfd,asection * sec,arelent * rel)661 nlm_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 
728 static bfd_boolean
nlm_powerpc_write_reloc(bfd * abfd,asection * sec,arelent * rel,int indx)729 nlm_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 
830 static bfd_boolean
nlm_powerpc_write_import(bfd * abfd,asection * sec,arelent * rel)831 nlm_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 
842 static bfd_boolean
nlm_powerpc_write_external(bfd * abfd,bfd_size_type count,asymbol * sym,struct reloc_and_sec * relocs)843 nlm_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 
891 static bfd_boolean
nlm_powerpc_set_public_section(bfd * abfd,nlmNAME (symbol_type)* sym)892 nlm_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 
912 static bfd_vma
nlm_powerpc_get_public_offset(bfd * abfd,asymbol * sym)913 nlm_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 
946 static 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			powerpc_nlm32_vec
984 #define TARGET_BACKEND_DATA		& nlm32_powerpc_backend
985 
986 #include "nlm-target.h"
987