* gas/hppa/reloc/reloc.exp: Minor fixes so that SOM & ELF can
[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
25#include "libnlm.h"
26
27static boolean nlm_i386_read_reloc
28 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
29static boolean nlm_i386_write_reloc
30 PARAMS ((bfd *, asection *, arelent *));
31static boolean nlm_i386_mangle_relocs
32 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
33
34/* Adjust the reloc location by an absolute value. */
35
36static reloc_howto_type nlm_i386_abs_howto =
37 HOWTO (0, /* type */
38 0, /* rightshift */
39 2, /* size (0 = byte, 1 = short, 2 = long) */
40 32, /* bitsize */
41 false, /* pc_relative */
42 0, /* bitpos */
43 complain_overflow_bitfield, /* complain_on_overflow */
44 0, /* special_function */
45 "32", /* name */
46 true, /* partial_inplace */
47 0xffffffff, /* src_mask */
48 0xffffffff, /* dst_mask */
49 false); /* pcrel_offset */
50
51/* Adjust the reloc location by a PC relative displacement. */
52
53static reloc_howto_type nlm_i386_pcrel_howto =
54 HOWTO (1, /* type */
55 0, /* rightshift */
56 2, /* size (0 = byte, 1 = short, 2 = long) */
57 32, /* bitsize */
58 true, /* pc_relative */
59 0, /* bitpos */
60 complain_overflow_signed, /* complain_on_overflow */
61 0, /* special_function */
62 "DISP32", /* name */
63 true, /* partial_inplace */
64 0xffffffff, /* src_mask */
65 0xffffffff, /* dst_mask */
66 true); /* pcrel_offset */
67
68/* Read a NetWare i386 reloc. */
69
70static boolean
71nlm_i386_read_reloc (abfd, sym, secp, rel)
72 bfd *abfd;
73 nlmNAME(symbol_type) *sym;
74 asection **secp;
75 arelent *rel;
76{
77 bfd_byte temp[4];
78 bfd_vma val;
79 const char *name;
80
81 if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
82 {
83 bfd_error = system_call_error;
84 return false;
85 }
86
87 val = bfd_get_32 (abfd, temp);
88
89 /* The value is an offset into either the code or data segment.
90 This is the location which needs to be adjusted.
91
92 If this is a relocation fixup rather than an imported symbol (the
93 sym argument is NULL) then the high bit is 0 if the location
94 needs to be adjusted by the address of the data segment, or 1 if
95 the location needs to be adjusted by the address of the code
96 segment. If this is an imported symbol, then the high bit is 0
97 if the location is 0 if the location should be adjusted by the
98 offset to the symbol, or 1 if the location should adjusted by the
99 absolute value of the symbol.
100
101 The second most significant bit is 0 if the value is an offset
102 into the data segment, or 1 if the value is an offset into the
103 code segment.
104
105 All this translates fairly easily into a BFD reloc. */
106
107 if (sym == NULL)
108 {
109 if ((val & NLM_HIBIT) == 0)
110 name = NLM_INITIALIZED_DATA_NAME;
111 else
112 {
113 name = NLM_CODE_NAME;
114 val &=~ NLM_HIBIT;
115 }
116 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
117 rel->howto = &nlm_i386_abs_howto;
118 }
119 else
120 {
121 /* In this case we do not need to set the sym_ptr_ptr field. */
122 rel->sym_ptr_ptr = NULL;
123 if ((val & NLM_HIBIT) == 0)
124 rel->howto = &nlm_i386_pcrel_howto;
125 else
126 {
127 rel->howto = &nlm_i386_abs_howto;
128 val &=~ NLM_HIBIT;
129 }
130 }
131
132 if ((val & (NLM_HIBIT >> 1)) == 0)
133 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
134 else
135 {
136 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
137 val &=~ (NLM_HIBIT >> 1);
138 }
139
140 rel->address = val;
141 rel->addend = 0;
142
143 return true;
144}
145
146/* Write a NetWare i386 reloc. */
147
148static boolean
149nlm_i386_write_reloc (abfd, sec, rel)
150 bfd *abfd;
151 asection *sec;
152 arelent *rel;
153{
154 asymbol *sym;
155 bfd_vma val;
156 bfd_byte temp[4];
157
158 /* NetWare only supports two kinds of relocs. We should check
159 special_function here, as well, but at the moment coff-i386
160 relocs uses a special_function which does not affect what we do
161 here. */
162 if (rel->addend != 0
163 || rel->howto == NULL
164 || rel->howto->rightshift != 0
165 || rel->howto->size != 2
166 || rel->howto->bitsize != 32
167 || rel->howto->bitpos != 0
168 || ! rel->howto->partial_inplace
169 || rel->howto->src_mask != 0xffffffff
170 || rel->howto->dst_mask != 0xffffffff)
171 {
172 bfd_error = invalid_operation;
173 return false;
174 }
175
176 sym = *rel->sym_ptr_ptr;
177
178 /* The value we write out is the offset into the appropriate
179 segment. This offset is the section vma, adjusted by the vma of
180 the lowest section in that segment, plus the address of the
181 relocation. */
182 val = bfd_get_section_vma (abfd, sec) + rel->address;
183
184 /* The second most significant bit is 0 if the value is an offset
185 into the data segment, or 1 if the value is an offset into the
186 code segment. */
187 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
188 {
189 val -= nlm_get_text_low (abfd);
190 val |= NLM_HIBIT >> 1;
191 }
192 else
193 val -= nlm_get_data_low (abfd);
194
195 if (bfd_get_section (sym) != &bfd_und_section)
196 {
197 /* NetWare only supports absolute internal relocs. */
198 if (rel->howto->pc_relative)
199 {
200 bfd_error = invalid_operation;
201 return false;
202 }
203
204 /* The high bit is 1 if the reloc is against the code section, 0
205 if against the data section. */
206 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
207 val |= NLM_HIBIT;
208 }
209 else
210 {
211 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
212 relative. */
213 if (! rel->howto->pc_relative)
214 val |= NLM_HIBIT;
215 else
216 {
217 /* PC relative relocs on NetWare must be pcrel_offset. */
218 if (! rel->howto->pcrel_offset)
219 {
220 bfd_error = invalid_operation;
221 return false;
222 }
223 }
224 }
225
226 bfd_put_32 (abfd, val, temp);
227 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
228 {
229 bfd_error = system_call_error;
230 return false;
231 }
232
233 return true;
234}
235
236/* I want to be able to use objcopy to turn a i386 a.out or COFF file
237 into a NetWare i386 module. That means that the relocs from the
238 source file have to be mapped into relocs that apply to the target
239 file. This function is called by nlm_set_section_contents to give
240 it a chance to rework the relocs.
241
242 This is actually a fairly general concept. However, this is not a
243 general implementation. */
244
245static boolean
246nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
247 bfd *abfd;
248 asection *sec;
249 PTR data;
250 bfd_vma offset;
251 bfd_size_type count;
252{
253 arelent **rel_ptr_ptr, **rel_end;
254
255 rel_ptr_ptr = sec->orelocation;
256 rel_end = rel_ptr_ptr + sec->reloc_count;
257 for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
258 {
259 arelent *rel;
260 asymbol *sym;
261 bfd_vma addend;
262
263 rel = *rel_ptr_ptr;
264 sym = *rel->sym_ptr_ptr;
265
266 /* Note that no serious harm will ensue if we fail to change a
267 reloc. We will wind up failing in nlm_i386_write_reloc. */
268
269 /* Make sure this reloc is within the data we have. We only 4
270 byte relocs here, so we insist on having 4 bytes. */
271 if (rel->address < offset
272 || rel->address + 4 > offset + count)
273 continue;
274
275 /* NetWare doesn't support reloc addends, so we get rid of them
276 here by simply adding them into the object data. We handle
277 the symbol value, if any, the same way. */
278 addend = rel->addend + sym->value;
279
280 /* The value of a symbol is the offset into the section. If the
281 symbol is in the .bss segment, we need to include the size of
282 the data segment in the offset as well. Fortunately, we know
283 that at this point the size of the data section is in the NLM
284 header. */
285 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
286 & (SEC_CODE | SEC_DATA)) == 0)
287 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
288 & SEC_ALLOC) != 0))
289 addend += nlm_fixed_header (abfd)->dataImageSize;
290
291 if (addend != 0
292 && rel->howto != NULL
293 && rel->howto->rightshift == 0
294 && rel->howto->size == 2
295 && rel->howto->bitsize == 32
296 && rel->howto->bitpos == 0
297 && rel->howto->partial_inplace
298 && rel->howto->src_mask == 0xffffffff
299 && rel->howto->dst_mask == 0xffffffff)
300 {
301 bfd_vma val;
302
303 val = bfd_get_32 (abfd, (char *) data + rel->address - offset);
304 val += addend;
305 bfd_put_32 (abfd, val, (char *) data + rel->address - offset);
306 rel->addend = 0;
307 }
308
309 /* NetWare uses a reloc with pcrel_offset set. We adjust
310 pc_relative relocs accordingly. We are going to change the
311 howto field, so we can only do this if the current one is
312 compatible. We should check special_function here, but at
313 the moment coff-i386 uses a special_function which does not
314 affect what we are doing here. */
315 if (rel->howto != NULL
316 && rel->howto->pc_relative
317 && ! rel->howto->pcrel_offset
318 && rel->howto->rightshift == 0
319 && rel->howto->size == 2
320 && rel->howto->bitsize == 32
321 && rel->howto->bitpos == 0
322 && rel->howto->partial_inplace
323 && rel->howto->src_mask == 0xffffffff
324 && rel->howto->dst_mask == 0xffffffff)
325 {
326 bfd_vma val;
327
328 /* When pcrel_offset is not set, it means that the negative
329 of the address of the memory location is stored in the
330 memory location. We must add it back in. */
331 val = bfd_get_32 (abfd, (char *) data + rel->address - offset);
332 val += rel->address;
333 bfd_put_32 (abfd, val, (char *) data + rel->address - offset);
334
335 rel->howto = &nlm_i386_pcrel_howto;
336 }
337 }
338
339 return true;
340}
341
342static const struct nlm_backend_data nlm32_i386_backend =
343{
344 bfd_arch_i386,
345 nlm_i386_read_reloc,
346 nlm_i386_write_reloc,
347 nlm_i386_mangle_relocs
348};
349
350#define TARGET_LITTLE_NAME "nlm32-i386"
351#define TARGET_LITTLE_SYM nlmNAME(i386_vec)
352#define TARGET_BACKEND_DATA &nlm32_i386_backend
353
354#include "nlm-target.h"
This page took 0.048637 seconds and 4 git commands to generate.