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