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