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