simple-object-coff.c revision 1.1.1.5 1 1.1 mrg /* simple-object-coff.c -- routines to manipulate COFF object files.
2 1.1.1.5 mrg Copyright (C) 2010-2020 Free Software Foundation, Inc.
3 1.1 mrg Written by Ian Lance Taylor, Google.
4 1.1 mrg
5 1.1 mrg This program is free software; you can redistribute it and/or modify it
6 1.1 mrg under the terms of the GNU General Public License as published by the
7 1.1 mrg Free Software Foundation; either version 2, or (at your option) any
8 1.1 mrg later version.
9 1.1 mrg
10 1.1 mrg This program is distributed in the hope that it will be useful,
11 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 1.1 mrg GNU General Public License for more details.
14 1.1 mrg
15 1.1 mrg You should have received a copy of the GNU General Public License
16 1.1 mrg along with this program; if not, write to the Free Software
17 1.1 mrg Foundation, 51 Franklin Street - Fifth Floor,
18 1.1 mrg Boston, MA 02110-1301, USA. */
19 1.1 mrg
20 1.1 mrg #include "config.h"
21 1.1 mrg #include "libiberty.h"
22 1.1 mrg #include "simple-object.h"
23 1.1 mrg
24 1.1 mrg #include <errno.h>
25 1.1 mrg #include <stddef.h>
26 1.1 mrg
27 1.1 mrg #ifdef HAVE_STDLIB_H
28 1.1 mrg #include <stdlib.h>
29 1.1 mrg #endif
30 1.1 mrg
31 1.1 mrg #ifdef HAVE_STDINT_H
32 1.1 mrg #include <stdint.h>
33 1.1 mrg #endif
34 1.1 mrg
35 1.1 mrg #ifdef HAVE_STRING_H
36 1.1 mrg #include <string.h>
37 1.1 mrg #endif
38 1.1 mrg
39 1.1 mrg #ifdef HAVE_INTTYPES_H
40 1.1 mrg #include <inttypes.h>
41 1.1 mrg #endif
42 1.1 mrg
43 1.1 mrg #include "simple-object-common.h"
44 1.1 mrg
45 1.1 mrg /* COFF structures and constants. */
46 1.1 mrg
47 1.1 mrg /* COFF file header. */
48 1.1 mrg
49 1.1 mrg struct external_filehdr
50 1.1 mrg {
51 1.1 mrg unsigned char f_magic[2]; /* magic number */
52 1.1 mrg unsigned char f_nscns[2]; /* number of sections */
53 1.1 mrg unsigned char f_timdat[4]; /* time & date stamp */
54 1.1 mrg unsigned char f_symptr[4]; /* file pointer to symtab */
55 1.1 mrg unsigned char f_nsyms[4]; /* number of symtab entries */
56 1.1 mrg unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
57 1.1 mrg unsigned char f_flags[2]; /* flags */
58 1.1 mrg };
59 1.1 mrg
60 1.1 mrg /* Bits for filehdr f_flags field. */
61 1.1 mrg
62 1.1 mrg #define F_EXEC (0x0002)
63 1.1 mrg #define IMAGE_FILE_SYSTEM (0x1000)
64 1.1 mrg #define IMAGE_FILE_DLL (0x2000)
65 1.1 mrg
66 1.1 mrg /* COFF section header. */
67 1.1 mrg
68 1.1 mrg struct external_scnhdr
69 1.1 mrg {
70 1.1 mrg unsigned char s_name[8]; /* section name */
71 1.1 mrg unsigned char s_paddr[4]; /* physical address, aliased s_nlib */
72 1.1 mrg unsigned char s_vaddr[4]; /* virtual address */
73 1.1 mrg unsigned char s_size[4]; /* section size */
74 1.1 mrg unsigned char s_scnptr[4]; /* file ptr to raw data for section */
75 1.1 mrg unsigned char s_relptr[4]; /* file ptr to relocation */
76 1.1 mrg unsigned char s_lnnoptr[4]; /* file ptr to line numbers */
77 1.1 mrg unsigned char s_nreloc[2]; /* number of relocation entries */
78 1.1 mrg unsigned char s_nlnno[2]; /* number of line number entries */
79 1.1 mrg unsigned char s_flags[4]; /* flags */
80 1.1 mrg };
81 1.1 mrg
82 1.1 mrg /* The length of the s_name field in struct external_scnhdr. */
83 1.1 mrg
84 1.1 mrg #define SCNNMLEN (8)
85 1.1 mrg
86 1.1 mrg /* Bits for scnhdr s_flags field. This includes some bits defined
87 1.1 mrg only for PE. This may need to be moved into coff_magic. */
88 1.1 mrg
89 1.1 mrg #define STYP_DATA (1 << 6)
90 1.1 mrg #define IMAGE_SCN_MEM_DISCARDABLE (1 << 25)
91 1.1 mrg #define IMAGE_SCN_MEM_SHARED (1 << 28)
92 1.1 mrg #define IMAGE_SCN_MEM_READ (1 << 30)
93 1.1 mrg
94 1.1 mrg #define IMAGE_SCN_ALIGN_POWER_BIT_POS 20
95 1.1 mrg #define IMAGE_SCN_ALIGN_POWER_CONST(val) \
96 1.1 mrg (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
97 1.1 mrg
98 1.1 mrg /* COFF symbol table entry. */
99 1.1 mrg
100 1.1 mrg #define E_SYMNMLEN 8 /* # characters in a symbol name */
101 1.1 mrg
102 1.1 mrg struct external_syment
103 1.1 mrg {
104 1.1 mrg union
105 1.1 mrg {
106 1.1 mrg unsigned char e_name[E_SYMNMLEN];
107 1.1 mrg
108 1.1 mrg struct
109 1.1 mrg {
110 1.1 mrg unsigned char e_zeroes[4];
111 1.1 mrg unsigned char e_offset[4];
112 1.1 mrg } e;
113 1.1 mrg } e;
114 1.1 mrg
115 1.1 mrg unsigned char e_value[4];
116 1.1 mrg unsigned char e_scnum[2];
117 1.1 mrg unsigned char e_type[2];
118 1.1 mrg unsigned char e_sclass[1];
119 1.1 mrg unsigned char e_numaux[1];
120 1.1 mrg };
121 1.1 mrg
122 1.1 mrg /* Length allowed for filename in aux sym format 4. */
123 1.1 mrg
124 1.1 mrg #define E_FILNMLEN 18
125 1.1 mrg
126 1.1 mrg /* Omits x_sym and other unused variants. */
127 1.1 mrg
128 1.1 mrg union external_auxent
129 1.1 mrg {
130 1.1 mrg /* Aux sym format 4: file. */
131 1.1 mrg union
132 1.1 mrg {
133 1.1 mrg char x_fname[E_FILNMLEN];
134 1.1 mrg struct
135 1.1 mrg {
136 1.1 mrg unsigned char x_zeroes[4];
137 1.1 mrg unsigned char x_offset[4];
138 1.1 mrg } x_n;
139 1.1 mrg } x_file;
140 1.1 mrg /* Aux sym format 5: section. */
141 1.1 mrg struct
142 1.1 mrg {
143 1.1 mrg unsigned char x_scnlen[4]; /* section length */
144 1.1 mrg unsigned char x_nreloc[2]; /* # relocation entries */
145 1.1 mrg unsigned char x_nlinno[2]; /* # line numbers */
146 1.1 mrg unsigned char x_checksum[4]; /* section COMDAT checksum */
147 1.1 mrg unsigned char x_associated[2]; /* COMDAT assoc section index */
148 1.1 mrg unsigned char x_comdat[1]; /* COMDAT selection number */
149 1.1 mrg } x_scn;
150 1.1 mrg };
151 1.1 mrg
152 1.1 mrg /* Symbol-related constants. */
153 1.1 mrg
154 1.1 mrg #define IMAGE_SYM_DEBUG (-2)
155 1.1 mrg #define IMAGE_SYM_TYPE_NULL (0)
156 1.1 mrg #define IMAGE_SYM_DTYPE_NULL (0)
157 1.1 mrg #define IMAGE_SYM_CLASS_STATIC (3)
158 1.1 mrg #define IMAGE_SYM_CLASS_FILE (103)
159 1.1 mrg
160 1.1 mrg #define IMAGE_SYM_TYPE \
161 1.1 mrg ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
162 1.1 mrg
163 1.1 mrg /* Private data for an simple_object_read. */
164 1.1 mrg
165 1.1 mrg struct simple_object_coff_read
166 1.1 mrg {
167 1.1 mrg /* Magic number. */
168 1.1 mrg unsigned short magic;
169 1.1 mrg /* Whether the file is big-endian. */
170 1.1 mrg unsigned char is_big_endian;
171 1.1 mrg /* Number of sections. */
172 1.1 mrg unsigned short nscns;
173 1.1 mrg /* File offset of symbol table. */
174 1.1 mrg off_t symptr;
175 1.1 mrg /* Number of symbol table entries. */
176 1.1 mrg unsigned int nsyms;
177 1.1 mrg /* Flags. */
178 1.1 mrg unsigned short flags;
179 1.1 mrg /* Offset of section headers in file. */
180 1.1 mrg off_t scnhdr_offset;
181 1.1 mrg };
182 1.1 mrg
183 1.1 mrg /* Private data for an simple_object_attributes. */
184 1.1 mrg
185 1.1 mrg struct simple_object_coff_attributes
186 1.1 mrg {
187 1.1 mrg /* Magic number. */
188 1.1 mrg unsigned short magic;
189 1.1 mrg /* Whether the file is big-endian. */
190 1.1 mrg unsigned char is_big_endian;
191 1.1 mrg /* Flags. */
192 1.1 mrg unsigned short flags;
193 1.1 mrg };
194 1.1 mrg
195 1.1 mrg /* There is no magic number which indicates a COFF file as opposed to
196 1.1 mrg any other sort of file. Instead, each COFF file starts with a
197 1.1 mrg two-byte magic number which also indicates the type of the target.
198 1.1 mrg This struct holds a magic number as well as characteristics of that
199 1.1 mrg COFF format. */
200 1.1 mrg
201 1.1 mrg struct coff_magic_struct
202 1.1 mrg {
203 1.1 mrg /* Magic number. */
204 1.1 mrg unsigned short magic;
205 1.1 mrg /* Whether this magic number is for a big-endian file. */
206 1.1 mrg unsigned char is_big_endian;
207 1.1 mrg /* Flag bits, in the f_flags fields, which indicates that this file
208 1.1 mrg is not a relocatable object file. There is no flag which
209 1.1 mrg specifically indicates a relocatable object file, it is only
210 1.1 mrg implied by the absence of these flags. */
211 1.1 mrg unsigned short non_object_flags;
212 1.1 mrg };
213 1.1 mrg
214 1.1 mrg /* This is a list of the COFF magic numbers which we recognize, namely
215 1.1 mrg the ones used on Windows. More can be added as needed. */
216 1.1 mrg
217 1.1 mrg static const struct coff_magic_struct coff_magic[] =
218 1.1 mrg {
219 1.1 mrg /* i386. */
220 1.1 mrg { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
221 1.1 mrg /* x86_64. */
222 1.1 mrg { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
223 1.1 mrg };
224 1.1 mrg
225 1.1 mrg /* See if we have a COFF file. */
226 1.1 mrg
227 1.1 mrg static void *
228 1.1 mrg simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
229 1.1 mrg int descriptor, off_t offset,
230 1.1 mrg const char *segment_name ATTRIBUTE_UNUSED,
231 1.1 mrg const char **errmsg, int *err)
232 1.1 mrg {
233 1.1 mrg size_t c;
234 1.1 mrg unsigned short magic_big;
235 1.1 mrg unsigned short magic_little;
236 1.1 mrg unsigned short magic;
237 1.1 mrg size_t i;
238 1.1 mrg int is_big_endian;
239 1.1 mrg unsigned short (*fetch_16) (const unsigned char *);
240 1.1 mrg unsigned int (*fetch_32) (const unsigned char *);
241 1.1 mrg unsigned char hdrbuf[sizeof (struct external_filehdr)];
242 1.1 mrg unsigned short flags;
243 1.1 mrg struct simple_object_coff_read *ocr;
244 1.1 mrg
245 1.1 mrg c = sizeof (coff_magic) / sizeof (coff_magic[0]);
246 1.1 mrg magic_big = simple_object_fetch_big_16 (header);
247 1.1 mrg magic_little = simple_object_fetch_little_16 (header);
248 1.1 mrg for (i = 0; i < c; ++i)
249 1.1 mrg {
250 1.1 mrg if (coff_magic[i].is_big_endian
251 1.1 mrg ? coff_magic[i].magic == magic_big
252 1.1 mrg : coff_magic[i].magic == magic_little)
253 1.1 mrg break;
254 1.1 mrg }
255 1.1 mrg if (i >= c)
256 1.1 mrg {
257 1.1 mrg *errmsg = NULL;
258 1.1 mrg *err = 0;
259 1.1 mrg return NULL;
260 1.1 mrg }
261 1.1 mrg is_big_endian = coff_magic[i].is_big_endian;
262 1.1 mrg
263 1.1 mrg magic = is_big_endian ? magic_big : magic_little;
264 1.1 mrg fetch_16 = (is_big_endian
265 1.1 mrg ? simple_object_fetch_big_16
266 1.1 mrg : simple_object_fetch_little_16);
267 1.1 mrg fetch_32 = (is_big_endian
268 1.1 mrg ? simple_object_fetch_big_32
269 1.1 mrg : simple_object_fetch_little_32);
270 1.1 mrg
271 1.1 mrg if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
272 1.1 mrg errmsg, err))
273 1.1 mrg return NULL;
274 1.1 mrg
275 1.1 mrg flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
276 1.1 mrg if ((flags & coff_magic[i].non_object_flags) != 0)
277 1.1 mrg {
278 1.1 mrg *errmsg = "not relocatable object file";
279 1.1 mrg *err = 0;
280 1.1 mrg return NULL;
281 1.1 mrg }
282 1.1 mrg
283 1.1 mrg ocr = XNEW (struct simple_object_coff_read);
284 1.1 mrg ocr->magic = magic;
285 1.1 mrg ocr->is_big_endian = is_big_endian;
286 1.1 mrg ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
287 1.1 mrg ocr->symptr = fetch_32 (hdrbuf
288 1.1 mrg + offsetof (struct external_filehdr, f_symptr));
289 1.1 mrg ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
290 1.1 mrg ocr->flags = flags;
291 1.1 mrg ocr->scnhdr_offset = (sizeof (struct external_filehdr)
292 1.1 mrg + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
293 1.1 mrg f_opthdr)));
294 1.1 mrg
295 1.1 mrg return (void *) ocr;
296 1.1 mrg }
297 1.1 mrg
298 1.1 mrg /* Read the string table in a COFF file. */
299 1.1 mrg
300 1.1 mrg static char *
301 1.1 mrg simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
302 1.1 mrg const char **errmsg, int *err)
303 1.1 mrg {
304 1.1 mrg struct simple_object_coff_read *ocr =
305 1.1 mrg (struct simple_object_coff_read *) sobj->data;
306 1.1 mrg off_t strtab_offset;
307 1.1 mrg unsigned char strsizebuf[4];
308 1.1 mrg size_t strsize;
309 1.1 mrg char *strtab;
310 1.1 mrg
311 1.1 mrg strtab_offset = sobj->offset + ocr->symptr
312 1.1 mrg + ocr->nsyms * sizeof (struct external_syment);
313 1.1 mrg if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
314 1.1 mrg strsizebuf, 4, errmsg, err))
315 1.1 mrg return NULL;
316 1.1 mrg strsize = (ocr->is_big_endian
317 1.1 mrg ? simple_object_fetch_big_32 (strsizebuf)
318 1.1 mrg : simple_object_fetch_little_32 (strsizebuf));
319 1.1 mrg strtab = XNEWVEC (char, strsize);
320 1.1 mrg if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
321 1.1 mrg (unsigned char *) strtab, strsize, errmsg,
322 1.1 mrg err))
323 1.1 mrg {
324 1.1 mrg XDELETEVEC (strtab);
325 1.1 mrg return NULL;
326 1.1 mrg }
327 1.1 mrg *strtab_size = strsize;
328 1.1 mrg return strtab;
329 1.1 mrg }
330 1.1 mrg
331 1.1 mrg /* Find all sections in a COFF file. */
332 1.1 mrg
333 1.1 mrg static const char *
334 1.1 mrg simple_object_coff_find_sections (simple_object_read *sobj,
335 1.1 mrg int (*pfn) (void *, const char *,
336 1.1 mrg off_t offset, off_t length),
337 1.1 mrg void *data,
338 1.1 mrg int *err)
339 1.1 mrg {
340 1.1 mrg struct simple_object_coff_read *ocr =
341 1.1 mrg (struct simple_object_coff_read *) sobj->data;
342 1.1 mrg size_t scnhdr_size;
343 1.1 mrg unsigned char *scnbuf;
344 1.1 mrg const char *errmsg;
345 1.1 mrg unsigned int (*fetch_32) (const unsigned char *);
346 1.1 mrg unsigned int nscns;
347 1.1 mrg char *strtab;
348 1.1 mrg size_t strtab_size;
349 1.1 mrg unsigned int i;
350 1.1 mrg
351 1.1 mrg scnhdr_size = sizeof (struct external_scnhdr);
352 1.1 mrg scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
353 1.1 mrg if (!simple_object_internal_read (sobj->descriptor,
354 1.1 mrg sobj->offset + ocr->scnhdr_offset,
355 1.1 mrg scnbuf, scnhdr_size * ocr->nscns, &errmsg,
356 1.1 mrg err))
357 1.1 mrg {
358 1.1 mrg XDELETEVEC (scnbuf);
359 1.1 mrg return errmsg;
360 1.1 mrg }
361 1.1 mrg
362 1.1 mrg fetch_32 = (ocr->is_big_endian
363 1.1 mrg ? simple_object_fetch_big_32
364 1.1 mrg : simple_object_fetch_little_32);
365 1.1 mrg
366 1.1 mrg nscns = ocr->nscns;
367 1.1 mrg strtab = NULL;
368 1.1 mrg strtab_size = 0;
369 1.1 mrg for (i = 0; i < nscns; ++i)
370 1.1 mrg {
371 1.1 mrg unsigned char *scnhdr;
372 1.1 mrg unsigned char *scnname;
373 1.1 mrg char namebuf[SCNNMLEN + 1];
374 1.1 mrg char *name;
375 1.1 mrg off_t scnptr;
376 1.1 mrg unsigned int size;
377 1.1 mrg
378 1.1 mrg scnhdr = scnbuf + i * scnhdr_size;
379 1.1 mrg scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
380 1.1 mrg memcpy (namebuf, scnname, SCNNMLEN);
381 1.1 mrg namebuf[SCNNMLEN] = '\0';
382 1.1 mrg name = &namebuf[0];
383 1.1 mrg if (namebuf[0] == '/')
384 1.1 mrg {
385 1.1 mrg size_t strindex;
386 1.1 mrg char *end;
387 1.1 mrg
388 1.1 mrg strindex = strtol (namebuf + 1, &end, 10);
389 1.1 mrg if (*end == '\0')
390 1.1 mrg {
391 1.1 mrg /* The real section name is found in the string
392 1.1 mrg table. */
393 1.1 mrg if (strtab == NULL)
394 1.1 mrg {
395 1.1 mrg strtab = simple_object_coff_read_strtab (sobj,
396 1.1 mrg &strtab_size,
397 1.1 mrg &errmsg, err);
398 1.1 mrg if (strtab == NULL)
399 1.1 mrg {
400 1.1 mrg XDELETEVEC (scnbuf);
401 1.1 mrg return errmsg;
402 1.1 mrg }
403 1.1 mrg }
404 1.1 mrg
405 1.1 mrg if (strindex < 4 || strindex >= strtab_size)
406 1.1 mrg {
407 1.1 mrg XDELETEVEC (strtab);
408 1.1 mrg XDELETEVEC (scnbuf);
409 1.1 mrg *err = 0;
410 1.1 mrg return "section string index out of range";
411 1.1 mrg }
412 1.1 mrg
413 1.1 mrg name = strtab + strindex;
414 1.1 mrg }
415 1.1 mrg }
416 1.1 mrg
417 1.1 mrg scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
418 1.1 mrg size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
419 1.1 mrg
420 1.1 mrg if (!(*pfn) (data, name, scnptr, size))
421 1.1 mrg break;
422 1.1 mrg }
423 1.1 mrg
424 1.1 mrg if (strtab != NULL)
425 1.1 mrg XDELETEVEC (strtab);
426 1.1 mrg XDELETEVEC (scnbuf);
427 1.1 mrg
428 1.1 mrg return NULL;
429 1.1 mrg }
430 1.1 mrg
431 1.1 mrg /* Fetch the attributes for an simple_object_read. */
432 1.1 mrg
433 1.1 mrg static void *
434 1.1 mrg simple_object_coff_fetch_attributes (simple_object_read *sobj,
435 1.1 mrg const char **errmsg ATTRIBUTE_UNUSED,
436 1.1 mrg int *err ATTRIBUTE_UNUSED)
437 1.1 mrg {
438 1.1 mrg struct simple_object_coff_read *ocr =
439 1.1 mrg (struct simple_object_coff_read *) sobj->data;
440 1.1 mrg struct simple_object_coff_attributes *ret;
441 1.1 mrg
442 1.1 mrg ret = XNEW (struct simple_object_coff_attributes);
443 1.1 mrg ret->magic = ocr->magic;
444 1.1 mrg ret->is_big_endian = ocr->is_big_endian;
445 1.1 mrg ret->flags = ocr->flags;
446 1.1 mrg return ret;
447 1.1 mrg }
448 1.1 mrg
449 1.1 mrg /* Release the private data for an simple_object_read. */
450 1.1 mrg
451 1.1 mrg static void
452 1.1 mrg simple_object_coff_release_read (void *data)
453 1.1 mrg {
454 1.1 mrg XDELETE (data);
455 1.1 mrg }
456 1.1 mrg
457 1.1 mrg /* Compare two attributes structures. */
458 1.1 mrg
459 1.1 mrg static const char *
460 1.1 mrg simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err)
461 1.1 mrg {
462 1.1 mrg struct simple_object_coff_attributes *to =
463 1.1 mrg (struct simple_object_coff_attributes *) todata;
464 1.1 mrg struct simple_object_coff_attributes *from =
465 1.1 mrg (struct simple_object_coff_attributes *) fromdata;
466 1.1 mrg
467 1.1 mrg if (to->magic != from->magic || to->is_big_endian != from->is_big_endian)
468 1.1 mrg {
469 1.1 mrg *err = 0;
470 1.1 mrg return "COFF object format mismatch";
471 1.1 mrg }
472 1.1 mrg return NULL;
473 1.1 mrg }
474 1.1 mrg
475 1.1 mrg /* Release the private data for an attributes structure. */
476 1.1 mrg
477 1.1 mrg static void
478 1.1 mrg simple_object_coff_release_attributes (void *data)
479 1.1 mrg {
480 1.1 mrg XDELETE (data);
481 1.1 mrg }
482 1.1 mrg
483 1.1 mrg /* Prepare to write out a file. */
484 1.1 mrg
485 1.1 mrg static void *
486 1.1 mrg simple_object_coff_start_write (void *attributes_data,
487 1.1 mrg const char **errmsg ATTRIBUTE_UNUSED,
488 1.1 mrg int *err ATTRIBUTE_UNUSED)
489 1.1 mrg {
490 1.1 mrg struct simple_object_coff_attributes *attrs =
491 1.1 mrg (struct simple_object_coff_attributes *) attributes_data;
492 1.1 mrg struct simple_object_coff_attributes *ret;
493 1.1 mrg
494 1.1 mrg /* We're just going to record the attributes, but we need to make a
495 1.1 mrg copy because the user may delete them. */
496 1.1 mrg ret = XNEW (struct simple_object_coff_attributes);
497 1.1 mrg *ret = *attrs;
498 1.1 mrg return ret;
499 1.1 mrg }
500 1.1 mrg
501 1.1 mrg /* Write out a COFF filehdr. */
502 1.1 mrg
503 1.1 mrg static int
504 1.1 mrg simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
505 1.1 mrg unsigned int nscns, size_t symtab_offset,
506 1.1 mrg unsigned int nsyms, const char **errmsg,
507 1.1 mrg int *err)
508 1.1 mrg {
509 1.1 mrg struct simple_object_coff_attributes *attrs =
510 1.1 mrg (struct simple_object_coff_attributes *) sobj->data;
511 1.1 mrg unsigned char hdrbuf[sizeof (struct external_filehdr)];
512 1.1 mrg unsigned char *hdr;
513 1.1 mrg void (*set_16) (unsigned char *, unsigned short);
514 1.1 mrg void (*set_32) (unsigned char *, unsigned int);
515 1.1 mrg
516 1.1 mrg hdr = &hdrbuf[0];
517 1.1 mrg
518 1.1 mrg set_16 = (attrs->is_big_endian
519 1.1 mrg ? simple_object_set_big_16
520 1.1 mrg : simple_object_set_little_16);
521 1.1 mrg set_32 = (attrs->is_big_endian
522 1.1 mrg ? simple_object_set_big_32
523 1.1 mrg : simple_object_set_little_32);
524 1.1 mrg
525 1.1 mrg memset (hdr, 0, sizeof (struct external_filehdr));
526 1.1 mrg
527 1.1 mrg set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
528 1.1 mrg set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
529 1.1 mrg /* f_timdat left as zero. */
530 1.1 mrg set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
531 1.1 mrg set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
532 1.1 mrg /* f_opthdr left as zero. */
533 1.1 mrg set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
534 1.1 mrg
535 1.1 mrg return simple_object_internal_write (descriptor, 0, hdrbuf,
536 1.1 mrg sizeof (struct external_filehdr),
537 1.1 mrg errmsg, err);
538 1.1 mrg }
539 1.1 mrg
540 1.1 mrg /* Write out a COFF section header. */
541 1.1 mrg
542 1.1 mrg static int
543 1.1 mrg simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
544 1.1 mrg const char *name, size_t *name_offset,
545 1.1 mrg off_t scnhdr_offset, size_t scnsize,
546 1.1 mrg off_t offset, unsigned int align,
547 1.1 mrg const char **errmsg, int *err)
548 1.1 mrg {
549 1.1 mrg struct simple_object_coff_attributes *attrs =
550 1.1 mrg (struct simple_object_coff_attributes *) sobj->data;
551 1.1 mrg void (*set_32) (unsigned char *, unsigned int);
552 1.1 mrg unsigned char hdrbuf[sizeof (struct external_scnhdr)];
553 1.1 mrg unsigned char *hdr;
554 1.1 mrg size_t namelen;
555 1.1 mrg unsigned int flags;
556 1.1 mrg
557 1.1 mrg set_32 = (attrs->is_big_endian
558 1.1 mrg ? simple_object_set_big_32
559 1.1 mrg : simple_object_set_little_32);
560 1.1 mrg
561 1.1 mrg memset (hdrbuf, 0, sizeof hdrbuf);
562 1.1 mrg hdr = &hdrbuf[0];
563 1.1 mrg
564 1.1 mrg namelen = strlen (name);
565 1.1 mrg if (namelen <= SCNNMLEN)
566 1.1 mrg strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
567 1.1 mrg SCNNMLEN);
568 1.1 mrg else
569 1.1 mrg {
570 1.1 mrg snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
571 1.1 mrg SCNNMLEN, "/%lu", (unsigned long) *name_offset);
572 1.1 mrg *name_offset += namelen + 1;
573 1.1 mrg }
574 1.1 mrg
575 1.1 mrg /* s_paddr left as zero. */
576 1.1 mrg /* s_vaddr left as zero. */
577 1.1 mrg set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
578 1.1 mrg set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
579 1.1 mrg /* s_relptr left as zero. */
580 1.1 mrg /* s_lnnoptr left as zero. */
581 1.1 mrg /* s_nreloc left as zero. */
582 1.1 mrg /* s_nlnno left as zero. */
583 1.1 mrg flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
584 1.1 mrg | IMAGE_SCN_MEM_READ);
585 1.1 mrg /* PE can represent alignment up to 13. */
586 1.1 mrg if (align > 13)
587 1.1 mrg align = 13;
588 1.1 mrg flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
589 1.1 mrg set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
590 1.1 mrg
591 1.1 mrg return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
592 1.1 mrg sizeof (struct external_scnhdr),
593 1.1 mrg errmsg, err);
594 1.1 mrg }
595 1.1 mrg
596 1.1 mrg /* Write out a complete COFF file. */
597 1.1 mrg
598 1.1 mrg static const char *
599 1.1 mrg simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
600 1.1 mrg int *err)
601 1.1 mrg {
602 1.1 mrg struct simple_object_coff_attributes *attrs =
603 1.1 mrg (struct simple_object_coff_attributes *) sobj->data;
604 1.1 mrg unsigned int nscns, secnum;
605 1.1 mrg simple_object_write_section *section;
606 1.1 mrg off_t scnhdr_offset;
607 1.1 mrg size_t symtab_offset;
608 1.1 mrg off_t secsym_offset;
609 1.1 mrg unsigned int nsyms;
610 1.1 mrg size_t offset;
611 1.1 mrg size_t name_offset;
612 1.1 mrg const char *errmsg;
613 1.1 mrg unsigned char strsizebuf[4];
614 1.1 mrg /* The interface doesn't give us access to the name of the input file
615 1.1 mrg yet. We want to use its basename for the FILE symbol. This is
616 1.1 mrg what 'gas' uses when told to assemble from stdin. */
617 1.1 mrg const char *source_filename = "fake";
618 1.1 mrg size_t sflen;
619 1.1 mrg union
620 1.1 mrg {
621 1.1 mrg struct external_syment sym;
622 1.1 mrg union external_auxent aux;
623 1.1 mrg } syms[2];
624 1.1 mrg void (*set_16) (unsigned char *, unsigned short);
625 1.1 mrg void (*set_32) (unsigned char *, unsigned int);
626 1.1 mrg
627 1.1 mrg set_16 = (attrs->is_big_endian
628 1.1 mrg ? simple_object_set_big_16
629 1.1 mrg : simple_object_set_little_16);
630 1.1 mrg set_32 = (attrs->is_big_endian
631 1.1 mrg ? simple_object_set_big_32
632 1.1 mrg : simple_object_set_little_32);
633 1.1 mrg
634 1.1 mrg nscns = 0;
635 1.1 mrg for (section = sobj->sections; section != NULL; section = section->next)
636 1.1 mrg ++nscns;
637 1.1 mrg
638 1.1 mrg scnhdr_offset = sizeof (struct external_filehdr);
639 1.1 mrg offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
640 1.1 mrg name_offset = 4;
641 1.1 mrg for (section = sobj->sections; section != NULL; section = section->next)
642 1.1 mrg {
643 1.1 mrg size_t mask;
644 1.1 mrg size_t new_offset;
645 1.1 mrg size_t scnsize;
646 1.1 mrg struct simple_object_write_section_buffer *buffer;
647 1.1 mrg
648 1.1 mrg mask = (1U << section->align) - 1;
649 1.1 mrg new_offset = offset & mask;
650 1.1 mrg new_offset &= ~ mask;
651 1.1 mrg while (new_offset > offset)
652 1.1 mrg {
653 1.1 mrg unsigned char zeroes[16];
654 1.1 mrg size_t write;
655 1.1 mrg
656 1.1 mrg memset (zeroes, 0, sizeof zeroes);
657 1.1 mrg write = new_offset - offset;
658 1.1 mrg if (write > sizeof zeroes)
659 1.1 mrg write = sizeof zeroes;
660 1.1 mrg if (!simple_object_internal_write (descriptor, offset, zeroes, write,
661 1.1 mrg &errmsg, err))
662 1.1 mrg return errmsg;
663 1.1 mrg }
664 1.1 mrg
665 1.1 mrg scnsize = 0;
666 1.1 mrg for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
667 1.1 mrg {
668 1.1 mrg if (!simple_object_internal_write (descriptor, offset + scnsize,
669 1.1 mrg ((const unsigned char *)
670 1.1 mrg buffer->buffer),
671 1.1 mrg buffer->size, &errmsg, err))
672 1.1 mrg return errmsg;
673 1.1 mrg scnsize += buffer->size;
674 1.1 mrg }
675 1.1 mrg
676 1.1 mrg if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
677 1.1 mrg &name_offset, scnhdr_offset,
678 1.1 mrg scnsize, offset, section->align,
679 1.1 mrg &errmsg, err))
680 1.1 mrg return errmsg;
681 1.1 mrg
682 1.1 mrg scnhdr_offset += sizeof (struct external_scnhdr);
683 1.1 mrg offset += scnsize;
684 1.1 mrg }
685 1.1 mrg
686 1.1 mrg /* Symbol table is always half-word aligned. */
687 1.1 mrg offset += (offset & 1);
688 1.1 mrg /* There is a file symbol and a section symbol per section,
689 1.1 mrg and each of these has a single auxiliary symbol following. */
690 1.1 mrg nsyms = 2 * (nscns + 1);
691 1.1 mrg symtab_offset = offset;
692 1.1 mrg /* Advance across space reserved for symbol table to locate
693 1.1 mrg start of string table. */
694 1.1 mrg offset += nsyms * sizeof (struct external_syment);
695 1.1 mrg
696 1.1 mrg /* Write out file symbol. */
697 1.1 mrg memset (&syms[0], 0, sizeof (syms));
698 1.1 mrg strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
699 1.1 mrg set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
700 1.1 mrg set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
701 1.1 mrg syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
702 1.1 mrg syms[0].sym.e_numaux[0] = 1;
703 1.1 mrg /* The name need not be nul-terminated if it fits into the x_fname field
704 1.1 mrg directly, but must be if it has to be placed into the string table. */
705 1.1 mrg sflen = strlen (source_filename);
706 1.1 mrg if (sflen <= E_FILNMLEN)
707 1.1 mrg memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
708 1.1 mrg else
709 1.1 mrg {
710 1.1 mrg set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
711 1.1 mrg if (!simple_object_internal_write (descriptor, offset + name_offset,
712 1.1 mrg ((const unsigned char *)
713 1.1 mrg source_filename),
714 1.1 mrg sflen + 1, &errmsg, err))
715 1.1 mrg return errmsg;
716 1.1 mrg name_offset += strlen (source_filename) + 1;
717 1.1 mrg }
718 1.1 mrg if (!simple_object_internal_write (descriptor, symtab_offset,
719 1.1 mrg (const unsigned char *) &syms[0],
720 1.1 mrg sizeof (syms), &errmsg, err))
721 1.1 mrg return errmsg;
722 1.1 mrg
723 1.1 mrg /* Write the string table length, followed by the strings and section
724 1.1 mrg symbols in step with each other. */
725 1.1 mrg set_32 (strsizebuf, name_offset);
726 1.1 mrg if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
727 1.1 mrg &errmsg, err))
728 1.1 mrg return errmsg;
729 1.1 mrg
730 1.1 mrg name_offset = 4;
731 1.1 mrg secsym_offset = symtab_offset + sizeof (syms);
732 1.1 mrg memset (&syms[0], 0, sizeof (syms));
733 1.1 mrg set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
734 1.1 mrg syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
735 1.1 mrg syms[0].sym.e_numaux[0] = 1;
736 1.1 mrg secnum = 1;
737 1.1 mrg
738 1.1 mrg for (section = sobj->sections; section != NULL; section = section->next)
739 1.1 mrg {
740 1.1 mrg size_t namelen;
741 1.1 mrg size_t scnsize;
742 1.1 mrg struct simple_object_write_section_buffer *buffer;
743 1.1 mrg
744 1.1 mrg namelen = strlen (section->name);
745 1.1 mrg set_16 (&syms[0].sym.e_scnum[0], secnum++);
746 1.1 mrg scnsize = 0;
747 1.1 mrg for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
748 1.1 mrg scnsize += buffer->size;
749 1.1 mrg set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
750 1.1 mrg if (namelen > SCNNMLEN)
751 1.1 mrg {
752 1.1 mrg set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
753 1.1 mrg set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
754 1.1 mrg if (!simple_object_internal_write (descriptor, offset + name_offset,
755 1.1 mrg ((const unsigned char *)
756 1.1 mrg section->name),
757 1.1 mrg namelen + 1, &errmsg, err))
758 1.1 mrg return errmsg;
759 1.1 mrg name_offset += namelen + 1;
760 1.1 mrg }
761 1.1 mrg else
762 1.1 mrg {
763 1.1 mrg memcpy (&syms[0].sym.e.e_name[0], section->name,
764 1.1 mrg strlen (section->name));
765 1.1 mrg memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
766 1.1 mrg E_SYMNMLEN - strlen (section->name));
767 1.1 mrg }
768 1.1 mrg
769 1.1 mrg if (!simple_object_internal_write (descriptor, secsym_offset,
770 1.1 mrg (const unsigned char *) &syms[0],
771 1.1 mrg sizeof (syms), &errmsg, err))
772 1.1 mrg return errmsg;
773 1.1 mrg secsym_offset += sizeof (syms);
774 1.1 mrg }
775 1.1 mrg
776 1.1 mrg if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
777 1.1 mrg symtab_offset, nsyms, &errmsg, err))
778 1.1 mrg return errmsg;
779 1.1 mrg
780 1.1 mrg return NULL;
781 1.1 mrg }
782 1.1 mrg
783 1.1 mrg /* Release the private data for an simple_object_write structure. */
784 1.1 mrg
785 1.1 mrg static void
786 1.1 mrg simple_object_coff_release_write (void *data)
787 1.1 mrg {
788 1.1 mrg XDELETE (data);
789 1.1 mrg }
790 1.1 mrg
791 1.1 mrg /* The COFF functions. */
792 1.1 mrg
793 1.1 mrg const struct simple_object_functions simple_object_coff_functions =
794 1.1 mrg {
795 1.1 mrg simple_object_coff_match,
796 1.1 mrg simple_object_coff_find_sections,
797 1.1 mrg simple_object_coff_fetch_attributes,
798 1.1 mrg simple_object_coff_release_read,
799 1.1 mrg simple_object_coff_attributes_merge,
800 1.1 mrg simple_object_coff_release_attributes,
801 1.1 mrg simple_object_coff_start_write,
802 1.1 mrg simple_object_coff_write_to_file,
803 1.1.1.3 mrg simple_object_coff_release_write,
804 1.1.1.3 mrg NULL
805 1.1 mrg };
806