]>
Commit | Line | Data |
---|---|---|
252b5132 RH |
1 | /* vms-gsd.c -- BFD back-end for VAX (openVMS/VAX) and |
2 | EVAX (openVMS/Alpha) files. | |
3f3c5c34 AM |
3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 |
4 | Free Software Foundation, Inc. | |
252b5132 RH |
5 | |
6 | go and read the openVMS linker manual (esp. appendix B) | |
7 | if you don't know what's going on here :-) | |
8 | ||
9 | Written by Klaus K"ampf ([email protected]) | |
10 | ||
11 | This program is free software; you can redistribute it and/or modify | |
12 | it under the terms of the GNU General Public License as published by | |
13 | the Free Software Foundation; either version 2 of the License, or | |
14 | (at your option) any later version. | |
15 | ||
16 | This program is distributed in the hope that it will be useful, | |
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | GNU General Public License for more details. | |
20 | ||
21 | You should have received a copy of the GNU General Public License | |
22 | along with this program; if not, write to the Free Software | |
23 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
24 | ||
252b5132 RH |
25 | #include "bfd.h" |
26 | #include "sysdep.h" | |
27 | #include "bfdlink.h" | |
28 | #include "libbfd.h" | |
29 | ||
30 | #include "vms.h" | |
31 | ||
32 | /*-----------------------------------------------------------------------------*/ | |
33 | ||
34 | /* typical sections for vax object files */ | |
35 | ||
36 | #define VAX_CODE_NAME "$CODE" | |
37 | #define VAX_DATA_NAME "$DATA" | |
38 | #define VAX_ADDRESS_DATA_NAME "$ADDRESS_DATA" | |
39 | ||
40 | /* typical sections for evax object files */ | |
41 | ||
42 | #define EVAX_ABS_NAME "$ABS$" | |
43 | #define EVAX_CODE_NAME "$CODE$" | |
44 | #define EVAX_LINK_NAME "$LINK$" | |
45 | #define EVAX_DATA_NAME "$DATA$" | |
46 | #define EVAX_BSS_NAME "$BSS$" | |
47 | #define EVAX_READONLYADDR_NAME "$READONLY_ADDR$" | |
48 | #define EVAX_READONLY_NAME "$READONLY$" | |
49 | #define EVAX_LITERAL_NAME "$LITERAL$" | |
50 | #define EVAX_COMMON_NAME "$COMMON$" | |
51 | #define EVAX_LOCAL_NAME "$LOCAL$" | |
52 | ||
53 | struct sec_flags_struct { | |
54 | char *name; /* name of section */ | |
55 | int vflags_always; | |
56 | flagword flags_always; /* flags we set always */ | |
57 | int vflags_hassize; | |
58 | flagword flags_hassize; /* flags we set if the section has a size > 0 */ | |
59 | }; | |
60 | ||
61 | /* These flags are deccrtl/vaxcrtl (openVMS 6.2 VAX) compatible */ | |
62 | ||
63 | static struct sec_flags_struct vax_section_flags[] = { | |
64 | { VAX_CODE_NAME, | |
65 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_SHR|GPS_S_M_EXE|GPS_S_M_RD), | |
66 | (SEC_CODE), | |
67 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_SHR|GPS_S_M_EXE|GPS_S_M_RD), | |
68 | (SEC_IN_MEMORY|SEC_CODE|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
69 | { VAX_DATA_NAME, | |
70 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD|GPS_S_M_WRT), | |
71 | (SEC_DATA), | |
72 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD|GPS_S_M_WRT), | |
73 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
74 | { VAX_ADDRESS_DATA_NAME, | |
75 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD), | |
76 | (SEC_DATA|SEC_READONLY), | |
77 | (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD), | |
78 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, | |
79 | { NULL, | |
80 | (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD|GPS_S_M_WRT), | |
81 | (SEC_DATA), | |
82 | (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD|GPS_S_M_WRT), | |
83 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) } | |
84 | }; | |
85 | ||
252b5132 RH |
86 | /* These flags are deccrtl/vaxcrtl (openVMS 6.2 Alpha) compatible */ |
87 | ||
88 | static struct sec_flags_struct evax_section_flags[] = { | |
89 | { EVAX_ABS_NAME, | |
90 | (EGPS_S_V_SHR), | |
91 | (SEC_DATA), | |
92 | (EGPS_S_V_SHR), | |
93 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
94 | { EVAX_CODE_NAME, | |
95 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_EXE), | |
96 | (SEC_CODE), | |
97 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_EXE), | |
98 | (SEC_IN_MEMORY|SEC_CODE|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
99 | { EVAX_LITERAL_NAME, | |
100 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD|EGPS_S_V_NOMOD), | |
101 | (SEC_DATA|SEC_READONLY), | |
102 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), | |
103 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, | |
104 | { EVAX_LINK_NAME, | |
105 | (EGPS_S_V_REL|EGPS_S_V_RD), | |
106 | (SEC_DATA|SEC_READONLY), | |
107 | (EGPS_S_V_REL|EGPS_S_V_RD), | |
108 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, | |
109 | { EVAX_DATA_NAME, | |
110 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD), | |
111 | (SEC_DATA), | |
112 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), | |
113 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
114 | { EVAX_BSS_NAME, | |
115 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD), | |
116 | (SEC_NO_FLAGS), | |
117 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD), | |
118 | (SEC_IN_MEMORY|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
119 | { EVAX_READONLYADDR_NAME, | |
120 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_RD), | |
121 | (SEC_DATA|SEC_READONLY), | |
122 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_RD), | |
123 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, | |
124 | { EVAX_READONLY_NAME, | |
125 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD|EGPS_S_V_NOMOD), | |
126 | (SEC_DATA|SEC_READONLY), | |
127 | (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), | |
128 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, | |
129 | { EVAX_LOCAL_NAME, | |
130 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), | |
131 | (SEC_DATA), | |
132 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), | |
133 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, | |
134 | { NULL, | |
135 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), | |
136 | (SEC_DATA), | |
137 | (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), | |
138 | (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) } | |
139 | }; | |
140 | ||
524f76c9 AJ |
141 | static flagword vms_secflag_by_name PARAMS ((bfd *, struct sec_flags_struct *, char *, int)); |
142 | static flagword vms_esecflag_by_name PARAMS ((struct sec_flags_struct *, char *, int)); | |
143 | ||
252b5132 RH |
144 | /* Retrieve bfd section flags by name and size */ |
145 | ||
146 | static flagword | |
dc810e39 | 147 | vms_secflag_by_name (abfd, section_flags, name, hassize) |
252b5132 RH |
148 | bfd *abfd; |
149 | struct sec_flags_struct *section_flags; | |
150 | char *name; | |
dc810e39 | 151 | int hassize; |
252b5132 RH |
152 | { |
153 | int i = 0; | |
154 | ||
155 | while (section_flags[i].name != NULL) | |
156 | { | |
157 | if ((PRIV(is_vax)? | |
158 | strcasecmp (name, section_flags[i].name): | |
159 | strcmp (name, section_flags[i].name)) == 0) | |
160 | { | |
dc810e39 | 161 | if (hassize) |
252b5132 RH |
162 | return section_flags[i].flags_hassize; |
163 | else | |
164 | return section_flags[i].flags_always; | |
165 | } | |
166 | i++; | |
167 | } | |
dc810e39 | 168 | if (hassize) |
252b5132 RH |
169 | return section_flags[i].flags_hassize; |
170 | return section_flags[i].flags_always; | |
171 | } | |
172 | ||
252b5132 RH |
173 | /* Retrieve vms section flags by name and size */ |
174 | ||
175 | static flagword | |
dc810e39 | 176 | vms_esecflag_by_name (section_flags, name, hassize) |
252b5132 RH |
177 | struct sec_flags_struct *section_flags; |
178 | char *name; | |
dc810e39 | 179 | int hassize; |
252b5132 RH |
180 | { |
181 | int i = 0; | |
182 | ||
183 | while (section_flags[i].name != NULL) | |
184 | { | |
185 | if (strcmp (name, section_flags[i].name) == 0) | |
186 | { | |
dc810e39 | 187 | if (hassize) |
252b5132 RH |
188 | return section_flags[i].vflags_hassize; |
189 | else | |
190 | return section_flags[i].vflags_always; | |
191 | } | |
192 | i++; | |
193 | } | |
dc810e39 | 194 | if (hassize) |
252b5132 RH |
195 | return section_flags[i].vflags_hassize; |
196 | return section_flags[i].vflags_always; | |
197 | } | |
198 | ||
199 | /*-----------------------------------------------------------------------------*/ | |
200 | #if VMS_DEBUG | |
201 | /* debug */ | |
202 | ||
203 | struct flagdescstruct { char *name; flagword value; }; | |
204 | ||
205 | /* Convert flag to printable string */ | |
206 | ||
207 | static char * | |
208 | flag2str(flagdesc, flags) | |
209 | struct flagdescstruct *flagdesc; | |
210 | flagword flags; | |
211 | { | |
212 | ||
213 | static char res[64]; | |
214 | int next = 0; | |
215 | ||
216 | res[0] = 0; | |
217 | while (flagdesc->name != NULL) | |
218 | { | |
219 | if ((flags & flagdesc->value) != 0) | |
220 | { | |
221 | if (next) | |
222 | strcat(res, ","); | |
223 | else | |
224 | next = 1; | |
225 | strcat (res, flagdesc->name); | |
226 | } | |
227 | flagdesc++; | |
228 | } | |
229 | return res; | |
230 | } | |
231 | #endif | |
232 | ||
233 | /*-----------------------------------------------------------------------------*/ | |
234 | /* input routines */ | |
235 | ||
236 | /* Process GSD/EGSD record | |
237 | return 0 on success, -1 on error */ | |
238 | ||
239 | int | |
240 | _bfd_vms_slurp_gsd (abfd, objtype) | |
241 | bfd *abfd; | |
242 | int objtype; | |
243 | { | |
244 | #if VMS_DEBUG | |
245 | static struct flagdescstruct gpsflagdesc[] = | |
246 | { | |
247 | { "PIC", 0x0001 }, | |
248 | { "LIB", 0x0002 }, | |
249 | { "OVR", 0x0004 }, | |
250 | { "REL", 0x0008 }, | |
251 | { "GBL", 0x0010 }, | |
252 | { "SHR", 0x0020 }, | |
253 | { "EXE", 0x0040 }, | |
254 | { "RD", 0x0080 }, | |
255 | { "WRT", 0x0100 }, | |
256 | { "VEC", 0x0200 }, | |
257 | { "NOMOD", 0x0400 }, | |
258 | { "COM", 0x0800 }, | |
259 | { NULL, 0 } | |
260 | }; | |
261 | ||
262 | static struct flagdescstruct gsyflagdesc[] = | |
263 | { | |
264 | { "WEAK", 0x0001 }, | |
265 | { "DEF", 0x0002 }, | |
266 | { "UNI", 0x0004 }, | |
267 | { "REL", 0x0008 }, | |
268 | { "COMM", 0x0010 }, | |
269 | { "VECEP", 0x0020 }, | |
270 | { "NORM", 0x0040 }, | |
271 | { NULL, 0 } | |
272 | }; | |
273 | #endif | |
274 | ||
275 | int gsd_type, gsd_size; | |
276 | asection *section; | |
277 | unsigned char *vms_rec; | |
278 | flagword new_flags, old_flags; | |
279 | char *name; | |
280 | asymbol *symbol; | |
281 | vms_symbol_entry *entry; | |
282 | unsigned long base_addr; | |
283 | unsigned long align_addr; | |
5f771d47 | 284 | static unsigned int psect_idx = 0; |
252b5132 RH |
285 | |
286 | #if VMS_DEBUG | |
287 | vms_debug (2, "GSD/EGSD (%d/%x)\n", objtype, objtype); | |
288 | #endif | |
289 | ||
290 | switch (objtype) | |
291 | { | |
dc810e39 AM |
292 | case EOBJ_S_C_EGSD: |
293 | PRIV(vms_rec) += 8; /* skip type, size, l_temp */ | |
294 | PRIV(rec_size) -= 8; | |
295 | break; | |
296 | case OBJ_S_C_GSD: | |
297 | PRIV(vms_rec) += 1; | |
298 | PRIV(rec_size) -= 1; | |
299 | break; | |
300 | default: | |
301 | return -1; | |
252b5132 RH |
302 | } |
303 | ||
304 | /* calculate base address for each section */ | |
305 | base_addr = 0L; | |
306 | ||
307 | abfd->symcount = 0; | |
308 | ||
309 | while (PRIV(rec_size) > 0) | |
310 | { | |
311 | vms_rec = PRIV(vms_rec); | |
312 | ||
313 | if (objtype == OBJ_S_C_GSD) | |
314 | { | |
315 | gsd_type = *vms_rec; | |
316 | } | |
317 | else | |
318 | { | |
319 | _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size); | |
320 | gsd_type += EVAX_OFFSET; | |
321 | } | |
322 | ||
323 | #if VMS_DEBUG | |
324 | vms_debug (3, "gsd_type %d\n", gsd_type); | |
325 | #endif | |
326 | ||
327 | switch (gsd_type) | |
328 | { | |
329 | case GSD_S_C_PSC: | |
330 | { | |
331 | /* | |
332 | * program section definition | |
333 | */ | |
334 | ||
335 | asection *old_section = 0; | |
336 | ||
337 | #if VMS_DEBUG | |
338 | vms_debug (4, "GSD_S_C_PSC\n"); | |
339 | #endif | |
340 | /* If this section isn't a bfd section. */ | |
341 | ||
342 | if (PRIV(is_vax) && (psect_idx < (abfd->section_count-1))) | |
343 | { | |
344 | /* check for temporary section from TIR record. */ | |
345 | ||
346 | if (psect_idx < PRIV(section_count)) | |
347 | old_section = PRIV(sections)[psect_idx]; | |
348 | else | |
349 | old_section = 0; | |
350 | } | |
351 | ||
352 | name = _bfd_vms_save_counted_string (vms_rec + 8); | |
353 | section = bfd_make_section (abfd, name); | |
354 | if (!section) | |
355 | { | |
e049a0de ILT |
356 | (*_bfd_error_handler) (_("bfd_make_section (%s) failed"), |
357 | name); | |
252b5132 RH |
358 | return -1; |
359 | } | |
360 | old_flags = bfd_getl16 (vms_rec + 2); | |
dc810e39 AM |
361 | section->_raw_size = bfd_getl32 (vms_rec + 4); /* allocation */ |
362 | new_flags = vms_secflag_by_name (abfd, vax_section_flags, name, | |
363 | section->_raw_size > 0); | |
252b5132 RH |
364 | if (old_flags & EGPS_S_V_REL) |
365 | new_flags |= SEC_RELOC; | |
366 | if (old_flags & GPS_S_M_OVR) | |
367 | new_flags |= SEC_IS_COMMON; | |
368 | if (!bfd_set_section_flags (abfd, section, new_flags)) | |
369 | { | |
e049a0de ILT |
370 | (*_bfd_error_handler) |
371 | (_("bfd_set_section_flags (%s, %x) failed"), | |
372 | name, new_flags); | |
252b5132 RH |
373 | return -1; |
374 | } | |
375 | section->alignment_power = vms_rec[1]; | |
376 | align_addr = (1 << section->alignment_power); | |
377 | if ((base_addr % align_addr) != 0) | |
378 | base_addr += (align_addr - (base_addr % align_addr)); | |
379 | section->vma = (bfd_vma)base_addr; | |
380 | base_addr += section->_raw_size; | |
381 | ||
382 | /* global section is common symbol */ | |
383 | ||
384 | if (old_flags & GPS_S_M_GBL) | |
385 | { | |
386 | entry = _bfd_vms_enter_symbol (abfd, name); | |
387 | if (entry == (vms_symbol_entry *)NULL) | |
388 | { | |
389 | bfd_set_error (bfd_error_no_memory); | |
390 | return -1; | |
391 | } | |
392 | symbol = entry->symbol; | |
393 | ||
394 | symbol->value = 0; | |
395 | symbol->section = section; | |
396 | symbol->flags = (BSF_GLOBAL|BSF_SECTION_SYM|BSF_OLD_COMMON); | |
397 | } | |
398 | ||
399 | /* copy saved contents if old_section set */ | |
400 | ||
401 | if (old_section != 0) | |
402 | { | |
403 | section->contents = old_section->contents; | |
404 | if (section->_raw_size < old_section->_raw_size) | |
405 | { | |
e049a0de ILT |
406 | (*_bfd_error_handler) |
407 | (_("Size mismatch section %s=%lx, %s=%lx"), | |
408 | old_section->name, | |
409 | (unsigned long) old_section->_raw_size, | |
410 | section->name, | |
411 | (unsigned long) section->_raw_size); | |
252b5132 RH |
412 | return -1; |
413 | } | |
414 | else if (section->_raw_size > old_section->_raw_size) | |
415 | { | |
416 | section->contents = ((unsigned char *) | |
dc810e39 AM |
417 | bfd_realloc (old_section->contents, |
418 | section->_raw_size)); | |
252b5132 RH |
419 | if (section->contents == NULL) |
420 | { | |
421 | bfd_set_error (bfd_error_no_memory); | |
422 | return -1; | |
423 | } | |
424 | } | |
425 | } | |
426 | else | |
427 | { | |
428 | section->contents = ((unsigned char *) | |
dc810e39 | 429 | bfd_malloc (section->_raw_size)); |
252b5132 RH |
430 | if (section->contents == NULL) |
431 | { | |
432 | bfd_set_error (bfd_error_no_memory); | |
433 | return -1; | |
434 | } | |
dc810e39 | 435 | memset (section->contents, 0, (size_t) section->_raw_size); |
252b5132 RH |
436 | } |
437 | section->_cooked_size = section->_raw_size; | |
438 | #if VMS_DEBUG | |
439 | vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ", | |
440 | section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); | |
441 | vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", | |
442 | section->_raw_size, section->vma, section->contents); | |
443 | #endif | |
444 | ||
445 | gsd_size = vms_rec[8] + 9; | |
446 | ||
447 | psect_idx++; | |
448 | } | |
449 | break; | |
450 | ||
451 | case GSD_S_C_EPM: | |
452 | case GSD_S_C_EPMW: | |
453 | #if VMS_DEBUG | |
454 | vms_debug(4, "gsd epm\n"); | |
455 | #endif | |
456 | /*FALLTHRU*/ | |
457 | case GSD_S_C_SYM: | |
458 | case GSD_S_C_SYMW: | |
459 | { | |
dc810e39 | 460 | int name_offset = 0, value_offset = 0; |
252b5132 RH |
461 | |
462 | /* | |
463 | * symbol specification (definition or reference) | |
464 | */ | |
465 | ||
466 | #if VMS_DEBUG | |
467 | vms_debug (4, "GSD_S_C_SYM(W)\n"); | |
468 | #endif | |
469 | old_flags = bfd_getl16 (vms_rec + 2); | |
470 | new_flags = BSF_NO_FLAGS; | |
471 | ||
472 | if (old_flags & GSY_S_M_WEAK) | |
473 | new_flags |= BSF_WEAK; | |
474 | ||
475 | switch (gsd_type) | |
476 | { | |
dc810e39 AM |
477 | case GSD_S_C_EPM: |
478 | name_offset = 11; | |
479 | value_offset = 5; | |
480 | new_flags |= BSF_FUNCTION; | |
481 | break; | |
482 | case GSD_S_C_EPMW: | |
483 | name_offset = 12; | |
484 | value_offset = 6; | |
485 | new_flags |= BSF_FUNCTION; | |
486 | break; | |
487 | case GSD_S_C_SYM: | |
488 | if (old_flags & GSY_S_M_DEF) /* symbol definition */ | |
489 | name_offset = 9; | |
490 | else | |
491 | name_offset = 4; | |
492 | value_offset = 5; | |
493 | break; | |
494 | case GSD_S_C_SYMW: | |
495 | if (old_flags & GSY_S_M_DEF) /* symbol definition */ | |
496 | name_offset = 10; | |
497 | else | |
498 | name_offset = 5; | |
499 | value_offset = 6; | |
500 | break; | |
252b5132 RH |
501 | } |
502 | ||
503 | /* save symbol in vms_symbol_table */ | |
504 | ||
505 | entry = _bfd_vms_enter_symbol (abfd, | |
506 | _bfd_vms_save_counted_string (vms_rec + name_offset)); | |
507 | if (entry == (vms_symbol_entry *)NULL) | |
508 | { | |
509 | bfd_set_error (bfd_error_no_memory); | |
510 | return -1; | |
511 | } | |
512 | symbol = entry->symbol; | |
513 | ||
514 | if (old_flags & GSY_S_M_DEF) /* symbol definition */ | |
515 | { | |
516 | int psect; | |
517 | ||
518 | symbol->value = bfd_getl32 (vms_rec+value_offset); | |
519 | if ((gsd_type == GSD_S_C_SYMW) | |
520 | || (gsd_type == GSD_S_C_EPMW)) | |
521 | psect = bfd_getl16 (vms_rec + value_offset - 2); | |
522 | else | |
523 | psect = vms_rec[value_offset-1]; | |
524 | ||
525 | symbol->section = (asection *)psect; | |
526 | #if VMS_DEBUG | |
527 | vms_debug(4, "gsd sym def #%d (%s, %d [%p], %04x=%s)\n", abfd->symcount, | |
528 | symbol->name, (int)symbol->section, symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); | |
529 | #endif | |
530 | } | |
531 | else /* symbol reference */ | |
532 | { | |
533 | symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); | |
534 | #if VMS_DEBUG | |
535 | vms_debug (4, "gsd sym ref #%d (%s, %s [%p], %04x=%s)\n", abfd->symcount, | |
536 | symbol->name, symbol->section->name, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); | |
537 | #endif | |
538 | } | |
539 | ||
540 | gsd_size = vms_rec[name_offset] + name_offset + 1; | |
541 | symbol->flags = new_flags; | |
542 | } | |
543 | ||
544 | break; | |
545 | ||
546 | case GSD_S_C_PRO: | |
547 | case GSD_S_C_PROW: | |
548 | #if VMS_DEBUG | |
549 | vms_debug(4, "gsd pro\n"); | |
550 | #endif | |
551 | break; | |
552 | case GSD_S_C_IDC: | |
553 | #if VMS_DEBUG | |
554 | vms_debug(4, "gsd idc\n"); | |
555 | #endif | |
556 | break; | |
557 | case GSD_S_C_ENV: | |
558 | #if VMS_DEBUG | |
559 | vms_debug(4, "gsd env\n"); | |
560 | #endif | |
561 | break; | |
562 | case GSD_S_C_LSY: | |
563 | #if VMS_DEBUG | |
564 | vms_debug(4, "gsd lsy\n"); | |
565 | #endif | |
566 | break; | |
567 | case GSD_S_C_LEPM: | |
568 | #if VMS_DEBUG | |
569 | vms_debug(4, "gsd lepm\n"); | |
570 | #endif | |
571 | break; | |
572 | case GSD_S_C_LPRO: | |
573 | #if VMS_DEBUG | |
574 | vms_debug(4, "gsd lpro\n"); | |
575 | #endif | |
576 | break; | |
577 | case GSD_S_C_SPSC: | |
578 | #if VMS_DEBUG | |
579 | vms_debug(4, "gsd spsc\n"); | |
580 | #endif | |
581 | break; | |
582 | case GSD_S_C_SYMV: | |
583 | #if VMS_DEBUG | |
584 | vms_debug(4, "gsd symv\n"); | |
585 | #endif | |
586 | break; | |
587 | case GSD_S_C_EPMV: | |
588 | #if VMS_DEBUG | |
589 | vms_debug(4, "gsd epmv\n"); | |
590 | #endif | |
591 | break; | |
592 | case GSD_S_C_PROV: | |
593 | #if VMS_DEBUG | |
594 | vms_debug(4, "gsd prov\n"); | |
595 | #endif | |
596 | break; | |
597 | ||
598 | case EGSD_S_C_PSC + EVAX_OFFSET: | |
599 | { | |
600 | /* program section definition */ | |
601 | ||
602 | name = _bfd_vms_save_counted_string (vms_rec+12); | |
603 | section = bfd_make_section (abfd, name); | |
604 | if (!section) | |
605 | return -1; | |
606 | old_flags = bfd_getl16 (vms_rec + 6); | |
607 | section->_raw_size = bfd_getl32 (vms_rec + 8); /* allocation */ | |
dc810e39 AM |
608 | new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, |
609 | section->_raw_size > 0); | |
252b5132 RH |
610 | if (old_flags & EGPS_S_V_REL) |
611 | new_flags |= SEC_RELOC; | |
612 | if (!bfd_set_section_flags (abfd, section, new_flags)) | |
613 | return -1; | |
614 | section->alignment_power = vms_rec[4]; | |
615 | align_addr = (1 << section->alignment_power); | |
616 | if ((base_addr % align_addr) != 0) | |
617 | base_addr += (align_addr - (base_addr % align_addr)); | |
618 | section->vma = (bfd_vma)base_addr; | |
619 | base_addr += section->_raw_size; | |
620 | section->contents = ((unsigned char *) | |
621 | bfd_malloc (section->_raw_size)); | |
622 | if (section->contents == NULL) | |
623 | return -1; | |
624 | memset (section->contents, 0, (size_t) section->_raw_size); | |
625 | section->_cooked_size = section->_raw_size; | |
626 | #if VMS_DEBUG | |
627 | vms_debug(4, "egsd psc %d (%s, flags %04x=%s) ", | |
628 | section->index, name, old_flags, flag2str(gpsflagdesc, old_flags)); | |
629 | vms_debug(4, "%d bytes at 0x%08lx (mem %p)\n", | |
630 | section->_raw_size, section->vma, section->contents); | |
631 | #endif | |
632 | } | |
633 | break; | |
634 | ||
635 | case EGSD_S_C_SYM + EVAX_OFFSET: | |
636 | { | |
637 | /* symbol specification (definition or reference) */ | |
638 | ||
3f3c5c34 | 639 | symbol = bfd_make_empty_symbol (abfd); |
252b5132 RH |
640 | if (symbol == 0) |
641 | return -1; | |
642 | ||
643 | old_flags = bfd_getl16 (vms_rec + 6); | |
644 | new_flags = BSF_NO_FLAGS; | |
645 | ||
646 | if (old_flags & EGSY_S_V_WEAK) | |
647 | new_flags |= BSF_WEAK; | |
648 | ||
649 | if (vms_rec[6] & EGSY_S_V_DEF) /* symbol definition */ | |
650 | { | |
651 | symbol->name = | |
652 | _bfd_vms_save_counted_string (vms_rec+32); | |
653 | if (old_flags & EGSY_S_V_NORM) | |
654 | { /* proc def */ | |
655 | new_flags |= BSF_FUNCTION; | |
656 | } | |
657 | symbol->value = bfd_getl64 (vms_rec+8); | |
558e161f | 658 | symbol->section = (asection *) ((unsigned long) bfd_getl32 (vms_rec+28)); |
252b5132 RH |
659 | #if VMS_DEBUG |
660 | vms_debug(4, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount, | |
661 | symbol->name, (int)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); | |
662 | #endif | |
663 | } | |
664 | else /* symbol reference */ | |
665 | { | |
666 | symbol->name = | |
667 | _bfd_vms_save_counted_string (vms_rec+8); | |
668 | #if VMS_DEBUG | |
669 | vms_debug(4, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, | |
670 | symbol->name, old_flags, flag2str(gsyflagdesc, old_flags)); | |
671 | #endif | |
672 | symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); | |
673 | } | |
674 | ||
675 | symbol->flags = new_flags; | |
676 | ||
677 | /* save symbol in vms_symbol_table */ | |
678 | ||
679 | entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV(vms_symbol_table), symbol->name, true, false); | |
680 | if (entry == (vms_symbol_entry *)NULL) | |
681 | { | |
682 | bfd_set_error (bfd_error_no_memory); | |
683 | return -1; | |
684 | } | |
685 | if (entry->symbol != (asymbol *)NULL) | |
686 | { /* FIXME ?, DEC C generates this */ | |
687 | #if VMS_DEBUG | |
688 | vms_debug(4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name); | |
689 | #endif | |
690 | } | |
691 | else | |
692 | { | |
693 | entry->symbol = symbol; | |
694 | PRIV(gsd_sym_count)++; | |
695 | abfd->symcount++; | |
696 | } | |
697 | } | |
698 | break; | |
699 | ||
700 | case EGSD_S_C_IDC + EVAX_OFFSET: | |
701 | break; | |
702 | ||
703 | default: | |
704 | (*_bfd_error_handler) (_("unknown gsd/egsd subtype %d"), gsd_type); | |
705 | bfd_set_error (bfd_error_bad_value); | |
706 | return -1; | |
707 | ||
708 | } /* switch */ | |
709 | ||
710 | PRIV(rec_size) -= gsd_size; | |
711 | PRIV(vms_rec) += gsd_size; | |
712 | ||
713 | } /* while (recsize > 0) */ | |
714 | ||
715 | if (abfd->symcount > 0) | |
716 | abfd->flags |= HAS_SYMS; | |
717 | ||
718 | return 0; | |
719 | } | |
720 | ||
721 | /*-----------------------------------------------------------------------------*/ | |
722 | /* output routines */ | |
723 | ||
724 | /* Write section and symbol directory of bfd abfd */ | |
725 | ||
726 | int | |
727 | _bfd_vms_write_gsd (abfd, objtype) | |
728 | bfd *abfd; | |
5f771d47 | 729 | int objtype ATTRIBUTE_UNUSED; |
252b5132 RH |
730 | { |
731 | asection *section; | |
732 | asymbol *symbol; | |
5f771d47 | 733 | unsigned int symnum; |
252b5132 RH |
734 | int last_index = -1; |
735 | char dummy_name[10]; | |
736 | char *sname; | |
737 | flagword new_flags, old_flags; | |
252b5132 RH |
738 | |
739 | #if VMS_DEBUG | |
740 | vms_debug (2, "vms_write_gsd (%p, %d)\n", abfd, objtype); | |
741 | #endif | |
742 | ||
743 | /* output sections */ | |
744 | ||
745 | section = abfd->sections; | |
746 | #if VMS_DEBUG | |
747 | vms_debug (3, "%d sections found\n", abfd->section_count); | |
748 | #endif | |
749 | ||
750 | /* egsd is quadword aligned */ | |
751 | ||
752 | _bfd_vms_output_alignment (abfd, 8); | |
753 | ||
754 | _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); | |
755 | _bfd_vms_output_long (abfd, 0); | |
756 | _bfd_vms_output_push (abfd); /* prepare output for subrecords */ | |
757 | ||
758 | while (section != 0) | |
759 | { | |
760 | #if VMS_DEBUG | |
761 | vms_debug (3, "Section #%d %s, %d bytes\n", section->index, section->name, (int)section->_raw_size); | |
762 | #endif | |
763 | ||
764 | /* 13 bytes egsd, max 31 chars name -> should be 44 bytes */ | |
765 | if (_bfd_vms_output_check (abfd, 64) < 0) | |
766 | { | |
767 | _bfd_vms_output_pop (abfd); | |
768 | _bfd_vms_output_end (abfd); | |
769 | _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); | |
770 | _bfd_vms_output_long (abfd, 0); | |
771 | _bfd_vms_output_push (abfd); /* prepare output for subrecords */ | |
772 | } | |
773 | ||
774 | /* Create dummy sections to keep consecutive indices */ | |
775 | ||
776 | while (section->index - last_index > 1) | |
777 | { | |
778 | #if VMS_DEBUG | |
779 | vms_debug (3, "index %d, last %d\n", section->index, last_index); | |
780 | #endif | |
781 | _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1); | |
782 | _bfd_vms_output_short (abfd, 0); | |
783 | _bfd_vms_output_short (abfd, 0); | |
784 | _bfd_vms_output_long (abfd, 0); | |
785 | sprintf (dummy_name, ".DUMMY%02d", last_index); | |
786 | _bfd_vms_output_counted (abfd, dummy_name); | |
787 | _bfd_vms_output_flush (abfd); | |
788 | last_index++; | |
789 | } | |
790 | ||
791 | /* Don't know if this is neccesary for the linker but for now it keeps | |
792 | vms_slurp_gsd happy */ | |
793 | ||
794 | sname = (char *)section->name; | |
795 | if (*sname == '.') | |
796 | { | |
797 | sname++; | |
798 | if ((*sname == 't') && (strcmp (sname, "text") == 0)) | |
799 | sname = PRIV(is_vax)?VAX_CODE_NAME:EVAX_CODE_NAME; | |
800 | else if ((*sname == 'd') && (strcmp (sname, "data") == 0)) | |
801 | sname = PRIV(is_vax)?VAX_DATA_NAME:EVAX_DATA_NAME; | |
802 | else if ((*sname == 'b') && (strcmp (sname, "bss") == 0)) | |
803 | sname = EVAX_BSS_NAME; | |
804 | else if ((*sname == 'l') && (strcmp (sname, "link") == 0)) | |
805 | sname = EVAX_LINK_NAME; | |
806 | else if ((*sname == 'r') && (strcmp (sname, "rdata") == 0)) | |
807 | sname = EVAX_READONLY_NAME; | |
808 | else if ((*sname == 'l') && (strcmp (sname, "literal") == 0)) | |
809 | sname = EVAX_LITERAL_NAME; | |
810 | else if ((*sname == 'c') && (strcmp (sname, "comm") == 0)) | |
811 | sname = EVAX_COMMON_NAME; | |
812 | else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0)) | |
813 | sname = EVAX_LOCAL_NAME; | |
814 | } | |
815 | else | |
816 | sname = _bfd_vms_length_hash_symbol (abfd, sname, EOBJ_S_C_SECSIZ); | |
817 | ||
818 | _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1); | |
819 | _bfd_vms_output_short (abfd, section->alignment_power & 0xff); | |
820 | if (bfd_is_com_section (section)) | |
821 | { | |
822 | new_flags = (EGPS_S_V_OVR|EGPS_S_V_REL|EGPS_S_V_GBL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD|EGPS_S_V_COM); | |
823 | } | |
824 | else | |
825 | { | |
dc810e39 AM |
826 | new_flags = vms_esecflag_by_name (evax_section_flags, sname, |
827 | section->_raw_size > 0); | |
252b5132 RH |
828 | } |
829 | _bfd_vms_output_short (abfd, new_flags); | |
dc810e39 | 830 | _bfd_vms_output_long (abfd, (unsigned long) section->_raw_size); |
252b5132 RH |
831 | _bfd_vms_output_counted (abfd, sname); |
832 | _bfd_vms_output_flush (abfd); | |
833 | ||
834 | last_index = section->index; | |
835 | section = section->next; | |
836 | } | |
837 | ||
838 | /* output symbols */ | |
839 | ||
840 | #if VMS_DEBUG | |
841 | vms_debug (3, "%d symbols found\n", abfd->symcount); | |
842 | #endif | |
843 | ||
844 | bfd_set_start_address (abfd, (bfd_vma)-1); | |
845 | ||
846 | for (symnum = 0; symnum < abfd->symcount; symnum++) | |
847 | { | |
dc810e39 | 848 | char *hash; |
252b5132 RH |
849 | |
850 | symbol = abfd->outsymbols[symnum]; | |
851 | if (*(symbol->name) == '_') | |
852 | { | |
853 | if (strcmp (symbol->name, "__main") == 0) | |
854 | bfd_set_start_address (abfd, (bfd_vma)symbol->value); | |
855 | } | |
856 | old_flags = symbol->flags; | |
857 | ||
858 | if (old_flags & BSF_FILE) | |
859 | continue; | |
860 | ||
861 | if (((old_flags & (BSF_GLOBAL|BSF_WEAK)) == 0) /* not xdef */ | |
862 | && (!bfd_is_und_section (symbol->section))) /* and not xref */ | |
863 | continue; /* dont output */ | |
864 | ||
865 | /* 13 bytes egsd, max 64 chars name -> should be 77 bytes */ | |
866 | ||
867 | if (_bfd_vms_output_check (abfd, 80) < 0) | |
868 | { | |
869 | _bfd_vms_output_pop (abfd); | |
870 | _bfd_vms_output_end (abfd); | |
871 | _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); | |
872 | _bfd_vms_output_long (abfd, 0); | |
873 | _bfd_vms_output_push (abfd); /* prepare output for subrecords */ | |
874 | } | |
875 | ||
876 | _bfd_vms_output_begin (abfd, EGSD_S_C_SYM, -1); | |
877 | ||
878 | _bfd_vms_output_short (abfd, 0); /* data type, alignment */ | |
879 | ||
880 | new_flags = 0; | |
881 | ||
882 | if (old_flags & BSF_WEAK) | |
883 | new_flags |= EGSY_S_V_WEAK; | |
884 | if (bfd_is_com_section (symbol->section)) /* .comm */ | |
885 | new_flags |= (EGSY_S_V_WEAK|EGSY_S_V_COMM); | |
886 | ||
887 | if (old_flags & BSF_FUNCTION) | |
888 | { | |
889 | new_flags |= EGSY_S_V_NORM; | |
890 | new_flags |= EGSY_S_V_REL; | |
891 | } | |
892 | if (old_flags & (BSF_GLOBAL|BSF_WEAK)) | |
893 | { | |
894 | new_flags |= EGSY_S_V_DEF; | |
895 | if (!bfd_is_abs_section (symbol->section)) | |
896 | new_flags |= EGSY_S_V_REL; | |
897 | } | |
898 | _bfd_vms_output_short (abfd, new_flags); | |
899 | ||
dc810e39 | 900 | if (old_flags & (BSF_GLOBAL | BSF_WEAK)) /* symbol definition */ |
252b5132 | 901 | { |
dc810e39 AM |
902 | uquad code_address = 0; |
903 | unsigned long ca_psindx = 0; | |
904 | unsigned long psindx; | |
905 | ||
252b5132 RH |
906 | if (old_flags & BSF_FUNCTION) |
907 | { | |
dc810e39 AM |
908 | code_address = ((asymbol *) (symbol->udata.p))->value; |
909 | ca_psindx = ((asymbol *) (symbol->udata.p))->section->index; | |
252b5132 | 910 | } |
dc810e39 AM |
911 | psindx = symbol->section->index; |
912 | ||
913 | _bfd_vms_output_quad (abfd, symbol->value); | |
914 | _bfd_vms_output_quad (abfd, code_address); | |
915 | _bfd_vms_output_long (abfd, ca_psindx); | |
916 | _bfd_vms_output_long (abfd, psindx); | |
252b5132 | 917 | } |
dc810e39 AM |
918 | hash = _bfd_vms_length_hash_symbol (abfd, symbol->name, EOBJ_S_C_SYMSIZ); |
919 | _bfd_vms_output_counted (abfd, hash); | |
252b5132 RH |
920 | |
921 | _bfd_vms_output_flush (abfd); | |
922 | ||
923 | } | |
924 | ||
925 | _bfd_vms_output_alignment (abfd, 8); | |
926 | _bfd_vms_output_pop (abfd); | |
558e161f | 927 | _bfd_vms_output_end (abfd); |
252b5132 RH |
928 | |
929 | return 0; | |
930 | } |