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 printf("\t.long\t%#x\n", (int)offset); 529 } else if (!symbol_absolute(table[i])) { 530 output_address(table[i]->addr); 531 } else { 532 printf("\tPTR\t%#llx\n", table[i]->addr); 533 } 534 } 535 printf("\n"); 536 537 if (base_relative) { 538 output_label("kallsyms_relative_base"); 539 output_address(relative_base); 540 printf("\n"); 541 } 542 543 output_label("kallsyms_num_syms"); 544 printf("\t.long\t%u\n", table_cnt); 545 printf("\n"); 546 547 /* table of offset markers, that give the offset in the compressed stream 548 * every 256 symbols */ 549 markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); 550 if (!markers) { 551 fprintf(stderr, "kallsyms failure: " 552 "unable to allocate required memory\n"); 553 exit(EXIT_FAILURE); 554 } 555 556 output_label("kallsyms_names"); 557 off = 0; 558 for (i = 0; i < table_cnt; i++) { 559 if ((i & 0xFF) == 0) 560 markers[i >> 8] = off; 561 table[i]->seq = i; 562 563 /* There cannot be any symbol of length zero. */ 564 if (table[i]->len == 0) { 565 fprintf(stderr, "kallsyms failure: " 566 "unexpected zero symbol length\n"); 567 exit(EXIT_FAILURE); 568 } 569 570 /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ 571 if (table[i]->len > 0x3FFF) { 572 fprintf(stderr, "kallsyms failure: " 573 "unexpected huge symbol length\n"); 574 exit(EXIT_FAILURE); 575 } 576 577 /* Encode length with ULEB128. */ 578 if (table[i]->len <= 0x7F) { 579 /* Most symbols use a single byte for the length. */ 580 printf("\t.byte 0x%02x", table[i]->len); 581 off += table[i]->len + 1; 582 } else { 583 /* "Big" symbols use two bytes. */ 584 printf("\t.byte 0x%02x, 0x%02x", 585 (table[i]->len & 0x7F) | 0x80, 586 (table[i]->len >> 7) & 0x7F); 587 off += table[i]->len + 2; 588 } 589 for (k = 0; k < table[i]->len; k++) 590 printf(", 0x%02x", table[i]->sym[k]); 591 printf("\n"); 592 } 593 printf("\n"); 594 595 output_label("kallsyms_markers"); 596 for (i = 0; i < ((table_cnt + 255) >> 8); i++) 597 printf("\t.long\t%u\n", markers[i]); 598 printf("\n"); 599 600 free(markers); 601 602 sort_symbols_by_name(); 603 output_label("kallsyms_seqs_of_names"); 604 for (i = 0; i < table_cnt; i++) 605 printf("\t.byte 0x%02x, 0x%02x, 0x%02x\n", 606 (unsigned char)(table[i]->seq >> 16), 607 (unsigned char)(table[i]->seq >> 8), 608 (unsigned char)(table[i]->seq >> 0)); 609 printf("\n"); 610 611 output_label("kallsyms_token_table"); 612 off = 0; 613 for (i = 0; i < 256; i++) { 614 best_idx[i] = off; 615 expand_symbol(best_table[i], best_table_len[i], buf); 616 printf("\t.asciz\t\"%s\"\n", buf); 617 off += strlen(buf) + 1; 618 } 619 printf("\n"); 620 621 output_label("kallsyms_token_index"); 622 for (i = 0; i < 256; i++) 623 printf("\t.short\t%d\n", best_idx[i]); 624 printf("\n"); 625 } 626 627 628 /* table lookup compression functions */ 629 630 /* count all the possible tokens in a symbol */ 631 static void learn_symbol(const unsigned char *symbol, int len) 632 { 633 int i; 634 635 for (i = 0; i < len - 1; i++) 636 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; 637 } 638 639 /* decrease the count for all the possible tokens in a symbol */ 640 static void forget_symbol(const unsigned char *symbol, int len) 641 { 642 int i; 643 644 for (i = 0; i < len - 1; i++) 645 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; 646 } 647 648 /* do the initial token count */ 649 static void build_initial_token_table(void) 650 { 651 unsigned int i; 652 653 for (i = 0; i < table_cnt; i++) 654 learn_symbol(table[i]->sym, table[i]->len); 655 } 656 657 static unsigned char *find_token(unsigned char *str, int len, 658 const unsigned char *token) 659 { 660 int i; 661 662 for (i = 0; i < len - 1; i++) { 663 if (str[i] == token[0] && str[i+1] == token[1]) 664 return &str[i]; 665 } 666 return NULL; 667 } 668 669 /* replace a given token in all the valid symbols. Use the sampled symbols 670 * to update the counts */ 671 static void compress_symbols(const unsigned char *str, int idx) 672 { 673 unsigned int i, len, size; 674 unsigned char *p1, *p2; 675 676 for (i = 0; i < table_cnt; i++) { 677 678 len = table[i]->len; 679 p1 = table[i]->sym; 680 681 /* find the token on the symbol */ 682 p2 = find_token(p1, len, str); 683 if (!p2) continue; 684 685 /* decrease the counts for this symbol's tokens */ 686 forget_symbol(table[i]->sym, len); 687 688 size = len; 689 690 do { 691 *p2 = idx; 692 p2++; 693 size -= (p2 - p1); 694 memmove(p2, p2 + 1, size); 695 p1 = p2; 696 len--; 697 698 if (size < 2) break; 699 700 /* find the token on the symbol */ 701 p2 = find_token(p1, size, str); 702 703 } while (p2); 704 705 table[i]->len = len; 706 707 /* increase the counts for this symbol's new tokens */ 708 learn_symbol(table[i]->sym, len); 709 } 710 } 711 712 /* search the token with the maximum profit */ 713 static int find_best_token(void) 714 { 715 int i, best, bestprofit; 716 717 bestprofit=-10000; 718 best = 0; 719 720 for (i = 0; i < 0x10000; i++) { 721 if (token_profit[i] > bestprofit) { 722 best = i; 723 bestprofit = token_profit[i]; 724 } 725 } 726 return best; 727 } 728 729 /* this is the core of the algorithm: calculate the "best" table */ 730 static void optimize_result(void) 731 { 732 int i, best; 733 734 /* using the '\0' symbol last allows compress_symbols to use standard 735 * fast string functions */ 736 for (i = 255; i >= 0; i--) { 737 738 /* if this table slot is empty (it is not used by an actual 739 * original char code */ 740 if (!best_table_len[i]) { 741 742 /* find the token with the best profit value */ 743 best = find_best_token(); 744 if (token_profit[best] == 0) 745 break; 746 747 /* place it in the "best" table */ 748 best_table_len[i] = 2; 749 best_table[i][0] = best & 0xFF; 750 best_table[i][1] = (best >> 8) & 0xFF; 751 752 /* replace this token in all the valid symbols */ 753 compress_symbols(best_table[i], i); 754 } 755 } 756 } 757 758 /* start by placing the symbols that are actually used on the table */ 759 static void insert_real_symbols_in_table(void) 760 { 761 unsigned int i, j, c; 762 763 for (i = 0; i < table_cnt; i++) { 764 for (j = 0; j < table[i]->len; j++) { 765 c = table[i]->sym[j]; 766 best_table[c][0]=c; 767 best_table_len[c]=1; 768 } 769 } 770 } 771 772 static void optimize_token_table(void) 773 { 774 build_initial_token_table(); 775 776 insert_real_symbols_in_table(); 777 778 optimize_result(); 779 } 780 781 /* guess for "linker script provide" symbol */ 782 static int may_be_linker_script_provide_symbol(const struct sym_entry *se) 783 { 784 const char *symbol = sym_name(se); 785 int len = se->len - 1; 786 787 if (len < 8) 788 return 0; 789 790 if (symbol[0] != '_' || symbol[1] != '_') 791 return 0; 792 793 /* __start_XXXXX */ 794 if (!memcmp(symbol + 2, "start_", 6)) 795 return 1; 796 797 /* __stop_XXXXX */ 798 if (!memcmp(symbol + 2, "stop_", 5)) 799 return 1; 800 801 /* __end_XXXXX */ 802 if (!memcmp(symbol + 2, "end_", 4)) 803 return 1; 804 805 /* __XXXXX_start */ 806 if (!memcmp(symbol + len - 6, "_start", 6)) 807 return 1; 808 809 /* __XXXXX_end */ 810 if (!memcmp(symbol + len - 4, "_end", 4)) 811 return 1; 812 813 return 0; 814 } 815 816 static int compare_symbols(const void *a, const void *b) 817 { 818 const struct sym_entry *sa = *(const struct sym_entry **)a; 819 const struct sym_entry *sb = *(const struct sym_entry **)b; 820 int wa, wb; 821 822 /* sort by address first */ 823 if (sa->addr > sb->addr) 824 return 1; 825 if (sa->addr < sb->addr) 826 return -1; 827 828 /* sort by "weakness" type */ 829 wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); 830 wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); 831 if (wa != wb) 832 return wa - wb; 833 834 /* sort by "linker script provide" type */ 835 wa = may_be_linker_script_provide_symbol(sa); 836 wb = may_be_linker_script_provide_symbol(sb); 837 if (wa != wb) 838 return wa - wb; 839 840 /* sort by the number of prefix underscores */ 841 wa = strspn(sym_name(sa), "_"); 842 wb = strspn(sym_name(sb), "_"); 843 if (wa != wb) 844 return wa - wb; 845 846 /* sort by initial order, so that other symbols are left undisturbed */ 847 return sa->start_pos - sb->start_pos; 848 } 849 850 static void sort_symbols(void) 851 { 852 qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 853 } 854 855 static void make_percpus_absolute(void) 856 { 857 unsigned int i; 858 859 for (i = 0; i < table_cnt; i++) 860 if (symbol_in_range(table[i], &percpu_range, 1)) { 861 /* 862 * Keep the 'A' override for percpu symbols to 863 * ensure consistent behavior compared to older 864 * versions of this tool. 865 */ 866 table[i]->sym[0] = 'A'; 867 table[i]->percpu_absolute = 1; 868 } 869 } 870 871 /* find the minimum non-absolute symbol address */ 872 static void record_relative_base(void) 873 { 874 unsigned int i; 875 876 for (i = 0; i < table_cnt; i++) 877 if (!symbol_absolute(table[i])) { 878 /* 879 * The table is sorted by address. 880 * Take the first non-absolute symbol value. 881 */ 882 relative_base = table[i]->addr; 883 return; 884 } 885 } 886 887 int main(int argc, char **argv) 888 { 889 while (1) { 890 static struct option long_options[] = { 891 {"all-symbols", no_argument, &all_symbols, 1}, 892 {"absolute-percpu", no_argument, &absolute_percpu, 1}, 893 {"base-relative", no_argument, &base_relative, 1}, 894 {"lto-clang", no_argument, <o_clang, 1}, 895 {}, 896 }; 897 898 int c = getopt_long(argc, argv, "", long_options, NULL); 899 900 if (c == -1) 901 break; 902 if (c != 0) 903 usage(); 904 } 905 906 if (optind >= argc) 907 usage(); 908 909 read_map(argv[optind]); 910 shrink_table(); 911 if (absolute_percpu) 912 make_percpus_absolute(); 913 sort_symbols(); 914 if (base_relative) 915 record_relative_base(); 916 optimize_token_table(); 917 write_src(); 918 919 return 0; 920 } 921