1 /* Generate assembler source containing symbol information 2 * 3 * Copyright 2002 by Kai Germaschewski 4 * 5 * This software may be used and distributed according to the terms 6 * of the GNU General Public License, incorporated herein by reference. 7 * 8 * Usage: kallsyms [--all-symbols] [--absolute-percpu] 9 * [--base-relative] in.map > out.S 10 * 11 * Table compression uses all the unused char codes on the symbols and 12 * maps these to the most used substrings (tokens). For instance, it might 13 * map char code 0xF7 to represent "write_" and then in every symbol where 14 * "write_" appears it can be replaced by 0xF7, saving 5 bytes. 15 * The used codes themselves are also placed in the table so that the 16 * decompresion can work without "special cases". 17 * Applied to kernel symbols, this usually produces a compression ratio 18 * of about 50%. 19 * 20 */ 21 22 #include <getopt.h> 23 #include <stdbool.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <ctype.h> 28 #include <limits.h> 29 30 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 31 32 #define _stringify_1(x) #x 33 #define _stringify(x) _stringify_1(x) 34 35 #define KSYM_NAME_LEN 512 36 37 /* 38 * A substantially bigger size than the current maximum. 39 * 40 * It cannot be defined as an expression because it gets stringified 41 * for the fscanf() format string. Therefore, a _Static_assert() is 42 * used instead to maintain the relationship with KSYM_NAME_LEN. 43 */ 44 #define KSYM_NAME_LEN_BUFFER 2048 45 _Static_assert( 46 KSYM_NAME_LEN_BUFFER == KSYM_NAME_LEN * 4, 47 "Please keep KSYM_NAME_LEN_BUFFER in sync with KSYM_NAME_LEN" 48 ); 49 50 struct sym_entry { 51 unsigned long long addr; 52 unsigned int len; 53 unsigned int seq; 54 unsigned int start_pos; 55 unsigned int percpu_absolute; 56 unsigned char sym[]; 57 }; 58 59 struct addr_range { 60 const char *start_sym, *end_sym; 61 unsigned long long start, end; 62 }; 63 64 static unsigned long long _text; 65 static unsigned long long relative_base; 66 static struct addr_range text_ranges[] = { 67 { "_stext", "_etext" }, 68 { "_sinittext", "_einittext" }, 69 }; 70 #define text_range_text (&text_ranges[0]) 71 #define text_range_inittext (&text_ranges[1]) 72 73 static struct addr_range percpu_range = { 74 "__per_cpu_start", "__per_cpu_end", -1ULL, 0 75 }; 76 77 static struct sym_entry **table; 78 static unsigned int table_size, table_cnt; 79 static int all_symbols; 80 static int absolute_percpu; 81 static int base_relative; 82 static int lto_clang; 83 84 static int token_profit[0x10000]; 85 86 /* the table that holds the result of the compression */ 87 static unsigned char best_table[256][2]; 88 static unsigned char best_table_len[256]; 89 90 91 static void usage(void) 92 { 93 fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " 94 "[--base-relative] [--lto-clang] in.map > out.S\n"); 95 exit(1); 96 } 97 98 static char *sym_name(const struct sym_entry *s) 99 { 100 return (char *)s->sym + 1; 101 } 102 103 static bool is_ignored_symbol(const char *name, char type) 104 { 105 /* Symbol names that exactly match to the following are ignored.*/ 106 static const char * const ignored_symbols[] = { 107 /* 108 * Symbols which vary between passes. Passes 1 and 2 must have 109 * identical symbol lists. The kallsyms_* symbols below are 110 * only added after pass 1, they would be included in pass 2 111 * when --all-symbols is specified so exclude them to get a 112 * stable symbol list. 113 */ 114 "kallsyms_addresses", 115 "kallsyms_offsets", 116 "kallsyms_relative_base", 117 "kallsyms_num_syms", 118 "kallsyms_names", 119 "kallsyms_markers", 120 "kallsyms_token_table", 121 "kallsyms_token_index", 122 "kallsyms_seqs_of_names", 123 /* Exclude linker generated symbols which vary between passes */ 124 "_SDA_BASE_", /* ppc */ 125 "_SDA2_BASE_", /* ppc */ 126 NULL 127 }; 128 129 /* Symbol names that begin with the following are ignored.*/ 130 static const char * const ignored_prefixes[] = { 131 "__efistub_", /* arm64 EFI stub namespace */ 132 "__kvm_nvhe_$", /* arm64 local symbols in non-VHE KVM namespace */ 133 "__kvm_nvhe_.L", /* arm64 local symbols in non-VHE KVM namespace */ 134 "__AArch64ADRPThunk_", /* arm64 lld */ 135 "__ARMV5PILongThunk_", /* arm lld */ 136 "__ARMV7PILongThunk_", 137 "__ThumbV7PILongThunk_", 138 "__LA25Thunk_", /* mips lld */ 139 "__microLA25Thunk_", 140 "__kcfi_typeid_", /* CFI type identifiers */ 141 NULL 142 }; 143 144 /* Symbol names that end with the following are ignored.*/ 145 static const char * const ignored_suffixes[] = { 146 "_from_arm", /* arm */ 147 "_from_thumb", /* arm */ 148 "_veneer", /* arm */ 149 NULL 150 }; 151 152 /* Symbol names that contain the following are ignored.*/ 153 static const char * const ignored_matches[] = { 154 ".long_branch.", /* ppc stub */ 155 ".plt_branch.", /* ppc stub */ 156 NULL 157 }; 158 159 const char * const *p; 160 161 for (p = ignored_symbols; *p; p++) 162 if (!strcmp(name, *p)) 163 return true; 164 165 for (p = ignored_prefixes; *p; p++) 166 if (!strncmp(name, *p, strlen(*p))) 167 return true; 168 169 for (p = ignored_suffixes; *p; p++) { 170 int l = strlen(name) - strlen(*p); 171 172 if (l >= 0 && !strcmp(name + l, *p)) 173 return true; 174 } 175 176 for (p = ignored_matches; *p; p++) { 177 if (strstr(name, *p)) 178 return true; 179 } 180 181 if (type == 'U' || type == 'u') 182 return true; 183 /* exclude debugging symbols */ 184 if (type == 'N' || type == 'n') 185 return true; 186 187 if (toupper(type) == 'A') { 188 /* Keep these useful absolute symbols */ 189 if (strcmp(name, "__kernel_syscall_via_break") && 190 strcmp(name, "__kernel_syscall_via_epc") && 191 strcmp(name, "__kernel_sigtramp") && 192 strcmp(name, "__gp")) 193 return true; 194 } 195 196 return false; 197 } 198 199 static void check_symbol_range(const char *sym, unsigned long long addr, 200 struct addr_range *ranges, int entries) 201 { 202 size_t i; 203 struct addr_range *ar; 204 205 for (i = 0; i < entries; ++i) { 206 ar = &ranges[i]; 207 208 if (strcmp(sym, ar->start_sym) == 0) { 209 ar->start = addr; 210 return; 211 } else if (strcmp(sym, ar->end_sym) == 0) { 212 ar->end = addr; 213 return; 214 } 215 } 216 } 217 218 static struct sym_entry *read_symbol(FILE *in) 219 { 220 char name[KSYM_NAME_LEN_BUFFER+1], type; 221 unsigned long long addr; 222 unsigned int len; 223 struct sym_entry *sym; 224 int rc; 225 226 rc = fscanf(in, "%llx %c %" _stringify(KSYM_NAME_LEN_BUFFER) "s\n", &addr, &type, name); 227 if (rc != 3) { 228 if (rc != EOF && fgets(name, ARRAY_SIZE(name), in) == NULL) 229 fprintf(stderr, "Read error or end of file.\n"); 230 return NULL; 231 } 232 if (strlen(name) >= KSYM_NAME_LEN) { 233 fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n" 234 "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", 235 name, strlen(name), KSYM_NAME_LEN); 236 return NULL; 237 } 238 239 if (strcmp(name, "_text") == 0) 240 _text = addr; 241 242 /* Ignore most absolute/undefined (?) symbols. */ 243 if (is_ignored_symbol(name, type)) 244 return NULL; 245 246 check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); 247 check_symbol_range(name, addr, &percpu_range, 1); 248 249 /* include the type field in the symbol name, so that it gets 250 * compressed together */ 251 252 len = strlen(name) + 1; 253 254 sym = malloc(sizeof(*sym) + len + 1); 255 if (!sym) { 256 fprintf(stderr, "kallsyms failure: " 257 "unable to allocate required amount of memory\n"); 258 exit(EXIT_FAILURE); 259 } 260 sym->addr = addr; 261 sym->len = len; 262 sym->sym[0] = type; 263 strcpy(sym_name(sym), name); 264 sym->percpu_absolute = 0; 265 266 return sym; 267 } 268 269 static int symbol_in_range(const struct sym_entry *s, 270 const struct addr_range *ranges, int entries) 271 { 272 size_t i; 273 const struct addr_range *ar; 274 275 for (i = 0; i < entries; ++i) { 276 ar = &ranges[i]; 277 278 if (s->addr >= ar->start && s->addr <= ar->end) 279 return 1; 280 } 281 282 return 0; 283 } 284 285 static int symbol_valid(const struct sym_entry *s) 286 { 287 const char *name = sym_name(s); 288 289 /* if --all-symbols is not specified, then symbols outside the text 290 * and inittext sections are discarded */ 291 if (!all_symbols) { 292 if (symbol_in_range(s, text_ranges, 293 ARRAY_SIZE(text_ranges)) == 0) 294 return 0; 295 /* Corner case. Discard any symbols with the same value as 296 * _etext _einittext; they can move between pass 1 and 2 when 297 * the kallsyms data are added. If these symbols move then 298 * they may get dropped in pass 2, which breaks the kallsyms 299 * rules. 300 */ 301 if ((s->addr == text_range_text->end && 302 strcmp(name, text_range_text->end_sym)) || 303 (s->addr == text_range_inittext->end && 304 strcmp(name, text_range_inittext->end_sym))) 305 return 0; 306 } 307 308 return 1; 309 } 310 311 /* remove all the invalid symbols from the table */ 312 static void shrink_table(void) 313 { 314 unsigned int i, pos; 315 316 pos = 0; 317 for (i = 0; i < table_cnt; i++) { 318 if (symbol_valid(table[i])) { 319 if (pos != i) 320 table[pos] = table[i]; 321 pos++; 322 } else { 323 free(table[i]); 324 } 325 } 326 table_cnt = pos; 327 328 /* When valid symbol is not registered, exit to error */ 329 if (!table_cnt) { 330 fprintf(stderr, "No valid symbol.\n"); 331 exit(1); 332 } 333 } 334 335 static void read_map(const char *in) 336 { 337 FILE *fp; 338 struct sym_entry *sym; 339 340 fp = fopen(in, "r"); 341 if (!fp) { 342 perror(in); 343 exit(1); 344 } 345 346 while (!feof(fp)) { 347 sym = read_symbol(fp); 348 if (!sym) 349 continue; 350 351 sym->start_pos = table_cnt; 352 353 if (table_cnt >= table_size) { 354 table_size += 10000; 355 table = realloc(table, sizeof(*table) * table_size); 356 if (!table) { 357 fprintf(stderr, "out of memory\n"); 358 fclose(fp); 359 exit (1); 360 } 361 } 362 363 table[table_cnt++] = sym; 364 } 365 366 fclose(fp); 367 } 368 369 static void output_label(const char *label) 370 { 371 printf(".globl %s\n", label); 372 printf("\tALGN\n"); 373 printf("%s:\n", label); 374 } 375 376 /* Provide proper symbols relocatability by their '_text' relativeness. */ 377 static void output_address(unsigned long long addr) 378 { 379 if (_text <= addr) 380 printf("\tPTR\t_text + %#llx\n", addr - _text); 381 else 382 printf("\tPTR\t_text - %#llx\n", _text - addr); 383 } 384 385 /* uncompress a compressed symbol. When this function is called, the best table 386 * might still be compressed itself, so the function needs to be recursive */ 387 static int expand_symbol(const unsigned char *data, int len, char *result) 388 { 389 int c, rlen, total=0; 390 391 while (len) { 392 c = *data; 393 /* if the table holds a single char that is the same as the one 394 * we are looking for, then end the search */ 395 if (best_table[c][0]==c && best_table_len[c]==1) { 396 *result++ = c; 397 total++; 398 } else { 399 /* if not, recurse and expand */ 400 rlen = expand_symbol(best_table[c], best_table_len[c], result); 401 total += rlen; 402 result += rlen; 403 } 404 data++; 405 len--; 406 } 407 *result=0; 408 409 return total; 410 } 411 412 static int symbol_absolute(const struct sym_entry *s) 413 { 414 return s->percpu_absolute; 415 } 416 417 static char * s_name(char *buf) 418 { 419 /* Skip the symbol type */ 420 return buf + 1; 421 } 422 423 static void cleanup_symbol_name(char *s) 424 { 425 char *p; 426 427 if (!lto_clang) 428 return; 429 430 /* 431 * ASCII[.] = 2e 432 * ASCII[0-9] = 30,39 433 * ASCII[A-Z] = 41,5a 434 * ASCII[_] = 5f 435 * ASCII[a-z] = 61,7a 436 * 437 * As above, replacing '.' with '\0' does not affect the main sorting, 438 * but it helps us with subsorting. 439 */ 440 p = strchr(s, '.'); 441 if (p) 442 *p = '\0'; 443 } 444 445 static int compare_names(const void *a, const void *b) 446 { 447 int ret; 448 char sa_namebuf[KSYM_NAME_LEN]; 449 char sb_namebuf[KSYM_NAME_LEN]; 450 const struct sym_entry *sa = *(const struct sym_entry **)a; 451 const struct sym_entry *sb = *(const struct sym_entry **)b; 452 453 expand_symbol(sa->sym, sa->len, sa_namebuf); 454 expand_symbol(sb->sym, sb->len, sb_namebuf); 455 cleanup_symbol_name(s_name(sa_namebuf)); 456 cleanup_symbol_name(s_name(sb_namebuf)); 457 ret = strcmp(s_name(sa_namebuf), s_name(sb_namebuf)); 458 if (!ret) { 459 if (sa->addr > sb->addr) 460 return 1; 461 else if (sa->addr < sb->addr) 462 return -1; 463 464 /* keep old order */ 465 return (int)(sa->seq - sb->seq); 466 } 467 468 return ret; 469 } 470 471 static void sort_symbols_by_name(void) 472 { 473 qsort(table, table_cnt, sizeof(table[0]), compare_names); 474 } 475 476 static void write_src(void) 477 { 478 unsigned int i, k, off; 479 unsigned int best_idx[256]; 480 unsigned int *markers; 481 char buf[KSYM_NAME_LEN]; 482 483 printf("#include <asm/bitsperlong.h>\n"); 484 printf("#if BITS_PER_LONG == 64\n"); 485 printf("#define PTR .quad\n"); 486 printf("#define ALGN .balign 8\n"); 487 printf("#else\n"); 488 printf("#define PTR .long\n"); 489 printf("#define ALGN .balign 4\n"); 490 printf("#endif\n"); 491 492 printf("\t.section .rodata, \"a\"\n"); 493 494 if (!base_relative) 495 output_label("kallsyms_addresses"); 496 else 497 output_label("kallsyms_offsets"); 498 499 for (i = 0; i < table_cnt; i++) { 500 if (base_relative) { 501 /* 502 * Use the offset relative to the lowest value 503 * encountered of all relative symbols, and emit 504 * non-relocatable fixed offsets that will be fixed 505 * up at runtime. 506 */ 507 508 long long offset; 509 int overflow; 510 511 if (!absolute_percpu) { 512 offset = table[i]->addr - relative_base; 513 overflow = (offset < 0 || offset > UINT_MAX); 514 } else if (symbol_absolute(table[i])) { 515 offset = table[i]->addr; 516 overflow = (offset < 0 || offset > INT_MAX); 517 } else { 518 offset = relative_base - table[i]->addr - 1; 519 overflow = (offset < INT_MIN || offset >= 0); 520 } 521 if (overflow) { 522 fprintf(stderr, "kallsyms failure: " 523 "%s symbol value %#llx out of range in relative mode\n", 524 symbol_absolute(table[i]) ? "absolute" : "relative", 525 table[i]->addr); 526 exit(EXIT_FAILURE); 527 } 528 expand_symbol(table[i]->sym, table[i]->len, buf); 529 printf("\t.long\t%#x /* %s */\n", (int)offset, buf); 530 } else if (!symbol_absolute(table[i])) { 531 output_address(table[i]->addr); 532 } else { 533 printf("\tPTR\t%#llx\n", table[i]->addr); 534 } 535 } 536 printf("\n"); 537 538 if (base_relative) { 539 output_label("kallsyms_relative_base"); 540 output_address(relative_base); 541 printf("\n"); 542 } 543 544 output_label("kallsyms_num_syms"); 545 printf("\t.long\t%u\n", table_cnt); 546 printf("\n"); 547 548 /* table of offset markers, that give the offset in the compressed stream 549 * every 256 symbols */ 550 markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); 551 if (!markers) { 552 fprintf(stderr, "kallsyms failure: " 553 "unable to allocate required memory\n"); 554 exit(EXIT_FAILURE); 555 } 556 557 output_label("kallsyms_names"); 558 off = 0; 559 for (i = 0; i < table_cnt; i++) { 560 if ((i & 0xFF) == 0) 561 markers[i >> 8] = off; 562 table[i]->seq = i; 563 564 /* There cannot be any symbol of length zero. */ 565 if (table[i]->len == 0) { 566 fprintf(stderr, "kallsyms failure: " 567 "unexpected zero symbol length\n"); 568 exit(EXIT_FAILURE); 569 } 570 571 /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ 572 if (table[i]->len > 0x3FFF) { 573 fprintf(stderr, "kallsyms failure: " 574 "unexpected huge symbol length\n"); 575 exit(EXIT_FAILURE); 576 } 577 578 /* Encode length with ULEB128. */ 579 if (table[i]->len <= 0x7F) { 580 /* Most symbols use a single byte for the length. */ 581 printf("\t.byte 0x%02x", table[i]->len); 582 off += table[i]->len + 1; 583 } else { 584 /* "Big" symbols use two bytes. */ 585 printf("\t.byte 0x%02x, 0x%02x", 586 (table[i]->len & 0x7F) | 0x80, 587 (table[i]->len >> 7) & 0x7F); 588 off += table[i]->len + 2; 589 } 590 for (k = 0; k < table[i]->len; k++) 591 printf(", 0x%02x", table[i]->sym[k]); 592 printf("\n"); 593 } 594 printf("\n"); 595 596 output_label("kallsyms_markers"); 597 for (i = 0; i < ((table_cnt + 255) >> 8); i++) 598 printf("\t.long\t%u\n", markers[i]); 599 printf("\n"); 600 601 free(markers); 602 603 sort_symbols_by_name(); 604 output_label("kallsyms_seqs_of_names"); 605 for (i = 0; i < table_cnt; i++) 606 printf("\t.byte 0x%02x, 0x%02x, 0x%02x\n", 607 (unsigned char)(table[i]->seq >> 16), 608 (unsigned char)(table[i]->seq >> 8), 609 (unsigned char)(table[i]->seq >> 0)); 610 printf("\n"); 611 612 output_label("kallsyms_token_table"); 613 off = 0; 614 for (i = 0; i < 256; i++) { 615 best_idx[i] = off; 616 expand_symbol(best_table[i], best_table_len[i], buf); 617 printf("\t.asciz\t\"%s\"\n", buf); 618 off += strlen(buf) + 1; 619 } 620 printf("\n"); 621 622 output_label("kallsyms_token_index"); 623 for (i = 0; i < 256; i++) 624 printf("\t.short\t%d\n", best_idx[i]); 625 printf("\n"); 626 } 627 628 629 /* table lookup compression functions */ 630 631 /* count all the possible tokens in a symbol */ 632 static void learn_symbol(const unsigned char *symbol, int len) 633 { 634 int i; 635 636 for (i = 0; i < len - 1; i++) 637 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; 638 } 639 640 /* decrease the count for all the possible tokens in a symbol */ 641 static void forget_symbol(const unsigned char *symbol, int len) 642 { 643 int i; 644 645 for (i = 0; i < len - 1; i++) 646 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; 647 } 648 649 /* do the initial token count */ 650 static void build_initial_token_table(void) 651 { 652 unsigned int i; 653 654 for (i = 0; i < table_cnt; i++) 655 learn_symbol(table[i]->sym, table[i]->len); 656 } 657 658 static unsigned char *find_token(unsigned char *str, int len, 659 const unsigned char *token) 660 { 661 int i; 662 663 for (i = 0; i < len - 1; i++) { 664 if (str[i] == token[0] && str[i+1] == token[1]) 665 return &str[i]; 666 } 667 return NULL; 668 } 669 670 /* replace a given token in all the valid symbols. Use the sampled symbols 671 * to update the counts */ 672 static void compress_symbols(const unsigned char *str, int idx) 673 { 674 unsigned int i, len, size; 675 unsigned char *p1, *p2; 676 677 for (i = 0; i < table_cnt; i++) { 678 679 len = table[i]->len; 680 p1 = table[i]->sym; 681 682 /* find the token on the symbol */ 683 p2 = find_token(p1, len, str); 684 if (!p2) continue; 685 686 /* decrease the counts for this symbol's tokens */ 687 forget_symbol(table[i]->sym, len); 688 689 size = len; 690 691 do { 692 *p2 = idx; 693 p2++; 694 size -= (p2 - p1); 695 memmove(p2, p2 + 1, size); 696 p1 = p2; 697 len--; 698 699 if (size < 2) break; 700 701 /* find the token on the symbol */ 702 p2 = find_token(p1, size, str); 703 704 } while (p2); 705 706 table[i]->len = len; 707 708 /* increase the counts for this symbol's new tokens */ 709 learn_symbol(table[i]->sym, len); 710 } 711 } 712 713 /* search the token with the maximum profit */ 714 static int find_best_token(void) 715 { 716 int i, best, bestprofit; 717 718 bestprofit=-10000; 719 best = 0; 720 721 for (i = 0; i < 0x10000; i++) { 722 if (token_profit[i] > bestprofit) { 723 best = i; 724 bestprofit = token_profit[i]; 725 } 726 } 727 return best; 728 } 729 730 /* this is the core of the algorithm: calculate the "best" table */ 731 static void optimize_result(void) 732 { 733 int i, best; 734 735 /* using the '\0' symbol last allows compress_symbols to use standard 736 * fast string functions */ 737 for (i = 255; i >= 0; i--) { 738 739 /* if this table slot is empty (it is not used by an actual 740 * original char code */ 741 if (!best_table_len[i]) { 742 743 /* find the token with the best profit value */ 744 best = find_best_token(); 745 if (token_profit[best] == 0) 746 break; 747 748 /* place it in the "best" table */ 749 best_table_len[i] = 2; 750 best_table[i][0] = best & 0xFF; 751 best_table[i][1] = (best >> 8) & 0xFF; 752 753 /* replace this token in all the valid symbols */ 754 compress_symbols(best_table[i], i); 755 } 756 } 757 } 758 759 /* start by placing the symbols that are actually used on the table */ 760 static void insert_real_symbols_in_table(void) 761 { 762 unsigned int i, j, c; 763 764 for (i = 0; i < table_cnt; i++) { 765 for (j = 0; j < table[i]->len; j++) { 766 c = table[i]->sym[j]; 767 best_table[c][0]=c; 768 best_table_len[c]=1; 769 } 770 } 771 } 772 773 static void optimize_token_table(void) 774 { 775 build_initial_token_table(); 776 777 insert_real_symbols_in_table(); 778 779 optimize_result(); 780 } 781 782 /* guess for "linker script provide" symbol */ 783 static int may_be_linker_script_provide_symbol(const struct sym_entry *se) 784 { 785 const char *symbol = sym_name(se); 786 int len = se->len - 1; 787 788 if (len < 8) 789 return 0; 790 791 if (symbol[0] != '_' || symbol[1] != '_') 792 return 0; 793 794 /* __start_XXXXX */ 795 if (!memcmp(symbol + 2, "start_", 6)) 796 return 1; 797 798 /* __stop_XXXXX */ 799 if (!memcmp(symbol + 2, "stop_", 5)) 800 return 1; 801 802 /* __end_XXXXX */ 803 if (!memcmp(symbol + 2, "end_", 4)) 804 return 1; 805 806 /* __XXXXX_start */ 807 if (!memcmp(symbol + len - 6, "_start", 6)) 808 return 1; 809 810 /* __XXXXX_end */ 811 if (!memcmp(symbol + len - 4, "_end", 4)) 812 return 1; 813 814 return 0; 815 } 816 817 static int compare_symbols(const void *a, const void *b) 818 { 819 const struct sym_entry *sa = *(const struct sym_entry **)a; 820 const struct sym_entry *sb = *(const struct sym_entry **)b; 821 int wa, wb; 822 823 /* sort by address first */ 824 if (sa->addr > sb->addr) 825 return 1; 826 if (sa->addr < sb->addr) 827 return -1; 828 829 /* sort by "weakness" type */ 830 wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); 831 wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); 832 if (wa != wb) 833 return wa - wb; 834 835 /* sort by "linker script provide" type */ 836 wa = may_be_linker_script_provide_symbol(sa); 837 wb = may_be_linker_script_provide_symbol(sb); 838 if (wa != wb) 839 return wa - wb; 840 841 /* sort by the number of prefix underscores */ 842 wa = strspn(sym_name(sa), "_"); 843 wb = strspn(sym_name(sb), "_"); 844 if (wa != wb) 845 return wa - wb; 846 847 /* sort by initial order, so that other symbols are left undisturbed */ 848 return sa->start_pos - sb->start_pos; 849 } 850 851 static void sort_symbols(void) 852 { 853 qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 854 } 855 856 static void make_percpus_absolute(void) 857 { 858 unsigned int i; 859 860 for (i = 0; i < table_cnt; i++) 861 if (symbol_in_range(table[i], &percpu_range, 1)) { 862 /* 863 * Keep the 'A' override for percpu symbols to 864 * ensure consistent behavior compared to older 865 * versions of this tool. 866 */ 867 table[i]->sym[0] = 'A'; 868 table[i]->percpu_absolute = 1; 869 } 870 } 871 872 /* find the minimum non-absolute symbol address */ 873 static void record_relative_base(void) 874 { 875 unsigned int i; 876 877 for (i = 0; i < table_cnt; i++) 878 if (!symbol_absolute(table[i])) { 879 /* 880 * The table is sorted by address. 881 * Take the first non-absolute symbol value. 882 */ 883 relative_base = table[i]->addr; 884 return; 885 } 886 } 887 888 int main(int argc, char **argv) 889 { 890 while (1) { 891 static struct option long_options[] = { 892 {"all-symbols", no_argument, &all_symbols, 1}, 893 {"absolute-percpu", no_argument, &absolute_percpu, 1}, 894 {"base-relative", no_argument, &base_relative, 1}, 895 {"lto-clang", no_argument, <o_clang, 1}, 896 {}, 897 }; 898 899 int c = getopt_long(argc, argv, "", long_options, NULL); 900 901 if (c == -1) 902 break; 903 if (c != 0) 904 usage(); 905 } 906 907 if (optind >= argc) 908 usage(); 909 910 read_map(argv[optind]); 911 shrink_table(); 912 if (absolute_percpu) 913 make_percpus_absolute(); 914 sort_symbols(); 915 if (base_relative) 916 record_relative_base(); 917 optimize_token_table(); 918 write_src(); 919 920 return 0; 921 } 922