simple-object-xcoff.c revision 1.1 1 1.1 christos /* simple-object-coff.c -- routines to manipulate XCOFF object files.
2 1.1 christos Copyright 2013 Free Software Foundation, Inc.
3 1.1 christos Written by Ian Lance Taylor, Google and David Edelsohn, IBM.
4 1.1 christos
5 1.1 christos This program is free software; you can redistribute it and/or modify it
6 1.1 christos under the terms of the GNU General Public License as published by the
7 1.1 christos Free Software Foundation; either version 2, or (at your option) any
8 1.1 christos later version.
9 1.1 christos
10 1.1 christos This program is distributed in the hope that it will be useful,
11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 1.1 christos GNU General Public License for more details.
14 1.1 christos
15 1.1 christos You should have received a copy of the GNU General Public License
16 1.1 christos along with this program; if not, write to the Free Software
17 1.1 christos Foundation, 51 Franklin Street - Fifth Floor,
18 1.1 christos Boston, MA 02110-1301, USA. */
19 1.1 christos
20 1.1 christos #include "config.h"
21 1.1 christos #include "libiberty.h"
22 1.1 christos #include "simple-object.h"
23 1.1 christos
24 1.1 christos #include <errno.h>
25 1.1 christos #include <stddef.h>
26 1.1 christos
27 1.1 christos #ifdef HAVE_STDLIB_H
28 1.1 christos #include <stdlib.h>
29 1.1 christos #endif
30 1.1 christos
31 1.1 christos #ifdef HAVE_STDINT_H
32 1.1 christos #include <stdint.h>
33 1.1 christos #endif
34 1.1 christos
35 1.1 christos #ifdef HAVE_STRING_H
36 1.1 christos #include <string.h>
37 1.1 christos #endif
38 1.1 christos
39 1.1 christos #ifdef HAVE_INTTYPES_H
40 1.1 christos #include <inttypes.h>
41 1.1 christos #endif
42 1.1 christos
43 1.1 christos #include "simple-object-common.h"
44 1.1 christos
45 1.1 christos /* XCOFF structures and constants. */
46 1.1 christos
47 1.1 christos /* XCOFF file header. */
48 1.1 christos
49 1.1 christos struct external_filehdr
50 1.1 christos {
51 1.1 christos unsigned char f_magic[2]; /* magic number */
52 1.1 christos unsigned char f_nscns[2]; /* number of sections */
53 1.1 christos unsigned char f_timdat[4]; /* time & date stamp */
54 1.1 christos union
55 1.1 christos {
56 1.1 christos struct
57 1.1 christos {
58 1.1 christos unsigned char f_symptr[4]; /* file pointer to symtab */
59 1.1 christos unsigned char f_nsyms[4]; /* number of symtab entries */
60 1.1 christos unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
61 1.1 christos unsigned char f_flags[2]; /* flags */
62 1.1 christos } xcoff32;
63 1.1 christos struct
64 1.1 christos {
65 1.1 christos unsigned char f_symptr[8]; /* file pointer to symtab */
66 1.1 christos unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
67 1.1 christos unsigned char f_flags[2]; /* flags */
68 1.1 christos unsigned char f_nsyms[4]; /* number of symtab entries */
69 1.1 christos } xcoff64;
70 1.1 christos } u;
71 1.1 christos };
72 1.1 christos
73 1.1 christos /* Bits for filehdr f_flags field. */
74 1.1 christos
75 1.1 christos #define F_EXEC (0x0002)
76 1.1 christos
77 1.1 christos /* The known values of f_magic in an XCOFF file header. */
78 1.1 christos
79 1.1 christos #define U802WRMAGIC 0730 /* Writeable text segments. */
80 1.1 christos #define U802ROMAGIC 0735 /* Readonly sharable text segments. */
81 1.1 christos #define U802TOCMAGIC 0737 /* Readonly text segments and TOC. */
82 1.1 christos #define U803XTOCMAGIC 0757 /* Aix 4.3 64-bit XCOFF. */
83 1.1 christos #define U64_TOCMAGIC 0767 /* AIX 5+ 64-bit XCOFF. */
84 1.1 christos
85 1.1 christos /* XCOFF section header. */
86 1.1 christos
87 1.1 christos struct external_scnhdr
88 1.1 christos {
89 1.1 christos unsigned char s_name[8]; /* section name */
90 1.1 christos union
91 1.1 christos {
92 1.1 christos struct
93 1.1 christos {
94 1.1 christos unsigned char s_paddr[4]; /* physical address, aliased s_nlib */
95 1.1 christos unsigned char s_vaddr[4]; /* virtual address */
96 1.1 christos unsigned char s_size[4]; /* section size */
97 1.1 christos unsigned char s_scnptr[4]; /* file ptr to raw data for section */
98 1.1 christos unsigned char s_relptr[4]; /* file ptr to relocation */
99 1.1 christos unsigned char s_lnnoptr[4]; /* file ptr to line numbers */
100 1.1 christos unsigned char s_nreloc[2]; /* number of relocation entries */
101 1.1 christos unsigned char s_nlnno[2]; /* number of line number entries */
102 1.1 christos unsigned char s_flags[4]; /* flags */
103 1.1 christos } xcoff32;
104 1.1 christos struct
105 1.1 christos {
106 1.1 christos unsigned char s_paddr[8]; /* physical address, aliased s_nlib */
107 1.1 christos unsigned char s_vaddr[8]; /* virtual address */
108 1.1 christos unsigned char s_size[8]; /* section size */
109 1.1 christos unsigned char s_scnptr[8]; /* file ptr to raw data for section */
110 1.1 christos unsigned char s_relptr[8]; /* file ptr to relocation */
111 1.1 christos unsigned char s_lnnoptr[8]; /* file ptr to line numbers */
112 1.1 christos unsigned char s_nreloc[4]; /* number of relocation entries */
113 1.1 christos unsigned char s_nlnno[4]; /* number of line number entries */
114 1.1 christos unsigned char s_flags[4]; /* flags */
115 1.1 christos } xcoff64;
116 1.1 christos } u;
117 1.1 christos };
118 1.1 christos
119 1.1 christos #define SCNHSZ32 (40)
120 1.1 christos #define SCNHSZ64 (68)
121 1.1 christos
122 1.1 christos /* The length of the s_name field in struct external_scnhdr. */
123 1.1 christos
124 1.1 christos #define SCNNMLEN (8)
125 1.1 christos
126 1.1 christos /* Bits for scnhdr s_flags field. */
127 1.1 christos
128 1.1 christos #define STYP_DATA 0x40
129 1.1 christos
130 1.1 christos /* XCOFF symbol table entry. */
131 1.1 christos
132 1.1 christos
133 1.1 christos #define N_SYMNMLEN (8) /* # characters in a symbol name */
134 1.1 christos
135 1.1 christos /* The format of an XCOFF symbol-table entry. */
136 1.1 christos struct external_syment
137 1.1 christos {
138 1.1 christos union {
139 1.1 christos struct {
140 1.1 christos union {
141 1.1 christos /* The name of the symbol. There is an implicit null character
142 1.1 christos after the end of the array. */
143 1.1 christos char n_name[N_SYMNMLEN];
144 1.1 christos struct {
145 1.1 christos /* If n_zeroes is zero, n_offset is the offset the name from
146 1.1 christos the start of the string table. */
147 1.1 christos unsigned char n_zeroes[4];
148 1.1 christos unsigned char n_offset[4];
149 1.1 christos } n;
150 1.1 christos } n;
151 1.1 christos
152 1.1 christos /* The symbol's value. */
153 1.1 christos unsigned char n_value[4];
154 1.1 christos } xcoff32;
155 1.1 christos struct {
156 1.1 christos /* The symbol's value. */
157 1.1 christos unsigned char n_value[8];
158 1.1 christos
159 1.1 christos /* The offset of the symbol from the start of the string table. */
160 1.1 christos unsigned char n_offset[4];
161 1.1 christos } xcoff64;
162 1.1 christos } u;
163 1.1 christos
164 1.1 christos /* The number of the section to which this symbol belongs. */
165 1.1 christos unsigned char n_scnum[2];
166 1.1 christos
167 1.1 christos /* The type of symbol. (It can be interpreted as an n_lang
168 1.1 christos and an n_cpu byte, but we don't care about that here.) */
169 1.1 christos unsigned char n_type[2];
170 1.1 christos
171 1.1 christos /* The class of symbol (a C_* value). */
172 1.1 christos unsigned char n_sclass[1];
173 1.1 christos
174 1.1 christos /* The number of auxiliary symbols attached to this entry. */
175 1.1 christos unsigned char n_numaux[1];
176 1.1 christos };
177 1.1 christos
178 1.1 christos #define SYMESZ (18)
179 1.1 christos
180 1.1 christos /* Length allowed for filename in aux sym format 4. */
181 1.1 christos
182 1.1 christos #define FILNMLEN (14)
183 1.1 christos
184 1.1 christos /* Omits x_sym and other unused variants. */
185 1.1 christos
186 1.1 christos union external_auxent
187 1.1 christos {
188 1.1 christos /* Aux sym format 4: file. */
189 1.1 christos union
190 1.1 christos {
191 1.1 christos char x_fname[FILNMLEN];
192 1.1 christos struct
193 1.1 christos {
194 1.1 christos unsigned char x_zeroes[4];
195 1.1 christos unsigned char x_offset[4];
196 1.1 christos unsigned char x_pad[FILNMLEN-8];
197 1.1 christos unsigned char x_ftype;
198 1.1 christos } _x;
199 1.1 christos } x_file;
200 1.1 christos /* Aux sym format 5: section. */
201 1.1 christos struct
202 1.1 christos {
203 1.1 christos unsigned char x_scnlen[4]; /* section length */
204 1.1 christos unsigned char x_nreloc[2]; /* # relocation entries */
205 1.1 christos unsigned char x_nlinno[2]; /* # line numbers */
206 1.1 christos } x_scn;
207 1.1 christos /* CSECT auxiliary entry. */
208 1.1 christos union
209 1.1 christos {
210 1.1 christos struct
211 1.1 christos {
212 1.1 christos struct
213 1.1 christos {
214 1.1 christos unsigned char x_scnlen[4]; /* csect length */
215 1.1 christos unsigned char x_parmhash[4]; /* parm type hash index */
216 1.1 christos unsigned char x_snhash[2]; /* sect num with parm hash */
217 1.1 christos unsigned char x_smtyp; /* symbol align and type */
218 1.1 christos unsigned char x_smclas; /* storage mapping class */
219 1.1 christos unsigned char x_stab; /* dbx stab info index */
220 1.1 christos unsigned char x_snstab[2]; /* sect num with dbx stab */
221 1.1 christos } x_csect;
222 1.1 christos } xcoff32;
223 1.1 christos struct
224 1.1 christos {
225 1.1 christos struct
226 1.1 christos {
227 1.1 christos unsigned char x_scnlen_lo[4]; /* csect length */
228 1.1 christos unsigned char x_parmhash[4]; /* parm type hash index */
229 1.1 christos unsigned char x_snhash[2]; /* sect num with parm hash */
230 1.1 christos unsigned char x_smtyp; /* symbol align and type */
231 1.1 christos unsigned char x_smclas; /* storage mapping class */
232 1.1 christos unsigned char x_scnlen_hi[4];
233 1.1 christos unsigned char pad;
234 1.1 christos unsigned char x_auxtype;
235 1.1 christos } x_csect;
236 1.1 christos } xcoff64;
237 1.1 christos } u;
238 1.1 christos /* SECTION/DWARF auxiliary entry. */
239 1.1 christos struct
240 1.1 christos {
241 1.1 christos unsigned char x_scnlen[4]; /* section length */
242 1.1 christos unsigned char pad1[4];
243 1.1 christos unsigned char x_nreloc[4]; /* number RLDs */
244 1.1 christos } x_sect;
245 1.1 christos };
246 1.1 christos
247 1.1 christos /* Symbol-related constants. */
248 1.1 christos
249 1.1 christos #define N_DEBUG (-2)
250 1.1 christos #define IMAGE_SYM_TYPE_NULL (0)
251 1.1 christos #define IMAGE_SYM_DTYPE_NULL (0)
252 1.1 christos #define IMAGE_SYM_CLASS_STATIC (3)
253 1.1 christos #define IMAGE_SYM_CLASS_FILE (103)
254 1.1 christos
255 1.1 christos #define IMAGE_SYM_TYPE \
256 1.1 christos ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
257 1.1 christos
258 1.1 christos #define C_STAT (3)
259 1.1 christos #define C_FILE (103)
260 1.1 christos
261 1.1 christos /* Private data for an simple_object_read. */
262 1.1 christos
263 1.1 christos struct simple_object_xcoff_read
264 1.1 christos {
265 1.1 christos /* Magic number. */
266 1.1 christos unsigned short magic;
267 1.1 christos /* Number of sections. */
268 1.1 christos unsigned short nscns;
269 1.1 christos /* File offset of symbol table. */
270 1.1 christos off_t symptr;
271 1.1 christos /* Number of symbol table entries. */
272 1.1 christos unsigned int nsyms;
273 1.1 christos /* Flags. */
274 1.1 christos unsigned short flags;
275 1.1 christos /* Offset of section headers in file. */
276 1.1 christos off_t scnhdr_offset;
277 1.1 christos };
278 1.1 christos
279 1.1 christos /* Private data for an simple_object_attributes. */
280 1.1 christos
281 1.1 christos struct simple_object_xcoff_attributes
282 1.1 christos {
283 1.1 christos /* Magic number. */
284 1.1 christos unsigned short magic;
285 1.1 christos /* Flags. */
286 1.1 christos unsigned short flags;
287 1.1 christos };
288 1.1 christos
289 1.1 christos /* See if we have a XCOFF file. */
290 1.1 christos
291 1.1 christos static void *
292 1.1 christos simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
293 1.1 christos int descriptor, off_t offset,
294 1.1 christos const char *segment_name ATTRIBUTE_UNUSED,
295 1.1 christos const char **errmsg, int *err)
296 1.1 christos {
297 1.1 christos unsigned short magic;
298 1.1 christos unsigned short (*fetch_16) (const unsigned char *);
299 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
300 1.1 christos ulong_type (*fetch_64) (const unsigned char *);
301 1.1 christos unsigned char hdrbuf[sizeof (struct external_filehdr)];
302 1.1 christos struct simple_object_xcoff_read *ocr;
303 1.1 christos int u64;
304 1.1 christos
305 1.1 christos magic = simple_object_fetch_big_16 (header);
306 1.1 christos
307 1.1 christos if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
308 1.1 christos {
309 1.1 christos *errmsg = NULL;
310 1.1 christos *err = 0;
311 1.1 christos return NULL;
312 1.1 christos }
313 1.1 christos
314 1.1 christos fetch_16 = simple_object_fetch_big_16;
315 1.1 christos fetch_32 = simple_object_fetch_big_32;
316 1.1 christos fetch_64 = simple_object_fetch_big_64;
317 1.1 christos
318 1.1 christos if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
319 1.1 christos errmsg, err))
320 1.1 christos return NULL;
321 1.1 christos
322 1.1 christos u64 = magic == U64_TOCMAGIC;
323 1.1 christos
324 1.1 christos ocr = XNEW (struct simple_object_xcoff_read);
325 1.1 christos ocr->magic = magic;
326 1.1 christos ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
327 1.1 christos if (u64)
328 1.1 christos {
329 1.1 christos ocr->symptr = fetch_64 (hdrbuf
330 1.1 christos + offsetof (struct external_filehdr,
331 1.1 christos u.xcoff64.f_symptr));
332 1.1 christos ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
333 1.1 christos u.xcoff64.f_nsyms));
334 1.1 christos ocr->scnhdr_offset = (sizeof (struct external_filehdr)
335 1.1 christos + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
336 1.1 christos u.xcoff64.f_opthdr)));
337 1.1 christos
338 1.1 christos }
339 1.1 christos else
340 1.1 christos {
341 1.1 christos ocr->symptr = fetch_32 (hdrbuf
342 1.1 christos + offsetof (struct external_filehdr,
343 1.1 christos u.xcoff32.f_symptr));
344 1.1 christos ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
345 1.1 christos u.xcoff32.f_nsyms));
346 1.1 christos ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
347 1.1 christos + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
348 1.1 christos u.xcoff32.f_opthdr)));
349 1.1 christos
350 1.1 christos }
351 1.1 christos
352 1.1 christos return (void *) ocr;
353 1.1 christos }
354 1.1 christos
355 1.1 christos /* Read the string table in a XCOFF file. */
356 1.1 christos
357 1.1 christos static char *
358 1.1 christos simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
359 1.1 christos const char **errmsg, int *err)
360 1.1 christos {
361 1.1 christos struct simple_object_xcoff_read *ocr =
362 1.1 christos (struct simple_object_xcoff_read *) sobj->data;
363 1.1 christos off_t strtab_offset;
364 1.1 christos unsigned char strsizebuf[4];
365 1.1 christos size_t strsize;
366 1.1 christos char *strtab;
367 1.1 christos
368 1.1 christos strtab_offset = sobj->offset + ocr->symptr
369 1.1 christos + ocr->nsyms * SYMESZ;
370 1.1 christos if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
371 1.1 christos strsizebuf, 4, errmsg, err))
372 1.1 christos return NULL;
373 1.1 christos strsize = simple_object_fetch_big_32 (strsizebuf);
374 1.1 christos strtab = XNEWVEC (char, strsize);
375 1.1 christos if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
376 1.1 christos (unsigned char *) strtab, strsize, errmsg,
377 1.1 christos err))
378 1.1 christos {
379 1.1 christos XDELETEVEC (strtab);
380 1.1 christos return NULL;
381 1.1 christos }
382 1.1 christos *strtab_size = strsize;
383 1.1 christos return strtab;
384 1.1 christos }
385 1.1 christos
386 1.1 christos /* Find all sections in a XCOFF file. */
387 1.1 christos
388 1.1 christos static const char *
389 1.1 christos simple_object_xcoff_find_sections (simple_object_read *sobj,
390 1.1 christos int (*pfn) (void *, const char *,
391 1.1 christos off_t offset, off_t length),
392 1.1 christos void *data,
393 1.1 christos int *err)
394 1.1 christos {
395 1.1 christos struct simple_object_xcoff_read *ocr =
396 1.1 christos (struct simple_object_xcoff_read *) sobj->data;
397 1.1 christos int u64 = ocr->magic == U64_TOCMAGIC;
398 1.1 christos size_t scnhdr_size;
399 1.1 christos unsigned char *scnbuf;
400 1.1 christos const char *errmsg;
401 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
402 1.1 christos ulong_type (*fetch_64) (const unsigned char *);
403 1.1 christos unsigned int nscns;
404 1.1 christos char *strtab;
405 1.1 christos size_t strtab_size;
406 1.1 christos unsigned int i;
407 1.1 christos
408 1.1 christos scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
409 1.1 christos scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
410 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
411 1.1 christos sobj->offset + ocr->scnhdr_offset,
412 1.1 christos scnbuf, scnhdr_size * ocr->nscns, &errmsg,
413 1.1 christos err))
414 1.1 christos {
415 1.1 christos XDELETEVEC (scnbuf);
416 1.1 christos return errmsg;
417 1.1 christos }
418 1.1 christos
419 1.1 christos fetch_32 = simple_object_fetch_big_32;
420 1.1 christos fetch_64 = simple_object_fetch_big_64;
421 1.1 christos
422 1.1 christos nscns = ocr->nscns;
423 1.1 christos strtab = NULL;
424 1.1 christos strtab_size = 0;
425 1.1 christos for (i = 0; i < nscns; ++i)
426 1.1 christos {
427 1.1 christos unsigned char *scnhdr;
428 1.1 christos unsigned char *scnname;
429 1.1 christos char namebuf[SCNNMLEN + 1];
430 1.1 christos char *name;
431 1.1 christos off_t scnptr;
432 1.1 christos unsigned int size;
433 1.1 christos
434 1.1 christos scnhdr = scnbuf + i * scnhdr_size;
435 1.1 christos scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
436 1.1 christos memcpy (namebuf, scnname, SCNNMLEN);
437 1.1 christos namebuf[SCNNMLEN] = '\0';
438 1.1 christos name = &namebuf[0];
439 1.1 christos if (namebuf[0] == '/')
440 1.1 christos {
441 1.1 christos size_t strindex;
442 1.1 christos char *end;
443 1.1 christos
444 1.1 christos strindex = strtol (namebuf + 1, &end, 10);
445 1.1 christos if (*end == '\0')
446 1.1 christos {
447 1.1 christos /* The real section name is found in the string
448 1.1 christos table. */
449 1.1 christos if (strtab == NULL)
450 1.1 christos {
451 1.1 christos strtab = simple_object_xcoff_read_strtab (sobj,
452 1.1 christos &strtab_size,
453 1.1 christos &errmsg, err);
454 1.1 christos if (strtab == NULL)
455 1.1 christos {
456 1.1 christos XDELETEVEC (scnbuf);
457 1.1 christos return errmsg;
458 1.1 christos }
459 1.1 christos }
460 1.1 christos
461 1.1 christos if (strindex < 4 || strindex >= strtab_size)
462 1.1 christos {
463 1.1 christos XDELETEVEC (strtab);
464 1.1 christos XDELETEVEC (scnbuf);
465 1.1 christos *err = 0;
466 1.1 christos return "section string index out of range";
467 1.1 christos }
468 1.1 christos
469 1.1 christos name = strtab + strindex;
470 1.1 christos }
471 1.1 christos }
472 1.1 christos
473 1.1 christos if (u64)
474 1.1 christos {
475 1.1 christos scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
476 1.1 christos u.xcoff64.s_scnptr));
477 1.1 christos size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
478 1.1 christos u.xcoff64.s_size));
479 1.1 christos }
480 1.1 christos else
481 1.1 christos {
482 1.1 christos scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
483 1.1 christos u.xcoff32.s_scnptr));
484 1.1 christos size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
485 1.1 christos u.xcoff32.s_size));
486 1.1 christos }
487 1.1 christos
488 1.1 christos if (!(*pfn) (data, name, scnptr, size))
489 1.1 christos break;
490 1.1 christos }
491 1.1 christos
492 1.1 christos if (strtab != NULL)
493 1.1 christos XDELETEVEC (strtab);
494 1.1 christos XDELETEVEC (scnbuf);
495 1.1 christos
496 1.1 christos return NULL;
497 1.1 christos }
498 1.1 christos
499 1.1 christos /* Fetch the attributes for an simple_object_read. */
500 1.1 christos
501 1.1 christos static void *
502 1.1 christos simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
503 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
504 1.1 christos int *err ATTRIBUTE_UNUSED)
505 1.1 christos {
506 1.1 christos struct simple_object_xcoff_read *ocr =
507 1.1 christos (struct simple_object_xcoff_read *) sobj->data;
508 1.1 christos struct simple_object_xcoff_attributes *ret;
509 1.1 christos
510 1.1 christos ret = XNEW (struct simple_object_xcoff_attributes);
511 1.1 christos ret->magic = ocr->magic;
512 1.1 christos ret->flags = ocr->flags;
513 1.1 christos return ret;
514 1.1 christos }
515 1.1 christos
516 1.1 christos /* Release the private data for an simple_object_read. */
517 1.1 christos
518 1.1 christos static void
519 1.1 christos simple_object_xcoff_release_read (void *data)
520 1.1 christos {
521 1.1 christos XDELETE (data);
522 1.1 christos }
523 1.1 christos
524 1.1 christos /* Compare two attributes structures. */
525 1.1 christos
526 1.1 christos static const char *
527 1.1 christos simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
528 1.1 christos {
529 1.1 christos struct simple_object_xcoff_attributes *to =
530 1.1 christos (struct simple_object_xcoff_attributes *) todata;
531 1.1 christos struct simple_object_xcoff_attributes *from =
532 1.1 christos (struct simple_object_xcoff_attributes *) fromdata;
533 1.1 christos
534 1.1 christos if (to->magic != from->magic)
535 1.1 christos {
536 1.1 christos *err = 0;
537 1.1 christos return "XCOFF object format mismatch";
538 1.1 christos }
539 1.1 christos return NULL;
540 1.1 christos }
541 1.1 christos
542 1.1 christos /* Release the private data for an attributes structure. */
543 1.1 christos
544 1.1 christos static void
545 1.1 christos simple_object_xcoff_release_attributes (void *data)
546 1.1 christos {
547 1.1 christos XDELETE (data);
548 1.1 christos }
549 1.1 christos
550 1.1 christos /* Prepare to write out a file. */
551 1.1 christos
552 1.1 christos static void *
553 1.1 christos simple_object_xcoff_start_write (void *attributes_data,
554 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
555 1.1 christos int *err ATTRIBUTE_UNUSED)
556 1.1 christos {
557 1.1 christos struct simple_object_xcoff_attributes *attrs =
558 1.1 christos (struct simple_object_xcoff_attributes *) attributes_data;
559 1.1 christos struct simple_object_xcoff_attributes *ret;
560 1.1 christos
561 1.1 christos /* We're just going to record the attributes, but we need to make a
562 1.1 christos copy because the user may delete them. */
563 1.1 christos ret = XNEW (struct simple_object_xcoff_attributes);
564 1.1 christos *ret = *attrs;
565 1.1 christos return ret;
566 1.1 christos }
567 1.1 christos
568 1.1 christos /* Write out a XCOFF filehdr. */
569 1.1 christos
570 1.1 christos static int
571 1.1 christos simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
572 1.1 christos unsigned int nscns, size_t symtab_offset,
573 1.1 christos unsigned int nsyms, const char **errmsg,
574 1.1 christos int *err)
575 1.1 christos {
576 1.1 christos struct simple_object_xcoff_attributes *attrs =
577 1.1 christos (struct simple_object_xcoff_attributes *) sobj->data;
578 1.1 christos int u64 = attrs->magic == U64_TOCMAGIC;
579 1.1 christos unsigned char hdrbuf[sizeof (struct external_filehdr)];
580 1.1 christos unsigned char *hdr;
581 1.1 christos void (*set_16) (unsigned char *, unsigned short);
582 1.1 christos void (*set_32) (unsigned char *, unsigned int);
583 1.1 christos void (*set_64) (unsigned char *, ulong_type);
584 1.1 christos
585 1.1 christos hdr = &hdrbuf[0];
586 1.1 christos
587 1.1 christos set_16 = simple_object_set_big_16;
588 1.1 christos set_32 = simple_object_set_big_32;
589 1.1 christos set_64 = simple_object_set_big_64;
590 1.1 christos
591 1.1 christos memset (hdr, 0, sizeof (struct external_filehdr));
592 1.1 christos
593 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
594 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
595 1.1 christos /* f_timdat left as zero. */
596 1.1 christos if (u64)
597 1.1 christos {
598 1.1 christos set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
599 1.1 christos symtab_offset);
600 1.1 christos set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
601 1.1 christos nsyms);
602 1.1 christos /* f_opthdr left as zero. */
603 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
604 1.1 christos attrs->flags);
605 1.1 christos }
606 1.1 christos else
607 1.1 christos {
608 1.1 christos set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
609 1.1 christos symtab_offset);
610 1.1 christos set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
611 1.1 christos nsyms);
612 1.1 christos /* f_opthdr left as zero. */
613 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
614 1.1 christos attrs->flags);
615 1.1 christos }
616 1.1 christos
617 1.1 christos return simple_object_internal_write (descriptor, 0, hdrbuf,
618 1.1 christos sizeof (struct external_filehdr),
619 1.1 christos errmsg, err);
620 1.1 christos }
621 1.1 christos
622 1.1 christos /* Write out a XCOFF section header. */
623 1.1 christos
624 1.1 christos static int
625 1.1 christos simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
626 1.1 christos int descriptor,
627 1.1 christos const char *name, size_t *name_offset,
628 1.1 christos off_t scnhdr_offset, size_t scnsize,
629 1.1 christos off_t offset, unsigned int align,
630 1.1 christos const char **errmsg, int *err)
631 1.1 christos {
632 1.1 christos struct simple_object_xcoff_read *ocr =
633 1.1 christos (struct simple_object_xcoff_read *) sobj->data;
634 1.1 christos int u64 = ocr->magic == U64_TOCMAGIC;
635 1.1 christos void (*set_32) (unsigned char *, unsigned int);
636 1.1 christos void (*set_64) (unsigned char *, unsigned int);
637 1.1 christos unsigned char hdrbuf[sizeof (struct external_scnhdr)];
638 1.1 christos unsigned char *hdr;
639 1.1 christos size_t namelen;
640 1.1 christos unsigned int flags;
641 1.1 christos
642 1.1 christos set_32 = simple_object_set_big_32;
643 1.1 christos set_64 = simple_object_set_big_32;
644 1.1 christos
645 1.1 christos memset (hdrbuf, 0, sizeof hdrbuf);
646 1.1 christos hdr = &hdrbuf[0];
647 1.1 christos
648 1.1 christos namelen = strlen (name);
649 1.1 christos if (namelen <= SCNNMLEN)
650 1.1 christos strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
651 1.1 christos name, SCNNMLEN);
652 1.1 christos else
653 1.1 christos {
654 1.1 christos snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
655 1.1 christos SCNNMLEN, "/%lu", (unsigned long) *name_offset);
656 1.1 christos *name_offset += namelen + 1;
657 1.1 christos }
658 1.1 christos
659 1.1 christos /* s_paddr left as zero. */
660 1.1 christos /* s_vaddr left as zero. */
661 1.1 christos if (u64)
662 1.1 christos {
663 1.1 christos set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
664 1.1 christos scnsize);
665 1.1 christos set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
666 1.1 christos offset);
667 1.1 christos }
668 1.1 christos else
669 1.1 christos {
670 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
671 1.1 christos scnsize);
672 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
673 1.1 christos offset);
674 1.1 christos }
675 1.1 christos /* s_relptr left as zero. */
676 1.1 christos /* s_lnnoptr left as zero. */
677 1.1 christos /* s_nreloc left as zero. */
678 1.1 christos /* s_nlnno left as zero. */
679 1.1 christos flags = STYP_DATA;
680 1.1 christos if (align > 13)
681 1.1 christos align = 13;
682 1.1 christos if (u64)
683 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
684 1.1 christos else
685 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
686 1.1 christos
687 1.1 christos return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
688 1.1 christos u64 ? SCNHSZ64 : SCNHSZ32,
689 1.1 christos errmsg, err);
690 1.1 christos }
691 1.1 christos
692 1.1 christos /* Write out a complete XCOFF file. */
693 1.1 christos
694 1.1 christos static const char *
695 1.1 christos simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
696 1.1 christos int *err)
697 1.1 christos {
698 1.1 christos struct simple_object_xcoff_read *ocr =
699 1.1 christos (struct simple_object_xcoff_read *) sobj->data;
700 1.1 christos int u64 = ocr->magic == U64_TOCMAGIC;
701 1.1 christos unsigned int nscns, secnum;
702 1.1 christos simple_object_write_section *section;
703 1.1 christos off_t scnhdr_offset;
704 1.1 christos size_t symtab_offset;
705 1.1 christos off_t secsym_offset;
706 1.1 christos unsigned int nsyms;
707 1.1 christos size_t offset;
708 1.1 christos size_t name_offset;
709 1.1 christos const char *errmsg;
710 1.1 christos unsigned char strsizebuf[4];
711 1.1 christos /* The interface doesn't give us access to the name of the input file
712 1.1 christos yet. We want to use its basename for the FILE symbol. This is
713 1.1 christos what 'gas' uses when told to assemble from stdin. */
714 1.1 christos const char *source_filename = "fake";
715 1.1 christos size_t sflen;
716 1.1 christos union
717 1.1 christos {
718 1.1 christos struct external_syment sym;
719 1.1 christos union external_auxent aux;
720 1.1 christos } syms[2];
721 1.1 christos void (*set_16) (unsigned char *, unsigned short);
722 1.1 christos void (*set_32) (unsigned char *, unsigned int);
723 1.1 christos
724 1.1 christos set_16 = simple_object_set_big_16;
725 1.1 christos set_32 = simple_object_set_big_32;
726 1.1 christos
727 1.1 christos nscns = 0;
728 1.1 christos for (section = sobj->sections; section != NULL; section = section->next)
729 1.1 christos ++nscns;
730 1.1 christos
731 1.1 christos scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
732 1.1 christos offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
733 1.1 christos name_offset = 4;
734 1.1 christos for (section = sobj->sections; section != NULL; section = section->next)
735 1.1 christos {
736 1.1 christos size_t mask;
737 1.1 christos size_t new_offset;
738 1.1 christos size_t scnsize;
739 1.1 christos struct simple_object_write_section_buffer *buffer;
740 1.1 christos
741 1.1 christos mask = (1U << section->align) - 1;
742 1.1 christos new_offset = offset & mask;
743 1.1 christos new_offset &= ~ mask;
744 1.1 christos while (new_offset > offset)
745 1.1 christos {
746 1.1 christos unsigned char zeroes[16];
747 1.1 christos size_t write;
748 1.1 christos
749 1.1 christos memset (zeroes, 0, sizeof zeroes);
750 1.1 christos write = new_offset - offset;
751 1.1 christos if (write > sizeof zeroes)
752 1.1 christos write = sizeof zeroes;
753 1.1 christos if (!simple_object_internal_write (descriptor, offset, zeroes, write,
754 1.1 christos &errmsg, err))
755 1.1 christos return errmsg;
756 1.1 christos }
757 1.1 christos
758 1.1 christos scnsize = 0;
759 1.1 christos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
760 1.1 christos {
761 1.1 christos if (!simple_object_internal_write (descriptor, offset + scnsize,
762 1.1 christos ((const unsigned char *)
763 1.1 christos buffer->buffer),
764 1.1 christos buffer->size, &errmsg, err))
765 1.1 christos return errmsg;
766 1.1 christos scnsize += buffer->size;
767 1.1 christos }
768 1.1 christos
769 1.1 christos if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
770 1.1 christos &name_offset, scnhdr_offset,
771 1.1 christos scnsize, offset, section->align,
772 1.1 christos &errmsg, err))
773 1.1 christos return errmsg;
774 1.1 christos
775 1.1 christos scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
776 1.1 christos offset += scnsize;
777 1.1 christos }
778 1.1 christos
779 1.1 christos /* Symbol table is always half-word aligned. */
780 1.1 christos offset += (offset & 1);
781 1.1 christos /* There is a file symbol and a section symbol per section,
782 1.1 christos and each of these has a single auxiliary symbol following. */
783 1.1 christos nsyms = 2 * (nscns + 1);
784 1.1 christos symtab_offset = offset;
785 1.1 christos /* Advance across space reserved for symbol table to locate
786 1.1 christos start of string table. */
787 1.1 christos offset += nsyms * SYMESZ;
788 1.1 christos
789 1.1 christos /* Write out file symbol. */
790 1.1 christos memset (&syms[0], 0, sizeof (syms));
791 1.1 christos if (!u64)
792 1.1 christos strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
793 1.1 christos set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
794 1.1 christos set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
795 1.1 christos syms[0].sym.n_sclass[0] = C_FILE;
796 1.1 christos syms[0].sym.n_numaux[0] = 1;
797 1.1 christos /* The name need not be nul-terminated if it fits into the x_fname field
798 1.1 christos directly, but must be if it has to be placed into the string table. */
799 1.1 christos sflen = strlen (source_filename);
800 1.1 christos if (sflen <= FILNMLEN)
801 1.1 christos memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
802 1.1 christos else
803 1.1 christos {
804 1.1 christos set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
805 1.1 christos if (!simple_object_internal_write (descriptor, offset + name_offset,
806 1.1 christos ((const unsigned char *)
807 1.1 christos source_filename),
808 1.1 christos sflen + 1, &errmsg, err))
809 1.1 christos return errmsg;
810 1.1 christos name_offset += strlen (source_filename) + 1;
811 1.1 christos }
812 1.1 christos if (!simple_object_internal_write (descriptor, symtab_offset,
813 1.1 christos (const unsigned char *) &syms[0],
814 1.1 christos sizeof (syms), &errmsg, err))
815 1.1 christos return errmsg;
816 1.1 christos
817 1.1 christos /* Write the string table length, followed by the strings and section
818 1.1 christos symbols in step with each other. */
819 1.1 christos set_32 (strsizebuf, name_offset);
820 1.1 christos if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
821 1.1 christos &errmsg, err))
822 1.1 christos return errmsg;
823 1.1 christos
824 1.1 christos name_offset = 4;
825 1.1 christos secsym_offset = symtab_offset + sizeof (syms);
826 1.1 christos memset (&syms[0], 0, sizeof (syms));
827 1.1 christos set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
828 1.1 christos syms[0].sym.n_sclass[0] = C_STAT;
829 1.1 christos syms[0].sym.n_numaux[0] = 1;
830 1.1 christos secnum = 1;
831 1.1 christos
832 1.1 christos for (section = sobj->sections; section != NULL; section = section->next)
833 1.1 christos {
834 1.1 christos size_t namelen;
835 1.1 christos size_t scnsize;
836 1.1 christos struct simple_object_write_section_buffer *buffer;
837 1.1 christos
838 1.1 christos namelen = strlen (section->name);
839 1.1 christos set_16 (&syms[0].sym.n_scnum[0], secnum++);
840 1.1 christos scnsize = 0;
841 1.1 christos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
842 1.1 christos scnsize += buffer->size;
843 1.1 christos set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
844 1.1 christos if (namelen > SCNNMLEN)
845 1.1 christos {
846 1.1 christos set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
847 1.1 christos set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
848 1.1 christos if (!simple_object_internal_write (descriptor, offset + name_offset,
849 1.1 christos ((const unsigned char *)
850 1.1 christos section->name),
851 1.1 christos namelen + 1, &errmsg, err))
852 1.1 christos return errmsg;
853 1.1 christos name_offset += namelen + 1;
854 1.1 christos }
855 1.1 christos else
856 1.1 christos {
857 1.1 christos memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
858 1.1 christos strlen (section->name));
859 1.1 christos memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
860 1.1 christos N_SYMNMLEN - strlen (section->name));
861 1.1 christos }
862 1.1 christos
863 1.1 christos if (!simple_object_internal_write (descriptor, secsym_offset,
864 1.1 christos (const unsigned char *) &syms[0],
865 1.1 christos sizeof (syms), &errmsg, err))
866 1.1 christos return errmsg;
867 1.1 christos secsym_offset += sizeof (syms);
868 1.1 christos }
869 1.1 christos
870 1.1 christos if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
871 1.1 christos symtab_offset, nsyms, &errmsg, err))
872 1.1 christos return errmsg;
873 1.1 christos
874 1.1 christos return NULL;
875 1.1 christos }
876 1.1 christos
877 1.1 christos /* Release the private data for an simple_object_write structure. */
878 1.1 christos
879 1.1 christos static void
880 1.1 christos simple_object_xcoff_release_write (void *data)
881 1.1 christos {
882 1.1 christos XDELETE (data);
883 1.1 christos }
884 1.1 christos
885 1.1 christos /* The XCOFF functions. */
886 1.1 christos
887 1.1 christos const struct simple_object_functions simple_object_xcoff_functions =
888 1.1 christos {
889 1.1 christos simple_object_xcoff_match,
890 1.1 christos simple_object_xcoff_find_sections,
891 1.1 christos simple_object_xcoff_fetch_attributes,
892 1.1 christos simple_object_xcoff_release_read,
893 1.1 christos simple_object_xcoff_attributes_merge,
894 1.1 christos simple_object_xcoff_release_attributes,
895 1.1 christos simple_object_xcoff_start_write,
896 1.1 christos simple_object_xcoff_write_to_file,
897 1.1 christos simple_object_xcoff_release_write
898 1.1 christos };
899