1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/mman.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <libgen.h> 33 #include <errno.h> 34 #include <libelf.h> 35 #include <stdio.h> 36 #include <strings.h> 37 #include <msg.h> 38 #include <machdep.h> 39 #include <_libelf.h> 40 #include <_elfwrap.h> 41 42 /* 43 * This module is compiled to support 32-bit and 64-bit class objects. Define 44 * the necessary interfaces for these classes. 45 */ 46 #if defined(_ELF64) 47 #define input input64 48 #define output output64 49 #else 50 #define input input32 51 #define output output32 52 #endif 53 54 static StdSec_t StdSecs[] = { 55 { MSG_ORIG(MSG_SCN_SYMTAB), SHT_SYMTAB, 0 }, 56 { MSG_ORIG(MSG_SCN_STRTAB), SHT_STRTAB, SHF_STRINGS}, 57 { MSG_ORIG(MSG_SCN_SHSTRTAB), SHT_STRTAB, SHF_STRINGS}, 58 { NULL, 0, 0 } 59 }; 60 61 /* 62 * Process all input files. These contain the data that will be assigned to a 63 * new ELF section. 64 */ 65 int 66 input(int argc, char **argv, const char *prog, const char *ofile, 67 ObjDesc_t *odp) 68 { 69 OutSec_t outsec; 70 StdSec_t *stdsecs; 71 size_t ndx, cnt; 72 int ret = 0, fd = -1; 73 74 /* 75 * Make sure we have access to read each input file, and prepare an 76 * output section descriptor for each. Note, we assign section indexes 77 * starting at 1, as section index 0 is special, and is created by 78 * libelf. 79 */ 80 for (ndx = 1; argc; argc--, argv++, ndx++) { 81 char *file = *argv; 82 struct stat status; 83 size_t namesz; 84 85 /* 86 * Close any previously opened file. 87 */ 88 if (fd != -1) 89 (void) close(fd); 90 91 /* 92 * Identify the section. 93 */ 94 outsec.os_name = basename(file); 95 outsec.os_type = SHT_PROGBITS; 96 outsec.os_flags = SHF_ALLOC; 97 outsec.os_ndx = ndx; 98 99 if ((fd = open(file, O_RDONLY)) == -1) { 100 int err = errno; 101 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 102 prog, file, strerror(err)); 103 ret = 1; 104 continue; 105 } 106 if (fstat(fd, &status) == -1) { 107 int err = errno; 108 (void) fprintf(stderr, MSG_INTL(MSG_ERR_FSTAT), 109 prog, file, strerror(err)); 110 ret = 1; 111 continue; 112 } 113 114 if ((outsec.os_size = status.st_size) == 0) { 115 (void) fprintf(stderr, MSG_INTL(MSG_WARN_ZERO), 116 prog, file); 117 continue; 118 } 119 120 if ((outsec.os_addr = mmap(0, outsec.os_size, PROT_READ, 121 MAP_PRIVATE, fd, 0)) == MAP_FAILED) { 122 int err = errno; 123 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MMAP), 124 prog, file, strerror(err)); 125 ret = 1; 126 continue; 127 } 128 129 if (alist_append(&(odp->od_outsecs), &outsec, sizeof (OutSec_t), 130 AL_CNT_WOSECS) == 0) { 131 int err = errno; 132 (void) fprintf(stderr, MSG_INTL(MSG_ERR_ALLOC), 133 prog, file, strerror(err)); 134 return (1); 135 } 136 137 /* 138 * Each data section contributes: 139 * 140 * i. its basename, prefixed with a "dot", to the .shstrtab. 141 * ii. a section symbol. 142 * iii. a data symbol, using the basename, with an 143 * appended "_data" string. 144 * iv. a data size symbol, using the basename with an 145 * appended "_size" string. 146 */ 147 namesz = strlen(outsec.os_name) + 1; 148 149 odp->od_symtabno += 3; 150 odp->od_strtabsz += (namesz + MSG_STR_START_SIZE); 151 odp->od_strtabsz += (namesz + MSG_STR_END_SIZE); 152 odp->od_shstrtabsz += (namesz + MSG_STR_DOT_SIZE); 153 } 154 155 if (fd != -1) 156 (void) close(fd); 157 158 /* 159 * If an error occurred, or no input files contributed data, bail now. 160 */ 161 if (ret || (odp->od_outsecs == NULL)) 162 return (1); 163 164 /* 165 * Create section descriptors for .symtab, .strtab, and .shstrtab. 166 */ 167 for (cnt = 0, stdsecs = &StdSecs[cnt]; stdsecs->ss_name; cnt++, 168 ndx++, stdsecs = &StdSecs[cnt]) { 169 170 /* 171 * Identify the section. 172 */ 173 outsec.os_name = stdsecs->ss_name; 174 outsec.os_type = stdsecs->ss_type; 175 outsec.os_flags = stdsecs->ss_flags; 176 outsec.os_ndx = ndx; 177 outsec.os_size = 0; 178 outsec.os_addr = 0; 179 180 if (alist_append(&(odp->od_outsecs), &outsec, sizeof (OutSec_t), 181 AL_CNT_WOSECS) == 0) { 182 int err = errno; 183 (void) fprintf(stderr, MSG_INTL(MSG_ERR_ALLOC), 184 prog, outsec.os_name, strerror(err)); 185 return (1); 186 } 187 188 /* 189 * Each standard section contributes: 190 * 191 * i. its section name to the .shstrtab. 192 * ii. a section symbol. 193 */ 194 odp->od_symtabno++; 195 odp->od_shstrtabsz += (strlen(outsec.os_name) + 1); 196 } 197 198 /* 199 * The symbol table requires an initial NULL entry and a following 200 * FILE entry. Both string tables require an initial NULL byte. 201 * The .strtab requires room for the output file name (STT_FILE). 202 */ 203 odp->od_symtabno += 2; 204 odp->od_strtabsz += strlen(ofile) + 2; 205 odp->od_shstrtabsz++; 206 207 return (0); 208 } 209 210 /* 211 * Having captured all input data, create the output file. 212 */ 213 int 214 output(const char *prog, int fd, const char *ofile, ushort_t mach, 215 ObjDesc_t *odp) 216 { 217 Aliste off; 218 Elf *melf, *oelf; 219 Ehdr *ehdr; 220 Sym *symtab, *secsymtabent, *glbsymtabent; 221 char *strtab, *strtabent, *shstrtab, *shstrtabent; 222 OutSec_t *outsec, *outsymtab, *outstrtab, *outshstrtab; 223 size_t len; 224 TargDesc_t tdesc; 225 226 /* 227 * Obtain any target specific ELF information. 228 */ 229 if (mach == 0) 230 mach = M_MACH; 231 232 switch (mach) { 233 #if !defined(lint) 234 case EM_SPARC: 235 target_init_sparc(&tdesc); 236 break; 237 case EM_SPARCV9: 238 target_init_sparcv9(&tdesc); 239 break; 240 case EM_386: 241 target_init_i386(&tdesc); 242 break; 243 case EM_AMD64: 244 target_init_amd64(&tdesc); 245 break; 246 #else 247 default: 248 target_init(&tdesc); 249 break; 250 #endif 251 } 252 /* 253 * Create a new ELF descriptor for the new output file. 254 */ 255 if ((oelf = elf_begin(fd, ELF_C_WRITE, 0)) == NULL) { 256 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog, 257 elf_errmsg(elf_errno())); 258 return (1); 259 } 260 261 /* 262 * Create and initialize the new ELF header. 263 */ 264 if ((ehdr = elf_newehdr(oelf)) == NULL) { 265 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWEHDR), prog, 266 elf_errmsg(elf_errno())); 267 return (1); 268 } 269 270 /* 271 * Note, the ELF header is initialized to reflect the host running 272 * elfwrap(1) rather than the target. Using host byte order allows 273 * elfwrap(1) to create the object data. Prior to the final update, 274 * the output ELF header is modified to reflect the target, causing 275 * libelf to produce the output object using the correct byte order 276 * and other target information. 277 */ 278 ehdr->e_ident[EI_DATA] = M_DATA; 279 ehdr->e_type = ET_REL; 280 ehdr->e_version = EV_CURRENT; 281 282 /* 283 * Create the required number of new sections, their associated section 284 * header, and an initial data buffer. 285 */ 286 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) { 287 Elf_Scn *scn; 288 Elf_Data *data; 289 Shdr *shdr; 290 291 if ((scn = elf_newscn(oelf)) == NULL) { 292 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWSCN), 293 prog, outsec->os_name, elf_errmsg(elf_errno())); 294 return (1); 295 } 296 if ((shdr = elf_getshdr(scn)) == NULL) { 297 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR), 298 prog, outsec->os_name, elf_errmsg(elf_errno())); 299 return (1); 300 } 301 302 /* 303 * Assign the section type and flags. 304 */ 305 shdr->sh_type = outsec->os_type; 306 shdr->sh_flags = outsec->os_flags; 307 308 if ((data = elf_newdata(scn)) == NULL) { 309 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWDATA), 310 prog, outsec->os_name, elf_errmsg(elf_errno())); 311 return (1); 312 } 313 314 switch (shdr->sh_type) { 315 case SHT_PROGBITS: 316 /* 317 * If this is a PROGBITS section, then the data 318 * originates from an input file. Assign the data 319 * buffer to this input file and provide a default 320 * alignment. 321 */ 322 data->d_buf = outsec->os_addr; 323 data->d_type = ELF_T_BYTE; 324 data->d_size = outsec->os_size; 325 data->d_align = tdesc.td_align; 326 break; 327 328 case SHT_SYMTAB: 329 /* 330 * If this is the symbol table, use the symbol count to 331 * reserve sufficient space for the symbols we need. 332 */ 333 data->d_buf = 0; 334 data->d_type = ELF_T_SYM; 335 data->d_size = (odp->od_symtabno * tdesc.td_symsz); 336 data->d_align = tdesc.td_align; 337 break; 338 339 case SHT_STRTAB: 340 /* 341 * If this is a string table, use the table size to 342 * reserve sufficient space for the strings we need. 343 */ 344 data->d_buf = 0; 345 data->d_type = ELF_T_BYTE; 346 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB))) 347 data->d_size = odp->od_shstrtabsz; 348 else 349 data->d_size = odp->od_strtabsz; 350 data->d_align = 1; 351 break; 352 } 353 } 354 355 /* 356 * Write the ELF data into a memory image. 357 */ 358 if ((elf_update(oelf, ELF_C_WRIMAGE)) == -1) { 359 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog, 360 elf_errmsg(elf_errno())); 361 return (1); 362 } 363 364 /* 365 * Assign an ELF descriptor to the memory image. 366 */ 367 if ((melf = elf_begin(0, ELF_C_IMAGE, oelf)) == NULL) { 368 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog, 369 elf_errmsg(elf_errno())); 370 return (1); 371 } 372 373 /* 374 * Get the ELF header from the memory image. 375 */ 376 if ((ehdr = elf_getehdr(melf)) == NULL) { 377 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR), prog, 378 elf_errmsg(elf_errno())); 379 return (1); 380 } 381 382 /* 383 * Read the section header and data from the new sections of the 384 * memory image. 385 */ 386 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) { 387 Elf_Scn *scn; 388 Shdr *shdr; 389 390 if ((scn = elf_getscn(melf, outsec->os_ndx)) == NULL) { 391 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSCN), 392 prog, outsec->os_name, elf_errmsg(elf_errno())); 393 return (1); 394 } 395 if ((outsec->os_shdr = shdr = elf_getshdr(scn)) == NULL) { 396 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR), 397 prog, outsec->os_name, elf_errmsg(elf_errno())); 398 return (1); 399 } 400 if ((outsec->os_data = elf_getdata(scn, NULL)) == NULL) { 401 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA), 402 prog, outsec->os_name, elf_errmsg(elf_errno())); 403 return (1); 404 } 405 406 if (shdr->sh_type == SHT_PROGBITS) 407 continue; 408 409 /* 410 * Remember the symbol table and string tables, so that they 411 * can be filled in later. 412 */ 413 if (shdr->sh_type == SHT_SYMTAB) { 414 outsymtab = outsec; 415 symtab = (Sym *)outsec->os_data->d_buf; 416 } else if (shdr->sh_type == SHT_STRTAB) { 417 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB))) { 418 outshstrtab = outsec; 419 shstrtab = (char *)outsec->os_data->d_buf; 420 } else { 421 outstrtab = outsec; 422 strtab = (char *)outsec->os_data->d_buf; 423 } 424 } 425 } 426 427 /* 428 * Update the ELF header with the .shstrtab index. 429 */ 430 ehdr->e_shstrndx = outshstrtab->os_ndx; 431 432 /* 433 * Set up the string table entries, and skip the first byte. 434 */ 435 strtabent = strtab; 436 strtabent++; 437 438 shstrtabent = shstrtab; 439 shstrtabent++; 440 441 /* 442 * Skip the first symbol table entry. Write a FILE entry, and set 443 * up for adding sections and data symbols. Associate the symbol 444 * table with the string table. 445 */ 446 secsymtabent = symtab; 447 secsymtabent++; 448 secsymtabent->st_name = (strtabent - strtab); 449 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_NOTYPE); 450 secsymtabent->st_shndx = SHN_ABS; 451 secsymtabent++; 452 453 glbsymtabent = secsymtabent; 454 glbsymtabent += alist_nitems(odp->od_outsecs); 455 456 outsymtab->os_shdr->sh_link = outstrtab->os_ndx; 457 458 /* 459 * Write the output file name to the .strtab. 460 */ 461 len = strlen(ofile) + 1; 462 (void) memcpy(strtabent, ofile, len); 463 strtabent += len; 464 465 /* 466 * Rescan all the new sections, adding symbols and strings as required. 467 */ 468 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) { 469 size_t alen; 470 471 /* 472 * Create a section symbol. 473 */ 474 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_SECTION); 475 secsymtabent->st_shndx = outsec->os_ndx; 476 secsymtabent++; 477 478 /* 479 * Store the section name, (with an appended "." if the section 480 * name is derived from the input file name), and point the 481 * section header to this name. 482 */ 483 outsec->os_shdr->sh_name = (shstrtabent - shstrtab); 484 485 if (outsec->os_shdr->sh_type == SHT_PROGBITS) { 486 (void) memcpy(shstrtabent, MSG_ORIG(MSG_STR_DOT), 487 MSG_STR_DOT_SIZE); 488 shstrtabent += MSG_STR_DOT_SIZE; 489 } 490 491 len = strlen(outsec->os_name) + 1; 492 (void) memcpy(shstrtabent, outsec->os_name, len); 493 shstrtabent += len; 494 495 if (outsec->os_shdr->sh_type != SHT_PROGBITS) 496 continue; 497 498 /* 499 * Add a symbol pointing to this PROGBITS section. The value 500 * is the base offset of this section, which can only be 0. 501 * The size of the symbol can be taken straight from the section 502 * header information (that libelf generated). 503 */ 504 glbsymtabent->st_name = (strtabent - strtab); 505 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 506 glbsymtabent->st_shndx = outsec->os_ndx; 507 glbsymtabent->st_size = outsec->os_shdr->sh_size; 508 glbsymtabent++; 509 510 /* 511 * Store this symbol name (with an appended "_data") in the 512 * string table. 513 */ 514 len--; 515 (void) memcpy(strtabent, outsec->os_name, len); 516 strtabent += len; 517 alen = (MSG_STR_START_SIZE + 1); 518 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_START), alen); 519 strtabent += alen; 520 521 /* 522 * Add a symbol indicating the size of this PROGBITS section. 523 */ 524 glbsymtabent->st_name = (strtabent - strtab); 525 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 526 glbsymtabent->st_shndx = outsec->os_ndx; 527 glbsymtabent->st_value = outsec->os_shdr->sh_size; 528 glbsymtabent++; 529 530 /* 531 * Store this symbol name (with an appended "_end") in the 532 * string table. 533 */ 534 (void) memcpy(strtabent, outsec->os_name, len); 535 strtabent += len; 536 alen = (MSG_STR_END_SIZE + 1); 537 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_END), alen); 538 strtabent += alen; 539 } 540 541 /* 542 * Update the .symtab section header with the index of the first 543 * non-local symbol. The only locals written are the section symbols. 544 */ 545 outsymtab->os_shdr->sh_info = (secsymtabent - symtab); 546 547 /* 548 * Having updated the image following the byte order of elfwrap(), seed 549 * the ELF header with the appropriate target information. 550 */ 551 ehdr->e_ident[EI_CLASS] = tdesc.td_class; 552 ehdr->e_ident[EI_DATA] = tdesc.td_data; 553 ehdr->e_machine = tdesc.td_mach; 554 555 /* 556 * If the output relocatable object is targeted to a machine with a 557 * different byte order than the host running elfwrap(1), swap the data 558 * to the target byte order. 559 */ 560 if ((_elf_sys_encoding() != ehdr->e_ident[EI_DATA]) && 561 (_elf_swap_wrimage(melf) != 0)) { 562 (void) fprintf(stderr, MSG_INTL(MSG_ELF_SWAP_WRIMAGE), prog, 563 elf_errmsg(elf_errno())); 564 return (1); 565 } 566 (void) elf_end(melf); 567 568 /* 569 * Finally, write the updated memory image out to disc. 570 */ 571 if ((elf_update(oelf, ELF_C_WRITE)) == -1) { 572 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog, 573 elf_errmsg(elf_errno())); 574 return (1); 575 } 576 (void) elf_end(oelf); 577 578 return (0); 579 } 580