* scripttempl/alpha.sc: Don't create .lit4 or .sdata sections,
[deliverable/binutils-gdb.git] / bfd / nlm32-i386.c
CommitLineData
7389debf
ILT
1/* Support for 32-bit i386 NLM (NetWare Loadable Module)
2 Copyright (C) 1993 Free Software Foundation, Inc.
3
4This file is part of BFD, the Binary File Descriptor library.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "bfd.h"
21#include "sysdep.h"
22#include "libbfd.h"
23
24#define ARCH_SIZE 32
cdbfad1c
ILT
25
26#include "nlm/i386-ext.h"
27#define Nlm_External_Fixed_Header Nlm32_i386_External_Fixed_Header
28
7389debf
ILT
29#include "libnlm.h"
30
31static boolean nlm_i386_read_reloc
32 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
cdbfad1c 33static boolean nlm_i386_write_import
7389debf
ILT
34 PARAMS ((bfd *, asection *, arelent *));
35static boolean nlm_i386_mangle_relocs
36 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
cdbfad1c
ILT
37static boolean nlm_i386_read_import
38 PARAMS ((bfd *, nlmNAME(symbol_type) *));
39static boolean nlm_i386_write_external
40 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
7389debf
ILT
41
42/* Adjust the reloc location by an absolute value. */
43
44static reloc_howto_type nlm_i386_abs_howto =
45 HOWTO (0, /* type */
46 0, /* rightshift */
47 2, /* size (0 = byte, 1 = short, 2 = long) */
48 32, /* bitsize */
49 false, /* pc_relative */
50 0, /* bitpos */
51 complain_overflow_bitfield, /* complain_on_overflow */
52 0, /* special_function */
53 "32", /* name */
54 true, /* partial_inplace */
55 0xffffffff, /* src_mask */
56 0xffffffff, /* dst_mask */
57 false); /* pcrel_offset */
58
59/* Adjust the reloc location by a PC relative displacement. */
60
61static reloc_howto_type nlm_i386_pcrel_howto =
62 HOWTO (1, /* type */
63 0, /* rightshift */
64 2, /* size (0 = byte, 1 = short, 2 = long) */
65 32, /* bitsize */
66 true, /* pc_relative */
67 0, /* bitpos */
68 complain_overflow_signed, /* complain_on_overflow */
69 0, /* special_function */
70 "DISP32", /* name */
71 true, /* partial_inplace */
72 0xffffffff, /* src_mask */
73 0xffffffff, /* dst_mask */
74 true); /* pcrel_offset */
75
76/* Read a NetWare i386 reloc. */
77
78static boolean
79nlm_i386_read_reloc (abfd, sym, secp, rel)
80 bfd *abfd;
81 nlmNAME(symbol_type) *sym;
82 asection **secp;
83 arelent *rel;
84{
85 bfd_byte temp[4];
86 bfd_vma val;
87 const char *name;
88
89 if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
90 {
91 bfd_error = system_call_error;
92 return false;
93 }
94
95 val = bfd_get_32 (abfd, temp);
96
97 /* The value is an offset into either the code or data segment.
98 This is the location which needs to be adjusted.
99
100 If this is a relocation fixup rather than an imported symbol (the
101 sym argument is NULL) then the high bit is 0 if the location
102 needs to be adjusted by the address of the data segment, or 1 if
103 the location needs to be adjusted by the address of the code
104 segment. If this is an imported symbol, then the high bit is 0
105 if the location is 0 if the location should be adjusted by the
106 offset to the symbol, or 1 if the location should adjusted by the
107 absolute value of the symbol.
108
109 The second most significant bit is 0 if the value is an offset
110 into the data segment, or 1 if the value is an offset into the
111 code segment.
112
113 All this translates fairly easily into a BFD reloc. */
114
115 if (sym == NULL)
116 {
117 if ((val & NLM_HIBIT) == 0)
118 name = NLM_INITIALIZED_DATA_NAME;
119 else
120 {
121 name = NLM_CODE_NAME;
122 val &=~ NLM_HIBIT;
123 }
124 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
125 rel->howto = &nlm_i386_abs_howto;
126 }
127 else
128 {
129 /* In this case we do not need to set the sym_ptr_ptr field. */
130 rel->sym_ptr_ptr = NULL;
131 if ((val & NLM_HIBIT) == 0)
132 rel->howto = &nlm_i386_pcrel_howto;
133 else
134 {
135 rel->howto = &nlm_i386_abs_howto;
136 val &=~ NLM_HIBIT;
137 }
138 }
139
140 if ((val & (NLM_HIBIT >> 1)) == 0)
141 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
142 else
143 {
144 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
145 val &=~ (NLM_HIBIT >> 1);
146 }
147
148 rel->address = val;
149 rel->addend = 0;
150
151 return true;
152}
153
154/* Write a NetWare i386 reloc. */
155
156static boolean
cdbfad1c 157nlm_i386_write_import (abfd, sec, rel)
7389debf
ILT
158 bfd *abfd;
159 asection *sec;
160 arelent *rel;
161{
162 asymbol *sym;
163 bfd_vma val;
164 bfd_byte temp[4];
165
166 /* NetWare only supports two kinds of relocs. We should check
167 special_function here, as well, but at the moment coff-i386
168 relocs uses a special_function which does not affect what we do
169 here. */
170 if (rel->addend != 0
171 || rel->howto == NULL
172 || rel->howto->rightshift != 0
173 || rel->howto->size != 2
174 || rel->howto->bitsize != 32
175 || rel->howto->bitpos != 0
7389debf
ILT
176 || rel->howto->src_mask != 0xffffffff
177 || rel->howto->dst_mask != 0xffffffff)
178 {
179 bfd_error = invalid_operation;
180 return false;
181 }
182
183 sym = *rel->sym_ptr_ptr;
184
185 /* The value we write out is the offset into the appropriate
186 segment. This offset is the section vma, adjusted by the vma of
187 the lowest section in that segment, plus the address of the
188 relocation. */
189 val = bfd_get_section_vma (abfd, sec) + rel->address;
190
191 /* The second most significant bit is 0 if the value is an offset
192 into the data segment, or 1 if the value is an offset into the
193 code segment. */
194 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
195 {
196 val -= nlm_get_text_low (abfd);
197 val |= NLM_HIBIT >> 1;
198 }
199 else
200 val -= nlm_get_data_low (abfd);
201
202 if (bfd_get_section (sym) != &bfd_und_section)
203 {
204 /* NetWare only supports absolute internal relocs. */
205 if (rel->howto->pc_relative)
206 {
207 bfd_error = invalid_operation;
208 return false;
209 }
210
211 /* The high bit is 1 if the reloc is against the code section, 0
212 if against the data section. */
213 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
214 val |= NLM_HIBIT;
215 }
216 else
217 {
218 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
219 relative. */
220 if (! rel->howto->pc_relative)
221 val |= NLM_HIBIT;
222 else
223 {
224 /* PC relative relocs on NetWare must be pcrel_offset. */
225 if (! rel->howto->pcrel_offset)
226 {
227 bfd_error = invalid_operation;
228 return false;
229 }
230 }
231 }
232
233 bfd_put_32 (abfd, val, temp);
234 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
235 {
236 bfd_error = system_call_error;
237 return false;
238 }
239
240 return true;
241}
242
243/* I want to be able to use objcopy to turn a i386 a.out or COFF file
244 into a NetWare i386 module. That means that the relocs from the
245 source file have to be mapped into relocs that apply to the target
246 file. This function is called by nlm_set_section_contents to give
247 it a chance to rework the relocs.
248
249 This is actually a fairly general concept. However, this is not a
250 general implementation. */
251
252static boolean
253nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
254 bfd *abfd;
255 asection *sec;
256 PTR data;
257 bfd_vma offset;
258 bfd_size_type count;
259{
260 arelent **rel_ptr_ptr, **rel_end;
261
262 rel_ptr_ptr = sec->orelocation;
263 rel_end = rel_ptr_ptr + sec->reloc_count;
264 for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
265 {
266 arelent *rel;
267 asymbol *sym;
268 bfd_vma addend;
269
270 rel = *rel_ptr_ptr;
271 sym = *rel->sym_ptr_ptr;
272
273 /* Note that no serious harm will ensue if we fail to change a
cdbfad1c 274 reloc. We will wind up failing in nlm_i386_write_import. */
7389debf
ILT
275
276 /* Make sure this reloc is within the data we have. We only 4
277 byte relocs here, so we insist on having 4 bytes. */
278 if (rel->address < offset
279 || rel->address + 4 > offset + count)
280 continue;
281
282 /* NetWare doesn't support reloc addends, so we get rid of them
283 here by simply adding them into the object data. We handle
284 the symbol value, if any, the same way. */
285 addend = rel->addend + sym->value;
286
287 /* The value of a symbol is the offset into the section. If the
288 symbol is in the .bss segment, we need to include the size of
289 the data segment in the offset as well. Fortunately, we know
290 that at this point the size of the data section is in the NLM
291 header. */
292 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
cdbfad1c 293 & SEC_LOAD) == 0)
7389debf
ILT
294 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
295 & SEC_ALLOC) != 0))
296 addend += nlm_fixed_header (abfd)->dataImageSize;
297
298 if (addend != 0
299 && rel->howto != NULL
300 && rel->howto->rightshift == 0
301 && rel->howto->size == 2
302 && rel->howto->bitsize == 32
303 && rel->howto->bitpos == 0
7389debf
ILT
304 && rel->howto->src_mask == 0xffffffff
305 && rel->howto->dst_mask == 0xffffffff)
306 {
307 bfd_vma val;
308
cdbfad1c 309 val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
7389debf 310 val += addend;
cdbfad1c 311 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
7389debf
ILT
312 rel->addend = 0;
313 }
314
315 /* NetWare uses a reloc with pcrel_offset set. We adjust
316 pc_relative relocs accordingly. We are going to change the
317 howto field, so we can only do this if the current one is
318 compatible. We should check special_function here, but at
319 the moment coff-i386 uses a special_function which does not
320 affect what we are doing here. */
321 if (rel->howto != NULL
322 && rel->howto->pc_relative
323 && ! rel->howto->pcrel_offset
324 && rel->howto->rightshift == 0
325 && rel->howto->size == 2
326 && rel->howto->bitsize == 32
327 && rel->howto->bitpos == 0
7389debf
ILT
328 && rel->howto->src_mask == 0xffffffff
329 && rel->howto->dst_mask == 0xffffffff)
330 {
331 bfd_vma val;
332
333 /* When pcrel_offset is not set, it means that the negative
334 of the address of the memory location is stored in the
335 memory location. We must add it back in. */
cdbfad1c 336 val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
7389debf 337 val += rel->address;
cdbfad1c 338 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
7389debf
ILT
339
340 rel->howto = &nlm_i386_pcrel_howto;
341 }
342 }
343
344 return true;
345}
346
cdbfad1c
ILT
347/* Read a NetWare i386 import record */
348static boolean
349nlm_i386_read_import (abfd, sym)
350 bfd *abfd;
351 nlmNAME(symbol_type) *sym;
352{
353 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
354 bfd_size_type rcount; /* number of relocs */
355 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
356 unsigned char symlength; /* length of symbol name */
357
358 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
359 != sizeof (symlength))
360 {
361 bfd_error = system_call_error;
362 return (false);
363 }
364 sym -> symbol.the_bfd = abfd;
365 sym -> symbol.name = bfd_alloc (abfd, symlength + 1);
366 if (bfd_read ((PTR) sym -> symbol.name, symlength, 1, abfd)
367 != symlength)
368 {
369 bfd_error = system_call_error;
370 return (false);
371 }
372 sym -> symbol.flags = 0;
373 sym -> symbol.value = 0;
374 sym -> symbol.section = &bfd_und_section;
375 if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
376 {
377 bfd_error = system_call_error;
378 return (false);
379 }
380 rcount = bfd_h_get_32 (abfd, temp);
381 nlm_relocs = ((struct nlm_relent *)
382 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
383 sym -> relocs = nlm_relocs;
384 sym -> rcnt = 0;
385 while (sym -> rcnt < rcount)
386 {
387 asection *section;
388
389 if (nlm_i386_read_reloc (abfd, sym, &section,
390 &nlm_relocs -> reloc)
391 == false)
392 return false;
393 nlm_relocs -> section = section;
394 nlm_relocs++;
395 sym -> rcnt++;
396 }
397 return true;
398}
399
400/* Write out an external reference. */
401
402static boolean
403nlm_i386_write_external (abfd, count, sym, relocs)
404 bfd *abfd;
405 bfd_size_type count;
406 asymbol *sym;
407 struct reloc_and_sec *relocs;
408{
409 int i;
410 bfd_byte len;
411 unsigned char temp[NLM_TARGET_LONG_SIZE];
412
413 len = strlen (sym->name);
414 if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
415 || bfd_write (sym->name, len, 1, abfd) != len)
416 {
417 bfd_error = system_call_error;
418 return false;
419 }
420
421 bfd_put_32 (abfd, count, temp);
422 if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
423 {
424 bfd_error = system_call_error;
425 return false;
426 }
427
428 for (i = 0; i < count; i++)
429 {
430 if (nlm_i386_write_import (abfd, relocs[i].sec,
431 relocs[i].rel) == false)
432 return false;
433 }
434
435 return true;
436}
437
438#include "nlmswap.h"
439
7389debf
ILT
440static const struct nlm_backend_data nlm32_i386_backend =
441{
cdbfad1c
ILT
442 "NetWare Loadable Module\032",
443 sizeof (Nlm32_i386_External_Fixed_Header),
444 0, /* optional_prefix_size */
7389debf 445 bfd_arch_i386,
cdbfad1c
ILT
446 0,
447 0, /* backend_object_p */
448 0, /* write_prefix_func */
7389debf 449 nlm_i386_read_reloc,
cdbfad1c
ILT
450 nlm_i386_mangle_relocs,
451 nlm_i386_read_import,
452 nlm_i386_write_import,
453 0, /* set_public_section */
454 0, /* get_public_offset */
455 nlm_swap_fixed_header_in,
456 nlm_swap_fixed_header_out,
457 nlm_i386_write_external,
7389debf
ILT
458};
459
460#define TARGET_LITTLE_NAME "nlm32-i386"
461#define TARGET_LITTLE_SYM nlmNAME(i386_vec)
462#define TARGET_BACKEND_DATA &nlm32_i386_backend
463
464#include "nlm-target.h"
This page took 0.081741 seconds and 4 git commands to generate.