1 1.1 christos /* simple-object-coff.c -- routines to manipulate COFF object files. 2 1.10 christos Copyright (C) 2010-2024 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.11 christos { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }, 223 1.11 christos /* AArch64. */ 224 1.11 christos { 0xaa64, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL } 225 1.1 christos }; 226 1.1 christos 227 1.1 christos /* See if we have a COFF file. */ 228 1.1 christos 229 1.1 christos static void * 230 1.1 christos simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 231 1.1 christos int descriptor, off_t offset, 232 1.1 christos const char *segment_name ATTRIBUTE_UNUSED, 233 1.1 christos const char **errmsg, int *err) 234 1.1 christos { 235 1.1 christos size_t c; 236 1.1 christos unsigned short magic_big; 237 1.1 christos unsigned short magic_little; 238 1.1 christos unsigned short magic; 239 1.1 christos size_t i; 240 1.1 christos int is_big_endian; 241 1.1 christos unsigned short (*fetch_16) (const unsigned char *); 242 1.1 christos unsigned int (*fetch_32) (const unsigned char *); 243 1.1 christos unsigned char hdrbuf[sizeof (struct external_filehdr)]; 244 1.1 christos unsigned short flags; 245 1.1 christos struct simple_object_coff_read *ocr; 246 1.1 christos 247 1.1 christos c = sizeof (coff_magic) / sizeof (coff_magic[0]); 248 1.1 christos magic_big = simple_object_fetch_big_16 (header); 249 1.1 christos magic_little = simple_object_fetch_little_16 (header); 250 1.1 christos for (i = 0; i < c; ++i) 251 1.1 christos { 252 1.1 christos if (coff_magic[i].is_big_endian 253 1.1 christos ? coff_magic[i].magic == magic_big 254 1.1 christos : coff_magic[i].magic == magic_little) 255 1.1 christos break; 256 1.1 christos } 257 1.1 christos if (i >= c) 258 1.1 christos { 259 1.1 christos *errmsg = NULL; 260 1.1 christos *err = 0; 261 1.1 christos return NULL; 262 1.1 christos } 263 1.1 christos is_big_endian = coff_magic[i].is_big_endian; 264 1.1 christos 265 1.1 christos magic = is_big_endian ? magic_big : magic_little; 266 1.1 christos fetch_16 = (is_big_endian 267 1.1 christos ? simple_object_fetch_big_16 268 1.1 christos : simple_object_fetch_little_16); 269 1.1 christos fetch_32 = (is_big_endian 270 1.1 christos ? simple_object_fetch_big_32 271 1.1 christos : simple_object_fetch_little_32); 272 1.1 christos 273 1.1 christos if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf, 274 1.1 christos errmsg, err)) 275 1.1 christos return NULL; 276 1.1 christos 277 1.1 christos flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags)); 278 1.1 christos if ((flags & coff_magic[i].non_object_flags) != 0) 279 1.1 christos { 280 1.1 christos *errmsg = "not relocatable object file"; 281 1.1 christos *err = 0; 282 1.1 christos return NULL; 283 1.1 christos } 284 1.1 christos 285 1.1 christos ocr = XNEW (struct simple_object_coff_read); 286 1.1 christos ocr->magic = magic; 287 1.1 christos ocr->is_big_endian = is_big_endian; 288 1.1 christos ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns)); 289 1.1 christos ocr->symptr = fetch_32 (hdrbuf 290 1.1 christos + offsetof (struct external_filehdr, f_symptr)); 291 1.1 christos ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms)); 292 1.1 christos ocr->flags = flags; 293 1.1 christos ocr->scnhdr_offset = (sizeof (struct external_filehdr) 294 1.1 christos + fetch_16 (hdrbuf + offsetof (struct external_filehdr, 295 1.1 christos f_opthdr))); 296 1.1 christos 297 1.1 christos return (void *) ocr; 298 1.1 christos } 299 1.1 christos 300 1.1 christos /* Read the string table in a COFF file. */ 301 1.1 christos 302 1.1 christos static char * 303 1.1 christos simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size, 304 1.1 christos const char **errmsg, int *err) 305 1.1 christos { 306 1.1 christos struct simple_object_coff_read *ocr = 307 1.1 christos (struct simple_object_coff_read *) sobj->data; 308 1.1 christos off_t strtab_offset; 309 1.1 christos unsigned char strsizebuf[4]; 310 1.1 christos size_t strsize; 311 1.1 christos char *strtab; 312 1.1 christos 313 1.1 christos strtab_offset = sobj->offset + ocr->symptr 314 1.1 christos + ocr->nsyms * sizeof (struct external_syment); 315 1.1 christos if (!simple_object_internal_read (sobj->descriptor, strtab_offset, 316 1.1 christos strsizebuf, 4, errmsg, err)) 317 1.1 christos return NULL; 318 1.1 christos strsize = (ocr->is_big_endian 319 1.1 christos ? simple_object_fetch_big_32 (strsizebuf) 320 1.1 christos : simple_object_fetch_little_32 (strsizebuf)); 321 1.1 christos strtab = XNEWVEC (char, strsize); 322 1.1 christos if (!simple_object_internal_read (sobj->descriptor, strtab_offset, 323 1.1 christos (unsigned char *) strtab, strsize, errmsg, 324 1.1 christos err)) 325 1.1 christos { 326 1.1 christos XDELETEVEC (strtab); 327 1.1 christos return NULL; 328 1.1 christos } 329 1.1 christos *strtab_size = strsize; 330 1.1 christos return strtab; 331 1.1 christos } 332 1.1 christos 333 1.1 christos /* Find all sections in a COFF file. */ 334 1.1 christos 335 1.1 christos static const char * 336 1.1 christos simple_object_coff_find_sections (simple_object_read *sobj, 337 1.1 christos int (*pfn) (void *, const char *, 338 1.1 christos off_t offset, off_t length), 339 1.1 christos void *data, 340 1.1 christos int *err) 341 1.1 christos { 342 1.1 christos struct simple_object_coff_read *ocr = 343 1.1 christos (struct simple_object_coff_read *) sobj->data; 344 1.1 christos size_t scnhdr_size; 345 1.1 christos unsigned char *scnbuf; 346 1.1 christos const char *errmsg; 347 1.1 christos unsigned int (*fetch_32) (const unsigned char *); 348 1.1 christos unsigned int nscns; 349 1.1 christos char *strtab; 350 1.1 christos size_t strtab_size; 351 1.1 christos unsigned int i; 352 1.1 christos 353 1.1 christos scnhdr_size = sizeof (struct external_scnhdr); 354 1.1 christos scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns); 355 1.1 christos if (!simple_object_internal_read (sobj->descriptor, 356 1.1 christos sobj->offset + ocr->scnhdr_offset, 357 1.1 christos scnbuf, scnhdr_size * ocr->nscns, &errmsg, 358 1.1 christos err)) 359 1.1 christos { 360 1.1 christos XDELETEVEC (scnbuf); 361 1.1 christos return errmsg; 362 1.1 christos } 363 1.1 christos 364 1.1 christos fetch_32 = (ocr->is_big_endian 365 1.1 christos ? simple_object_fetch_big_32 366 1.1 christos : simple_object_fetch_little_32); 367 1.1 christos 368 1.1 christos nscns = ocr->nscns; 369 1.1 christos strtab = NULL; 370 1.1 christos strtab_size = 0; 371 1.1 christos for (i = 0; i < nscns; ++i) 372 1.1 christos { 373 1.1 christos unsigned char *scnhdr; 374 1.1 christos unsigned char *scnname; 375 1.1 christos char namebuf[SCNNMLEN + 1]; 376 1.1 christos char *name; 377 1.1 christos off_t scnptr; 378 1.1 christos unsigned int size; 379 1.1 christos 380 1.1 christos scnhdr = scnbuf + i * scnhdr_size; 381 1.1 christos scnname = scnhdr + offsetof (struct external_scnhdr, s_name); 382 1.1 christos memcpy (namebuf, scnname, SCNNMLEN); 383 1.1 christos namebuf[SCNNMLEN] = '\0'; 384 1.1 christos name = &namebuf[0]; 385 1.1 christos if (namebuf[0] == '/') 386 1.1 christos { 387 1.1 christos size_t strindex; 388 1.1 christos char *end; 389 1.1 christos 390 1.1 christos strindex = strtol (namebuf + 1, &end, 10); 391 1.1 christos if (*end == '\0') 392 1.1 christos { 393 1.1 christos /* The real section name is found in the string 394 1.1 christos table. */ 395 1.1 christos if (strtab == NULL) 396 1.1 christos { 397 1.1 christos strtab = simple_object_coff_read_strtab (sobj, 398 1.1 christos &strtab_size, 399 1.1 christos &errmsg, err); 400 1.1 christos if (strtab == NULL) 401 1.1 christos { 402 1.1 christos XDELETEVEC (scnbuf); 403 1.1 christos return errmsg; 404 1.1 christos } 405 1.1 christos } 406 1.1 christos 407 1.1 christos if (strindex < 4 || strindex >= strtab_size) 408 1.1 christos { 409 1.1 christos XDELETEVEC (strtab); 410 1.1 christos XDELETEVEC (scnbuf); 411 1.1 christos *err = 0; 412 1.1 christos return "section string index out of range"; 413 1.1 christos } 414 1.1 christos 415 1.1 christos name = strtab + strindex; 416 1.1 christos } 417 1.1 christos } 418 1.1 christos 419 1.1 christos scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr)); 420 1.1 christos size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size)); 421 1.1 christos 422 1.1 christos if (!(*pfn) (data, name, scnptr, size)) 423 1.1 christos break; 424 1.1 christos } 425 1.1 christos 426 1.1 christos if (strtab != NULL) 427 1.1 christos XDELETEVEC (strtab); 428 1.1 christos XDELETEVEC (scnbuf); 429 1.1 christos 430 1.1 christos return NULL; 431 1.1 christos } 432 1.1 christos 433 1.1 christos /* Fetch the attributes for an simple_object_read. */ 434 1.1 christos 435 1.1 christos static void * 436 1.1 christos simple_object_coff_fetch_attributes (simple_object_read *sobj, 437 1.1 christos const char **errmsg ATTRIBUTE_UNUSED, 438 1.1 christos int *err ATTRIBUTE_UNUSED) 439 1.1 christos { 440 1.1 christos struct simple_object_coff_read *ocr = 441 1.1 christos (struct simple_object_coff_read *) sobj->data; 442 1.1 christos struct simple_object_coff_attributes *ret; 443 1.1 christos 444 1.1 christos ret = XNEW (struct simple_object_coff_attributes); 445 1.1 christos ret->magic = ocr->magic; 446 1.1 christos ret->is_big_endian = ocr->is_big_endian; 447 1.1 christos ret->flags = ocr->flags; 448 1.1 christos return ret; 449 1.1 christos } 450 1.1 christos 451 1.1 christos /* Release the private data for an simple_object_read. */ 452 1.1 christos 453 1.1 christos static void 454 1.1 christos simple_object_coff_release_read (void *data) 455 1.1 christos { 456 1.1 christos XDELETE (data); 457 1.1 christos } 458 1.1 christos 459 1.1 christos /* Compare two attributes structures. */ 460 1.1 christos 461 1.1 christos static const char * 462 1.1 christos simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err) 463 1.1 christos { 464 1.1 christos struct simple_object_coff_attributes *to = 465 1.1 christos (struct simple_object_coff_attributes *) todata; 466 1.1 christos struct simple_object_coff_attributes *from = 467 1.1 christos (struct simple_object_coff_attributes *) fromdata; 468 1.1 christos 469 1.1 christos if (to->magic != from->magic || to->is_big_endian != from->is_big_endian) 470 1.1 christos { 471 1.1 christos *err = 0; 472 1.1 christos return "COFF object format mismatch"; 473 1.1 christos } 474 1.1 christos return NULL; 475 1.1 christos } 476 1.1 christos 477 1.1 christos /* Release the private data for an attributes structure. */ 478 1.1 christos 479 1.1 christos static void 480 1.1 christos simple_object_coff_release_attributes (void *data) 481 1.1 christos { 482 1.1 christos XDELETE (data); 483 1.1 christos } 484 1.1 christos 485 1.1 christos /* Prepare to write out a file. */ 486 1.1 christos 487 1.1 christos static void * 488 1.1 christos simple_object_coff_start_write (void *attributes_data, 489 1.1 christos const char **errmsg ATTRIBUTE_UNUSED, 490 1.1 christos int *err ATTRIBUTE_UNUSED) 491 1.1 christos { 492 1.1 christos struct simple_object_coff_attributes *attrs = 493 1.1 christos (struct simple_object_coff_attributes *) attributes_data; 494 1.1 christos struct simple_object_coff_attributes *ret; 495 1.1 christos 496 1.1 christos /* We're just going to record the attributes, but we need to make a 497 1.1 christos copy because the user may delete them. */ 498 1.1 christos ret = XNEW (struct simple_object_coff_attributes); 499 1.1 christos *ret = *attrs; 500 1.1 christos return ret; 501 1.1 christos } 502 1.1 christos 503 1.1 christos /* Write out a COFF filehdr. */ 504 1.1 christos 505 1.1 christos static int 506 1.1 christos simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor, 507 1.1 christos unsigned int nscns, size_t symtab_offset, 508 1.1 christos unsigned int nsyms, const char **errmsg, 509 1.1 christos int *err) 510 1.1 christos { 511 1.1 christos struct simple_object_coff_attributes *attrs = 512 1.1 christos (struct simple_object_coff_attributes *) sobj->data; 513 1.1 christos unsigned char hdrbuf[sizeof (struct external_filehdr)]; 514 1.1 christos unsigned char *hdr; 515 1.1 christos void (*set_16) (unsigned char *, unsigned short); 516 1.1 christos void (*set_32) (unsigned char *, unsigned int); 517 1.1 christos 518 1.1 christos hdr = &hdrbuf[0]; 519 1.1 christos 520 1.1 christos set_16 = (attrs->is_big_endian 521 1.1 christos ? simple_object_set_big_16 522 1.1 christos : simple_object_set_little_16); 523 1.1 christos set_32 = (attrs->is_big_endian 524 1.1 christos ? simple_object_set_big_32 525 1.1 christos : simple_object_set_little_32); 526 1.1 christos 527 1.1 christos memset (hdr, 0, sizeof (struct external_filehdr)); 528 1.1 christos 529 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); 530 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); 531 1.1 christos /* f_timdat left as zero. */ 532 1.1 christos set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset); 533 1.1 christos set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms); 534 1.1 christos /* f_opthdr left as zero. */ 535 1.1 christos set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags); 536 1.1 christos 537 1.1 christos return simple_object_internal_write (descriptor, 0, hdrbuf, 538 1.1 christos sizeof (struct external_filehdr), 539 1.1 christos errmsg, err); 540 1.1 christos } 541 1.1 christos 542 1.1 christos /* Write out a COFF section header. */ 543 1.1 christos 544 1.1 christos static int 545 1.1 christos simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor, 546 1.1 christos const char *name, size_t *name_offset, 547 1.1 christos off_t scnhdr_offset, size_t scnsize, 548 1.1 christos off_t offset, unsigned int align, 549 1.1 christos const char **errmsg, int *err) 550 1.1 christos { 551 1.1 christos struct simple_object_coff_attributes *attrs = 552 1.1 christos (struct simple_object_coff_attributes *) sobj->data; 553 1.1 christos void (*set_32) (unsigned char *, unsigned int); 554 1.1 christos unsigned char hdrbuf[sizeof (struct external_scnhdr)]; 555 1.1 christos unsigned char *hdr; 556 1.1 christos size_t namelen; 557 1.1 christos unsigned int flags; 558 1.1 christos 559 1.1 christos set_32 = (attrs->is_big_endian 560 1.1 christos ? simple_object_set_big_32 561 1.1 christos : simple_object_set_little_32); 562 1.1 christos 563 1.1 christos memset (hdrbuf, 0, sizeof hdrbuf); 564 1.1 christos hdr = &hdrbuf[0]; 565 1.1 christos 566 1.1 christos namelen = strlen (name); 567 1.1 christos if (namelen <= SCNNMLEN) 568 1.1 christos strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name, 569 1.1 christos SCNNMLEN); 570 1.1 christos else 571 1.1 christos { 572 1.1 christos snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name), 573 1.1 christos SCNNMLEN, "/%lu", (unsigned long) *name_offset); 574 1.1 christos *name_offset += namelen + 1; 575 1.1 christos } 576 1.1 christos 577 1.1 christos /* s_paddr left as zero. */ 578 1.1 christos /* s_vaddr left as zero. */ 579 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize); 580 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset); 581 1.1 christos /* s_relptr left as zero. */ 582 1.1 christos /* s_lnnoptr left as zero. */ 583 1.1 christos /* s_nreloc left as zero. */ 584 1.1 christos /* s_nlnno left as zero. */ 585 1.1 christos flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED 586 1.1 christos | IMAGE_SCN_MEM_READ); 587 1.1 christos /* PE can represent alignment up to 13. */ 588 1.1 christos if (align > 13) 589 1.1 christos align = 13; 590 1.1 christos flags |= IMAGE_SCN_ALIGN_POWER_CONST(align); 591 1.1 christos set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags); 592 1.1 christos 593 1.1 christos return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, 594 1.1 christos sizeof (struct external_scnhdr), 595 1.1 christos errmsg, err); 596 1.1 christos } 597 1.1 christos 598 1.1 christos /* Write out a complete COFF file. */ 599 1.1 christos 600 1.1 christos static const char * 601 1.1 christos simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, 602 1.1 christos int *err) 603 1.1 christos { 604 1.1 christos struct simple_object_coff_attributes *attrs = 605 1.1 christos (struct simple_object_coff_attributes *) sobj->data; 606 1.1 christos unsigned int nscns, secnum; 607 1.1 christos simple_object_write_section *section; 608 1.1 christos off_t scnhdr_offset; 609 1.1 christos size_t symtab_offset; 610 1.1 christos off_t secsym_offset; 611 1.1 christos unsigned int nsyms; 612 1.1 christos size_t offset; 613 1.1 christos size_t name_offset; 614 1.1 christos const char *errmsg; 615 1.1 christos unsigned char strsizebuf[4]; 616 1.1 christos /* The interface doesn't give us access to the name of the input file 617 1.1 christos yet. We want to use its basename for the FILE symbol. This is 618 1.1 christos what 'gas' uses when told to assemble from stdin. */ 619 1.1 christos const char *source_filename = "fake"; 620 1.1 christos size_t sflen; 621 1.1 christos union 622 1.1 christos { 623 1.1 christos struct external_syment sym; 624 1.1 christos union external_auxent aux; 625 1.1 christos } syms[2]; 626 1.1 christos void (*set_16) (unsigned char *, unsigned short); 627 1.1 christos void (*set_32) (unsigned char *, unsigned int); 628 1.1 christos 629 1.1 christos set_16 = (attrs->is_big_endian 630 1.1 christos ? simple_object_set_big_16 631 1.1 christos : simple_object_set_little_16); 632 1.1 christos set_32 = (attrs->is_big_endian 633 1.1 christos ? simple_object_set_big_32 634 1.1 christos : simple_object_set_little_32); 635 1.1 christos 636 1.1 christos nscns = 0; 637 1.1 christos for (section = sobj->sections; section != NULL; section = section->next) 638 1.1 christos ++nscns; 639 1.1 christos 640 1.1 christos scnhdr_offset = sizeof (struct external_filehdr); 641 1.1 christos offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr); 642 1.1 christos name_offset = 4; 643 1.1 christos for (section = sobj->sections; section != NULL; section = section->next) 644 1.1 christos { 645 1.1 christos size_t mask; 646 1.1 christos size_t new_offset; 647 1.1 christos size_t scnsize; 648 1.1 christos struct simple_object_write_section_buffer *buffer; 649 1.1 christos 650 1.1 christos mask = (1U << section->align) - 1; 651 1.1 christos new_offset = offset & mask; 652 1.1 christos new_offset &= ~ mask; 653 1.1 christos while (new_offset > offset) 654 1.1 christos { 655 1.1 christos unsigned char zeroes[16]; 656 1.1 christos size_t write; 657 1.1 christos 658 1.1 christos memset (zeroes, 0, sizeof zeroes); 659 1.1 christos write = new_offset - offset; 660 1.1 christos if (write > sizeof zeroes) 661 1.1 christos write = sizeof zeroes; 662 1.1 christos if (!simple_object_internal_write (descriptor, offset, zeroes, write, 663 1.1 christos &errmsg, err)) 664 1.1 christos return errmsg; 665 1.1 christos } 666 1.1 christos 667 1.1 christos scnsize = 0; 668 1.1 christos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 669 1.1 christos { 670 1.1 christos if (!simple_object_internal_write (descriptor, offset + scnsize, 671 1.1 christos ((const unsigned char *) 672 1.1 christos buffer->buffer), 673 1.1 christos buffer->size, &errmsg, err)) 674 1.1 christos return errmsg; 675 1.1 christos scnsize += buffer->size; 676 1.1 christos } 677 1.1 christos 678 1.1 christos if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name, 679 1.1 christos &name_offset, scnhdr_offset, 680 1.1 christos scnsize, offset, section->align, 681 1.1 christos &errmsg, err)) 682 1.1 christos return errmsg; 683 1.1 christos 684 1.1 christos scnhdr_offset += sizeof (struct external_scnhdr); 685 1.1 christos offset += scnsize; 686 1.1 christos } 687 1.1 christos 688 1.1 christos /* Symbol table is always half-word aligned. */ 689 1.1 christos offset += (offset & 1); 690 1.1 christos /* There is a file symbol and a section symbol per section, 691 1.1 christos and each of these has a single auxiliary symbol following. */ 692 1.1 christos nsyms = 2 * (nscns + 1); 693 1.1 christos symtab_offset = offset; 694 1.1 christos /* Advance across space reserved for symbol table to locate 695 1.1 christos start of string table. */ 696 1.1 christos offset += nsyms * sizeof (struct external_syment); 697 1.1 christos 698 1.1 christos /* Write out file symbol. */ 699 1.1 christos memset (&syms[0], 0, sizeof (syms)); 700 1.1 christos strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); 701 1.1 christos set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); 702 1.1 christos set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 703 1.1 christos syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; 704 1.1 christos syms[0].sym.e_numaux[0] = 1; 705 1.1 christos /* The name need not be nul-terminated if it fits into the x_fname field 706 1.1 christos directly, but must be if it has to be placed into the string table. */ 707 1.1 christos sflen = strlen (source_filename); 708 1.1 christos if (sflen <= E_FILNMLEN) 709 1.1 christos memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); 710 1.1 christos else 711 1.1 christos { 712 1.1 christos set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); 713 1.1 christos if (!simple_object_internal_write (descriptor, offset + name_offset, 714 1.1 christos ((const unsigned char *) 715 1.1 christos source_filename), 716 1.1 christos sflen + 1, &errmsg, err)) 717 1.1 christos return errmsg; 718 1.1 christos name_offset += strlen (source_filename) + 1; 719 1.1 christos } 720 1.1 christos if (!simple_object_internal_write (descriptor, symtab_offset, 721 1.1 christos (const unsigned char *) &syms[0], 722 1.1 christos sizeof (syms), &errmsg, err)) 723 1.1 christos return errmsg; 724 1.1 christos 725 1.1 christos /* Write the string table length, followed by the strings and section 726 1.1 christos symbols in step with each other. */ 727 1.1 christos set_32 (strsizebuf, name_offset); 728 1.1 christos if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, 729 1.1 christos &errmsg, err)) 730 1.1 christos return errmsg; 731 1.1 christos 732 1.1 christos name_offset = 4; 733 1.1 christos secsym_offset = symtab_offset + sizeof (syms); 734 1.1 christos memset (&syms[0], 0, sizeof (syms)); 735 1.1 christos set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 736 1.1 christos syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; 737 1.1 christos syms[0].sym.e_numaux[0] = 1; 738 1.1 christos secnum = 1; 739 1.1 christos 740 1.1 christos for (section = sobj->sections; section != NULL; section = section->next) 741 1.1 christos { 742 1.1 christos size_t namelen; 743 1.1 christos size_t scnsize; 744 1.1 christos struct simple_object_write_section_buffer *buffer; 745 1.1 christos 746 1.1 christos namelen = strlen (section->name); 747 1.1 christos set_16 (&syms[0].sym.e_scnum[0], secnum++); 748 1.1 christos scnsize = 0; 749 1.1 christos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 750 1.1 christos scnsize += buffer->size; 751 1.1 christos set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); 752 1.1 christos if (namelen > SCNNMLEN) 753 1.1 christos { 754 1.1 christos set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); 755 1.1 christos set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); 756 1.1 christos if (!simple_object_internal_write (descriptor, offset + name_offset, 757 1.1 christos ((const unsigned char *) 758 1.1 christos section->name), 759 1.1 christos namelen + 1, &errmsg, err)) 760 1.1 christos return errmsg; 761 1.1 christos name_offset += namelen + 1; 762 1.1 christos } 763 1.1 christos else 764 1.1 christos { 765 1.1 christos memcpy (&syms[0].sym.e.e_name[0], section->name, 766 1.1 christos strlen (section->name)); 767 1.1 christos memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, 768 1.1 christos E_SYMNMLEN - strlen (section->name)); 769 1.1 christos } 770 1.1 christos 771 1.1 christos if (!simple_object_internal_write (descriptor, secsym_offset, 772 1.1 christos (const unsigned char *) &syms[0], 773 1.1 christos sizeof (syms), &errmsg, err)) 774 1.1 christos return errmsg; 775 1.1 christos secsym_offset += sizeof (syms); 776 1.1 christos } 777 1.1 christos 778 1.1 christos if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, 779 1.1 christos symtab_offset, nsyms, &errmsg, err)) 780 1.1 christos return errmsg; 781 1.1 christos 782 1.1 christos return NULL; 783 1.1 christos } 784 1.1 christos 785 1.1 christos /* Release the private data for an simple_object_write structure. */ 786 1.1 christos 787 1.1 christos static void 788 1.1 christos simple_object_coff_release_write (void *data) 789 1.1 christos { 790 1.1 christos XDELETE (data); 791 1.1 christos } 792 1.1 christos 793 1.1 christos /* The COFF functions. */ 794 1.1 christos 795 1.1 christos const struct simple_object_functions simple_object_coff_functions = 796 1.1 christos { 797 1.1 christos simple_object_coff_match, 798 1.1 christos simple_object_coff_find_sections, 799 1.1 christos simple_object_coff_fetch_attributes, 800 1.1 christos simple_object_coff_release_read, 801 1.1 christos simple_object_coff_attributes_merge, 802 1.1 christos simple_object_coff_release_attributes, 803 1.1 christos simple_object_coff_start_write, 804 1.1 christos simple_object_coff_write_to_file, 805 1.7 christos simple_object_coff_release_write, 806 1.7 christos NULL 807 1.1 christos }; 808