1 1.1 mrg /* simple-object-coff.c -- routines to manipulate COFF object files. 2 1.9 mrg Copyright (C) 2010-2022 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.6 mrg simple_object_coff_release_write, 804 1.6 mrg NULL 805 1.1 mrg }; 806