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