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