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, §ion, &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