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