11da177e4SLinus Torvalds /* Generate assembler source containing symbol information 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright 2002 by Kai Germaschewski 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This software may be used and distributed according to the terms 61da177e4SLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 71da177e4SLinus Torvalds * 8adc40221SYuma Ueda * Usage: kallsyms [--all-symbols] [--absolute-percpu] 9adc40221SYuma Ueda * [--base-relative] in.map > out.S 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Table compression uses all the unused char codes on the symbols and 121da177e4SLinus Torvalds * maps these to the most used substrings (tokens). For instance, it might 131da177e4SLinus Torvalds * map char code 0xF7 to represent "write_" and then in every symbol where 141da177e4SLinus Torvalds * "write_" appears it can be replaced by 0xF7, saving 5 bytes. 151da177e4SLinus Torvalds * The used codes themselves are also placed in the table so that the 161da177e4SLinus Torvalds * decompresion can work without "special cases". 171da177e4SLinus Torvalds * Applied to kernel symbols, this usually produces a compression ratio 181da177e4SLinus Torvalds * of about 50%. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 22aa221f2eSMasahiro Yamada #include <getopt.h> 23a41333e0SMasahiro Yamada #include <stdbool.h> 241da177e4SLinus Torvalds #include <stdio.h> 251da177e4SLinus Torvalds #include <stdlib.h> 261da177e4SLinus Torvalds #include <string.h> 271da177e4SLinus Torvalds #include <ctype.h> 282213e9a6SArd Biesheuvel #include <limits.h> 291da177e4SLinus Torvalds 3017b1f0deSMike Frysinger #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 3117b1f0deSMike Frysinger 32b471927eSBoqun Feng #define _stringify_1(x) #x 33b471927eSBoqun Feng #define _stringify(x) _stringify_1(x) 34b471927eSBoqun Feng 35b8a94bfbSMiguel Ojeda #define KSYM_NAME_LEN 512 361da177e4SLinus Torvalds 376e8c5bbdSMiguel Ojeda /* 386e8c5bbdSMiguel Ojeda * A substantially bigger size than the current maximum. 396e8c5bbdSMiguel Ojeda * 406e8c5bbdSMiguel Ojeda * It cannot be defined as an expression because it gets stringified 416e8c5bbdSMiguel Ojeda * for the fscanf() format string. Therefore, a _Static_assert() is 426e8c5bbdSMiguel Ojeda * used instead to maintain the relationship with KSYM_NAME_LEN. 436e8c5bbdSMiguel Ojeda */ 44b8a94bfbSMiguel Ojeda #define KSYM_NAME_LEN_BUFFER 2048 456e8c5bbdSMiguel Ojeda _Static_assert( 466e8c5bbdSMiguel Ojeda KSYM_NAME_LEN_BUFFER == KSYM_NAME_LEN * 4, 476e8c5bbdSMiguel Ojeda "Please keep KSYM_NAME_LEN_BUFFER in sync with KSYM_NAME_LEN" 486e8c5bbdSMiguel Ojeda ); 49b471927eSBoqun Feng 501da177e4SLinus Torvalds struct sym_entry { 511da177e4SLinus Torvalds unsigned long long addr; 52b3dbb4ecSPaulo Marques unsigned int len; 5360443c88SZhen Lei unsigned int seq; 54f2df3f65SPaulo Marques unsigned int start_pos; 558c996940SArd Biesheuvel unsigned int percpu_absolute; 569d82973eSLinus Torvalds unsigned char sym[]; 571da177e4SLinus Torvalds }; 581da177e4SLinus Torvalds 5978eb7159SKees Cook struct addr_range { 6078eb7159SKees Cook const char *start_sym, *end_sym; 6117b1f0deSMike Frysinger unsigned long long start, end; 6217b1f0deSMike Frysinger }; 6317b1f0deSMike Frysinger 6417b1f0deSMike Frysinger static unsigned long long _text; 652213e9a6SArd Biesheuvel static unsigned long long relative_base; 6678eb7159SKees Cook static struct addr_range text_ranges[] = { 6717b1f0deSMike Frysinger { "_stext", "_etext" }, 6817b1f0deSMike Frysinger { "_sinittext", "_einittext" }, 6917b1f0deSMike Frysinger }; 7017b1f0deSMike Frysinger #define text_range_text (&text_ranges[0]) 7117b1f0deSMike Frysinger #define text_range_inittext (&text_ranges[1]) 7217b1f0deSMike Frysinger 73c6bda7c9SRusty Russell static struct addr_range percpu_range = { 74c6bda7c9SRusty Russell "__per_cpu_start", "__per_cpu_end", -1ULL, 0 75c6bda7c9SRusty Russell }; 76c6bda7c9SRusty Russell 778d605269SMasahiro Yamada static struct sym_entry **table; 78b3dbb4ecSPaulo Marques static unsigned int table_size, table_cnt; 79831362fcSMasahiro Yamada static int all_symbols; 80831362fcSMasahiro Yamada static int absolute_percpu; 81831362fcSMasahiro Yamada static int base_relative; 82010a0aadSZhen Lei static int lto_clang; 831da177e4SLinus Torvalds 84f43e9daaSMasahiro Yamada static int token_profit[0x10000]; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* the table that holds the result of the compression */ 87f43e9daaSMasahiro Yamada static unsigned char best_table[256][2]; 88f43e9daaSMasahiro Yamada static unsigned char best_table_len[256]; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds 91b3dbb4ecSPaulo Marques static void usage(void) 921da177e4SLinus Torvalds { 938d3a7507SYuntao Wang fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " 94010a0aadSZhen Lei "[--base-relative] [--lto-clang] in.map > out.S\n"); 951da177e4SLinus Torvalds exit(1); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 9829e55ad3SMasahiro Yamada static char *sym_name(const struct sym_entry *s) 9929e55ad3SMasahiro Yamada { 10029e55ad3SMasahiro Yamada return (char *)s->sym + 1; 10129e55ad3SMasahiro Yamada } 10229e55ad3SMasahiro Yamada 103a41333e0SMasahiro Yamada static bool is_ignored_symbol(const char *name, char type) 104a41333e0SMasahiro Yamada { 105a7b00a18SMasahiro Yamada if (type == 'u' || type == 'n') 106887df76dSMasahiro Yamada return true; 107887df76dSMasahiro Yamada 108887df76dSMasahiro Yamada if (toupper(type) == 'A') { 109887df76dSMasahiro Yamada /* Keep these useful absolute symbols */ 110887df76dSMasahiro Yamada if (strcmp(name, "__kernel_syscall_via_break") && 111887df76dSMasahiro Yamada strcmp(name, "__kernel_syscall_via_epc") && 112887df76dSMasahiro Yamada strcmp(name, "__kernel_sigtramp") && 113887df76dSMasahiro Yamada strcmp(name, "__gp")) 114887df76dSMasahiro Yamada return true; 115887df76dSMasahiro Yamada } 116887df76dSMasahiro Yamada 117a41333e0SMasahiro Yamada return false; 118a41333e0SMasahiro Yamada } 119a41333e0SMasahiro Yamada 120b6233d0dSMasahiro Yamada static void check_symbol_range(const char *sym, unsigned long long addr, 12178eb7159SKees Cook struct addr_range *ranges, int entries) 12217b1f0deSMike Frysinger { 12317b1f0deSMike Frysinger size_t i; 12478eb7159SKees Cook struct addr_range *ar; 12517b1f0deSMike Frysinger 12678eb7159SKees Cook for (i = 0; i < entries; ++i) { 12778eb7159SKees Cook ar = &ranges[i]; 12817b1f0deSMike Frysinger 12978eb7159SKees Cook if (strcmp(sym, ar->start_sym) == 0) { 13078eb7159SKees Cook ar->start = addr; 131b6233d0dSMasahiro Yamada return; 13278eb7159SKees Cook } else if (strcmp(sym, ar->end_sym) == 0) { 13378eb7159SKees Cook ar->end = addr; 134b6233d0dSMasahiro Yamada return; 13517b1f0deSMike Frysinger } 13617b1f0deSMike Frysinger } 13717b1f0deSMike Frysinger } 13817b1f0deSMike Frysinger 1398d605269SMasahiro Yamada static struct sym_entry *read_symbol(FILE *in) 1401da177e4SLinus Torvalds { 141b471927eSBoqun Feng char name[KSYM_NAME_LEN_BUFFER+1], type; 1428d605269SMasahiro Yamada unsigned long long addr; 1438d605269SMasahiro Yamada unsigned int len; 1448d605269SMasahiro Yamada struct sym_entry *sym; 1451da177e4SLinus Torvalds int rc; 1461da177e4SLinus Torvalds 147b471927eSBoqun Feng rc = fscanf(in, "%llx %c %" _stringify(KSYM_NAME_LEN_BUFFER) "s\n", &addr, &type, name); 1481da177e4SLinus Torvalds if (rc != 3) { 149b66c874fSBoqun Feng if (rc != EOF && fgets(name, ARRAY_SIZE(name), in) == NULL) 150ef894870SJean Sacren fprintf(stderr, "Read error or end of file.\n"); 1518d605269SMasahiro Yamada return NULL; 1521da177e4SLinus Torvalds } 153be9f6133SMasahiro Yamada if (strlen(name) >= KSYM_NAME_LEN) { 1546db2983cSEugene Loh fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n" 155f3462aa9SAndi Kleen "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", 156be9f6133SMasahiro Yamada name, strlen(name), KSYM_NAME_LEN); 1578d605269SMasahiro Yamada return NULL; 158f3462aa9SAndi Kleen } 1591da177e4SLinus Torvalds 160be9f6133SMasahiro Yamada if (strcmp(name, "_text") == 0) 1618d605269SMasahiro Yamada _text = addr; 162b6233d0dSMasahiro Yamada 1637883a143SMikhail Petrov /* Ignore most absolute/undefined (?) symbols. */ 1647883a143SMikhail Petrov if (is_ignored_symbol(name, type)) 1657883a143SMikhail Petrov return NULL; 1667883a143SMikhail Petrov 1678d605269SMasahiro Yamada check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); 1688d605269SMasahiro Yamada check_symbol_range(name, addr, &percpu_range, 1); 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* include the type field in the symbol name, so that it gets 1711da177e4SLinus Torvalds * compressed together */ 1728d605269SMasahiro Yamada 1738d605269SMasahiro Yamada len = strlen(name) + 1; 1748d605269SMasahiro Yamada 1759d1b3895SMasahiro Yamada sym = malloc(sizeof(*sym) + len + 1); 1768d605269SMasahiro Yamada if (!sym) { 177f1a136e0SJesper Juhl fprintf(stderr, "kallsyms failure: " 178f1a136e0SJesper Juhl "unable to allocate required amount of memory\n"); 179f1a136e0SJesper Juhl exit(EXIT_FAILURE); 180f1a136e0SJesper Juhl } 1818d605269SMasahiro Yamada sym->addr = addr; 1828d605269SMasahiro Yamada sym->len = len; 1838d605269SMasahiro Yamada sym->sym[0] = type; 1849d1b3895SMasahiro Yamada strcpy(sym_name(sym), name); 1858d605269SMasahiro Yamada sym->percpu_absolute = 0; 1861da177e4SLinus Torvalds 1878d605269SMasahiro Yamada return sym; 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1904bfe2b78SMasahiro Yamada static int symbol_in_range(const struct sym_entry *s, 1914bfe2b78SMasahiro Yamada const struct addr_range *ranges, int entries) 19217b1f0deSMike Frysinger { 19317b1f0deSMike Frysinger size_t i; 1944bfe2b78SMasahiro Yamada const struct addr_range *ar; 19517b1f0deSMike Frysinger 19678eb7159SKees Cook for (i = 0; i < entries; ++i) { 19778eb7159SKees Cook ar = &ranges[i]; 19817b1f0deSMike Frysinger 19978eb7159SKees Cook if (s->addr >= ar->start && s->addr <= ar->end) 200ac6ca5c8SMike Frysinger return 1; 20117b1f0deSMike Frysinger } 20217b1f0deSMike Frysinger 203ac6ca5c8SMike Frysinger return 0; 20417b1f0deSMike Frysinger } 20517b1f0deSMike Frysinger 2064bfe2b78SMasahiro Yamada static int symbol_valid(const struct sym_entry *s) 2071da177e4SLinus Torvalds { 20829e55ad3SMasahiro Yamada const char *name = sym_name(s); 209bd8b22d2SArd Biesheuvel 2101da177e4SLinus Torvalds /* if --all-symbols is not specified, then symbols outside the text 2111da177e4SLinus Torvalds * and inittext sections are discarded */ 2121da177e4SLinus Torvalds if (!all_symbols) { 21378eb7159SKees Cook if (symbol_in_range(s, text_ranges, 21478eb7159SKees Cook ARRAY_SIZE(text_ranges)) == 0) 2151da177e4SLinus Torvalds return 0; 2161da177e4SLinus Torvalds /* Corner case. Discard any symbols with the same value as 217a3b81113SRobin Getz * _etext _einittext; they can move between pass 1 and 2 when 218a3b81113SRobin Getz * the kallsyms data are added. If these symbols move then 219a3b81113SRobin Getz * they may get dropped in pass 2, which breaks the kallsyms 220a3b81113SRobin Getz * rules. 2211da177e4SLinus Torvalds */ 22217b1f0deSMike Frysinger if ((s->addr == text_range_text->end && 22329e55ad3SMasahiro Yamada strcmp(name, text_range_text->end_sym)) || 22417b1f0deSMike Frysinger (s->addr == text_range_inittext->end && 22529e55ad3SMasahiro Yamada strcmp(name, text_range_inittext->end_sym))) 2261da177e4SLinus Torvalds return 0; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds return 1; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2325e5c4fa7SMasahiro Yamada /* remove all the invalid symbols from the table */ 2335e5c4fa7SMasahiro Yamada static void shrink_table(void) 2345e5c4fa7SMasahiro Yamada { 2355e5c4fa7SMasahiro Yamada unsigned int i, pos; 2365e5c4fa7SMasahiro Yamada 2375e5c4fa7SMasahiro Yamada pos = 0; 2385e5c4fa7SMasahiro Yamada for (i = 0; i < table_cnt; i++) { 2398d605269SMasahiro Yamada if (symbol_valid(table[i])) { 2405e5c4fa7SMasahiro Yamada if (pos != i) 2415e5c4fa7SMasahiro Yamada table[pos] = table[i]; 2425e5c4fa7SMasahiro Yamada pos++; 2435e5c4fa7SMasahiro Yamada } else { 2448d605269SMasahiro Yamada free(table[i]); 2455e5c4fa7SMasahiro Yamada } 2465e5c4fa7SMasahiro Yamada } 2475e5c4fa7SMasahiro Yamada table_cnt = pos; 2485e5c4fa7SMasahiro Yamada 2495e5c4fa7SMasahiro Yamada /* When valid symbol is not registered, exit to error */ 2505e5c4fa7SMasahiro Yamada if (!table_cnt) { 2515e5c4fa7SMasahiro Yamada fprintf(stderr, "No valid symbol.\n"); 2525e5c4fa7SMasahiro Yamada exit(1); 2535e5c4fa7SMasahiro Yamada } 2545e5c4fa7SMasahiro Yamada } 2555e5c4fa7SMasahiro Yamada 256aa221f2eSMasahiro Yamada static void read_map(const char *in) 2571da177e4SLinus Torvalds { 258aa221f2eSMasahiro Yamada FILE *fp; 2598d605269SMasahiro Yamada struct sym_entry *sym; 2608d605269SMasahiro Yamada 261aa221f2eSMasahiro Yamada fp = fopen(in, "r"); 262aa221f2eSMasahiro Yamada if (!fp) { 263aa221f2eSMasahiro Yamada perror(in); 264aa221f2eSMasahiro Yamada exit(1); 265aa221f2eSMasahiro Yamada } 266aa221f2eSMasahiro Yamada 267aa221f2eSMasahiro Yamada while (!feof(fp)) { 268aa221f2eSMasahiro Yamada sym = read_symbol(fp); 2698d605269SMasahiro Yamada if (!sym) 2708d605269SMasahiro Yamada continue; 2718d605269SMasahiro Yamada 2728d605269SMasahiro Yamada sym->start_pos = table_cnt; 2738d605269SMasahiro Yamada 274b3dbb4ecSPaulo Marques if (table_cnt >= table_size) { 275b3dbb4ecSPaulo Marques table_size += 10000; 276b3dbb4ecSPaulo Marques table = realloc(table, sizeof(*table) * table_size); 2771da177e4SLinus Torvalds if (!table) { 2781da177e4SLinus Torvalds fprintf(stderr, "out of memory\n"); 279aa221f2eSMasahiro Yamada fclose(fp); 2801da177e4SLinus Torvalds exit (1); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds } 2838d605269SMasahiro Yamada 2848d605269SMasahiro Yamada table[table_cnt++] = sym; 2851da177e4SLinus Torvalds } 286aa221f2eSMasahiro Yamada 287aa221f2eSMasahiro Yamada fclose(fp); 288f2df3f65SPaulo Marques } 2891da177e4SLinus Torvalds 2904bfe2b78SMasahiro Yamada static void output_label(const char *label) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds printf(".globl %s\n", label); 2931da177e4SLinus Torvalds printf("\tALGN\n"); 2941da177e4SLinus Torvalds printf("%s:\n", label); 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 297fd2ab2f6SMasahiro Yamada /* Provide proper symbols relocatability by their '_text' relativeness. */ 298fd2ab2f6SMasahiro Yamada static void output_address(unsigned long long addr) 299fd2ab2f6SMasahiro Yamada { 300fd2ab2f6SMasahiro Yamada if (_text <= addr) 301fd2ab2f6SMasahiro Yamada printf("\tPTR\t_text + %#llx\n", addr - _text); 302fd2ab2f6SMasahiro Yamada else 303fd2ab2f6SMasahiro Yamada printf("\tPTR\t_text - %#llx\n", _text - addr); 304fd2ab2f6SMasahiro Yamada } 305fd2ab2f6SMasahiro Yamada 3061da177e4SLinus Torvalds /* uncompress a compressed symbol. When this function is called, the best table 3071da177e4SLinus Torvalds * might still be compressed itself, so the function needs to be recursive */ 3084bfe2b78SMasahiro Yamada static int expand_symbol(const unsigned char *data, int len, char *result) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds int c, rlen, total=0; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds while (len) { 3131da177e4SLinus Torvalds c = *data; 3141da177e4SLinus Torvalds /* if the table holds a single char that is the same as the one 3151da177e4SLinus Torvalds * we are looking for, then end the search */ 3161da177e4SLinus Torvalds if (best_table[c][0]==c && best_table_len[c]==1) { 3171da177e4SLinus Torvalds *result++ = c; 3181da177e4SLinus Torvalds total++; 3191da177e4SLinus Torvalds } else { 3201da177e4SLinus Torvalds /* if not, recurse and expand */ 3211da177e4SLinus Torvalds rlen = expand_symbol(best_table[c], best_table_len[c], result); 3221da177e4SLinus Torvalds total += rlen; 3231da177e4SLinus Torvalds result += rlen; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds data++; 3261da177e4SLinus Torvalds len--; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds *result=0; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds return total; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3334bfe2b78SMasahiro Yamada static int symbol_absolute(const struct sym_entry *s) 33478eb7159SKees Cook { 3358c996940SArd Biesheuvel return s->percpu_absolute; 33678eb7159SKees Cook } 33778eb7159SKees Cook 338010a0aadSZhen Lei static char * s_name(char *buf) 339010a0aadSZhen Lei { 340010a0aadSZhen Lei /* Skip the symbol type */ 341010a0aadSZhen Lei return buf + 1; 342010a0aadSZhen Lei } 343010a0aadSZhen Lei 344010a0aadSZhen Lei static void cleanup_symbol_name(char *s) 345010a0aadSZhen Lei { 346010a0aadSZhen Lei char *p; 347010a0aadSZhen Lei 348010a0aadSZhen Lei if (!lto_clang) 349010a0aadSZhen Lei return; 350010a0aadSZhen Lei 351010a0aadSZhen Lei /* 352010a0aadSZhen Lei * ASCII[.] = 2e 353010a0aadSZhen Lei * ASCII[0-9] = 30,39 354010a0aadSZhen Lei * ASCII[A-Z] = 41,5a 355010a0aadSZhen Lei * ASCII[_] = 5f 356010a0aadSZhen Lei * ASCII[a-z] = 61,7a 357010a0aadSZhen Lei * 358010a0aadSZhen Lei * As above, replacing '.' with '\0' does not affect the main sorting, 359010a0aadSZhen Lei * but it helps us with subsorting. 360010a0aadSZhen Lei */ 361010a0aadSZhen Lei p = strchr(s, '.'); 362010a0aadSZhen Lei if (p) 363010a0aadSZhen Lei *p = '\0'; 364010a0aadSZhen Lei } 365010a0aadSZhen Lei 36660443c88SZhen Lei static int compare_names(const void *a, const void *b) 36760443c88SZhen Lei { 36860443c88SZhen Lei int ret; 36960443c88SZhen Lei char sa_namebuf[KSYM_NAME_LEN]; 37060443c88SZhen Lei char sb_namebuf[KSYM_NAME_LEN]; 37160443c88SZhen Lei const struct sym_entry *sa = *(const struct sym_entry **)a; 37260443c88SZhen Lei const struct sym_entry *sb = *(const struct sym_entry **)b; 37360443c88SZhen Lei 37460443c88SZhen Lei expand_symbol(sa->sym, sa->len, sa_namebuf); 37560443c88SZhen Lei expand_symbol(sb->sym, sb->len, sb_namebuf); 376010a0aadSZhen Lei cleanup_symbol_name(s_name(sa_namebuf)); 377010a0aadSZhen Lei cleanup_symbol_name(s_name(sb_namebuf)); 378010a0aadSZhen Lei ret = strcmp(s_name(sa_namebuf), s_name(sb_namebuf)); 37960443c88SZhen Lei if (!ret) { 38060443c88SZhen Lei if (sa->addr > sb->addr) 38160443c88SZhen Lei return 1; 38260443c88SZhen Lei else if (sa->addr < sb->addr) 38360443c88SZhen Lei return -1; 38460443c88SZhen Lei 38560443c88SZhen Lei /* keep old order */ 38660443c88SZhen Lei return (int)(sa->seq - sb->seq); 38760443c88SZhen Lei } 38860443c88SZhen Lei 38960443c88SZhen Lei return ret; 39060443c88SZhen Lei } 39160443c88SZhen Lei 39260443c88SZhen Lei static void sort_symbols_by_name(void) 39360443c88SZhen Lei { 39460443c88SZhen Lei qsort(table, table_cnt, sizeof(table[0]), compare_names); 39560443c88SZhen Lei } 39660443c88SZhen Lei 397b3dbb4ecSPaulo Marques static void write_src(void) 3981da177e4SLinus Torvalds { 399b3dbb4ecSPaulo Marques unsigned int i, k, off; 4001da177e4SLinus Torvalds unsigned int best_idx[256]; 4011da177e4SLinus Torvalds unsigned int *markers; 4029281aceaSTejun Heo char buf[KSYM_NAME_LEN]; 4031da177e4SLinus Torvalds 404500193ecSMasahiro Yamada printf("#include <asm/bitsperlong.h>\n"); 4051da177e4SLinus Torvalds printf("#if BITS_PER_LONG == 64\n"); 4061da177e4SLinus Torvalds printf("#define PTR .quad\n"); 40772d3ebb9SMathias Krause printf("#define ALGN .balign 8\n"); 4081da177e4SLinus Torvalds printf("#else\n"); 4091da177e4SLinus Torvalds printf("#define PTR .long\n"); 41072d3ebb9SMathias Krause printf("#define ALGN .balign 4\n"); 4111da177e4SLinus Torvalds printf("#endif\n"); 4121da177e4SLinus Torvalds 413aad09470SJan Beulich printf("\t.section .rodata, \"a\"\n"); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds output_label("kallsyms_num_syms"); 41680ffbaa5SJan Beulich printf("\t.long\t%u\n", table_cnt); 4171da177e4SLinus Torvalds printf("\n"); 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds /* table of offset markers, that give the offset in the compressed stream 4201da177e4SLinus Torvalds * every 256 symbols */ 421f1a136e0SJesper Juhl markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); 422f1a136e0SJesper Juhl if (!markers) { 423f1a136e0SJesper Juhl fprintf(stderr, "kallsyms failure: " 424f1a136e0SJesper Juhl "unable to allocate required memory\n"); 425f1a136e0SJesper Juhl exit(EXIT_FAILURE); 426f1a136e0SJesper Juhl } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds output_label("kallsyms_names"); 4291da177e4SLinus Torvalds off = 0; 430b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 431b3dbb4ecSPaulo Marques if ((i & 0xFF) == 0) 432b3dbb4ecSPaulo Marques markers[i >> 8] = off; 43360443c88SZhen Lei table[i]->seq = i; 4341da177e4SLinus Torvalds 43573bbb944SMiguel Ojeda /* There cannot be any symbol of length zero. */ 43673bbb944SMiguel Ojeda if (table[i]->len == 0) { 43773bbb944SMiguel Ojeda fprintf(stderr, "kallsyms failure: " 43873bbb944SMiguel Ojeda "unexpected zero symbol length\n"); 43973bbb944SMiguel Ojeda exit(EXIT_FAILURE); 44073bbb944SMiguel Ojeda } 44173bbb944SMiguel Ojeda 44273bbb944SMiguel Ojeda /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ 44373bbb944SMiguel Ojeda if (table[i]->len > 0x3FFF) { 44473bbb944SMiguel Ojeda fprintf(stderr, "kallsyms failure: " 44573bbb944SMiguel Ojeda "unexpected huge symbol length\n"); 44673bbb944SMiguel Ojeda exit(EXIT_FAILURE); 44773bbb944SMiguel Ojeda } 44873bbb944SMiguel Ojeda 44973bbb944SMiguel Ojeda /* Encode length with ULEB128. */ 45073bbb944SMiguel Ojeda if (table[i]->len <= 0x7F) { 45173bbb944SMiguel Ojeda /* Most symbols use a single byte for the length. */ 4528d605269SMasahiro Yamada printf("\t.byte 0x%02x", table[i]->len); 45373bbb944SMiguel Ojeda off += table[i]->len + 1; 45473bbb944SMiguel Ojeda } else { 45573bbb944SMiguel Ojeda /* "Big" symbols use two bytes. */ 45673bbb944SMiguel Ojeda printf("\t.byte 0x%02x, 0x%02x", 45773bbb944SMiguel Ojeda (table[i]->len & 0x7F) | 0x80, 45873bbb944SMiguel Ojeda (table[i]->len >> 7) & 0x7F); 45973bbb944SMiguel Ojeda off += table[i]->len + 2; 46073bbb944SMiguel Ojeda } 4618d605269SMasahiro Yamada for (k = 0; k < table[i]->len; k++) 4628d605269SMasahiro Yamada printf(", 0x%02x", table[i]->sym[k]); 4631da177e4SLinus Torvalds printf("\n"); 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds printf("\n"); 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds output_label("kallsyms_markers"); 468b3dbb4ecSPaulo Marques for (i = 0; i < ((table_cnt + 255) >> 8); i++) 46980ffbaa5SJan Beulich printf("\t.long\t%u\n", markers[i]); 4701da177e4SLinus Torvalds printf("\n"); 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds free(markers); 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds output_label("kallsyms_token_table"); 4751da177e4SLinus Torvalds off = 0; 4761da177e4SLinus Torvalds for (i = 0; i < 256; i++) { 4771da177e4SLinus Torvalds best_idx[i] = off; 4781da177e4SLinus Torvalds expand_symbol(best_table[i], best_table_len[i], buf); 4791da177e4SLinus Torvalds printf("\t.asciz\t\"%s\"\n", buf); 4801da177e4SLinus Torvalds off += strlen(buf) + 1; 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds printf("\n"); 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds output_label("kallsyms_token_index"); 4851da177e4SLinus Torvalds for (i = 0; i < 256; i++) 4861da177e4SLinus Torvalds printf("\t.short\t%d\n", best_idx[i]); 4871da177e4SLinus Torvalds printf("\n"); 488*404bad70SMasahiro Yamada 489*404bad70SMasahiro Yamada if (!base_relative) 490*404bad70SMasahiro Yamada output_label("kallsyms_addresses"); 491*404bad70SMasahiro Yamada else 492*404bad70SMasahiro Yamada output_label("kallsyms_offsets"); 493*404bad70SMasahiro Yamada 494*404bad70SMasahiro Yamada for (i = 0; i < table_cnt; i++) { 495*404bad70SMasahiro Yamada if (base_relative) { 496*404bad70SMasahiro Yamada /* 497*404bad70SMasahiro Yamada * Use the offset relative to the lowest value 498*404bad70SMasahiro Yamada * encountered of all relative symbols, and emit 499*404bad70SMasahiro Yamada * non-relocatable fixed offsets that will be fixed 500*404bad70SMasahiro Yamada * up at runtime. 501*404bad70SMasahiro Yamada */ 502*404bad70SMasahiro Yamada 503*404bad70SMasahiro Yamada long long offset; 504*404bad70SMasahiro Yamada int overflow; 505*404bad70SMasahiro Yamada 506*404bad70SMasahiro Yamada if (!absolute_percpu) { 507*404bad70SMasahiro Yamada offset = table[i]->addr - relative_base; 508*404bad70SMasahiro Yamada overflow = (offset < 0 || offset > UINT_MAX); 509*404bad70SMasahiro Yamada } else if (symbol_absolute(table[i])) { 510*404bad70SMasahiro Yamada offset = table[i]->addr; 511*404bad70SMasahiro Yamada overflow = (offset < 0 || offset > INT_MAX); 512*404bad70SMasahiro Yamada } else { 513*404bad70SMasahiro Yamada offset = relative_base - table[i]->addr - 1; 514*404bad70SMasahiro Yamada overflow = (offset < INT_MIN || offset >= 0); 515*404bad70SMasahiro Yamada } 516*404bad70SMasahiro Yamada if (overflow) { 517*404bad70SMasahiro Yamada fprintf(stderr, "kallsyms failure: " 518*404bad70SMasahiro Yamada "%s symbol value %#llx out of range in relative mode\n", 519*404bad70SMasahiro Yamada symbol_absolute(table[i]) ? "absolute" : "relative", 520*404bad70SMasahiro Yamada table[i]->addr); 521*404bad70SMasahiro Yamada exit(EXIT_FAILURE); 522*404bad70SMasahiro Yamada } 523*404bad70SMasahiro Yamada expand_symbol(table[i]->sym, table[i]->len, buf); 524*404bad70SMasahiro Yamada printf("\t.long\t%#x /* %s */\n", (int)offset, buf); 525*404bad70SMasahiro Yamada } else if (!symbol_absolute(table[i])) { 526*404bad70SMasahiro Yamada output_address(table[i]->addr); 527*404bad70SMasahiro Yamada } else { 528*404bad70SMasahiro Yamada printf("\tPTR\t%#llx\n", table[i]->addr); 529*404bad70SMasahiro Yamada } 530*404bad70SMasahiro Yamada } 531*404bad70SMasahiro Yamada printf("\n"); 532*404bad70SMasahiro Yamada 533*404bad70SMasahiro Yamada if (base_relative) { 534*404bad70SMasahiro Yamada output_label("kallsyms_relative_base"); 535*404bad70SMasahiro Yamada output_address(relative_base); 536*404bad70SMasahiro Yamada printf("\n"); 537*404bad70SMasahiro Yamada } 538*404bad70SMasahiro Yamada 539*404bad70SMasahiro Yamada sort_symbols_by_name(); 540*404bad70SMasahiro Yamada output_label("kallsyms_seqs_of_names"); 541*404bad70SMasahiro Yamada for (i = 0; i < table_cnt; i++) 542*404bad70SMasahiro Yamada printf("\t.byte 0x%02x, 0x%02x, 0x%02x\n", 543*404bad70SMasahiro Yamada (unsigned char)(table[i]->seq >> 16), 544*404bad70SMasahiro Yamada (unsigned char)(table[i]->seq >> 8), 545*404bad70SMasahiro Yamada (unsigned char)(table[i]->seq >> 0)); 546*404bad70SMasahiro Yamada printf("\n"); 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds /* table lookup compression functions */ 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds /* count all the possible tokens in a symbol */ 5534bfe2b78SMasahiro Yamada static void learn_symbol(const unsigned char *symbol, int len) 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds int i; 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds for (i = 0; i < len - 1; i++) 558b3dbb4ecSPaulo Marques token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* decrease the count for all the possible tokens in a symbol */ 5624bfe2b78SMasahiro Yamada static void forget_symbol(const unsigned char *symbol, int len) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds int i; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds for (i = 0; i < len - 1; i++) 567b3dbb4ecSPaulo Marques token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5705e5c4fa7SMasahiro Yamada /* do the initial token count */ 571fcdf7197SZhen Lei static void build_initial_token_table(void) 5721da177e4SLinus Torvalds { 5735e5c4fa7SMasahiro Yamada unsigned int i; 5741da177e4SLinus Torvalds 5755e5c4fa7SMasahiro Yamada for (i = 0; i < table_cnt; i++) 5768d605269SMasahiro Yamada learn_symbol(table[i]->sym, table[i]->len); 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5792558c138SMasahiro Yamada static unsigned char *find_token(unsigned char *str, int len, 5804bfe2b78SMasahiro Yamada const unsigned char *token) 5817c5d249aSPaulo Marques { 5827c5d249aSPaulo Marques int i; 5837c5d249aSPaulo Marques 5847c5d249aSPaulo Marques for (i = 0; i < len - 1; i++) { 5857c5d249aSPaulo Marques if (str[i] == token[0] && str[i+1] == token[1]) 5867c5d249aSPaulo Marques return &str[i]; 5877c5d249aSPaulo Marques } 5887c5d249aSPaulo Marques return NULL; 5897c5d249aSPaulo Marques } 5907c5d249aSPaulo Marques 5911da177e4SLinus Torvalds /* replace a given token in all the valid symbols. Use the sampled symbols 5921da177e4SLinus Torvalds * to update the counts */ 5934bfe2b78SMasahiro Yamada static void compress_symbols(const unsigned char *str, int idx) 5941da177e4SLinus Torvalds { 595b3dbb4ecSPaulo Marques unsigned int i, len, size; 596b3dbb4ecSPaulo Marques unsigned char *p1, *p2; 5971da177e4SLinus Torvalds 598b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 5991da177e4SLinus Torvalds 6008d605269SMasahiro Yamada len = table[i]->len; 6018d605269SMasahiro Yamada p1 = table[i]->sym; 602b3dbb4ecSPaulo Marques 603b3dbb4ecSPaulo Marques /* find the token on the symbol */ 6047c5d249aSPaulo Marques p2 = find_token(p1, len, str); 605b3dbb4ecSPaulo Marques if (!p2) continue; 606b3dbb4ecSPaulo Marques 607b3dbb4ecSPaulo Marques /* decrease the counts for this symbol's tokens */ 6088d605269SMasahiro Yamada forget_symbol(table[i]->sym, len); 609b3dbb4ecSPaulo Marques 610b3dbb4ecSPaulo Marques size = len; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds do { 613b3dbb4ecSPaulo Marques *p2 = idx; 614b3dbb4ecSPaulo Marques p2++; 615b3dbb4ecSPaulo Marques size -= (p2 - p1); 616b3dbb4ecSPaulo Marques memmove(p2, p2 + 1, size); 617b3dbb4ecSPaulo Marques p1 = p2; 618b3dbb4ecSPaulo Marques len--; 619b3dbb4ecSPaulo Marques 620b3dbb4ecSPaulo Marques if (size < 2) break; 621b3dbb4ecSPaulo Marques 6221da177e4SLinus Torvalds /* find the token on the symbol */ 6237c5d249aSPaulo Marques p2 = find_token(p1, size, str); 6241da177e4SLinus Torvalds 625b3dbb4ecSPaulo Marques } while (p2); 6261da177e4SLinus Torvalds 6278d605269SMasahiro Yamada table[i]->len = len; 628b3dbb4ecSPaulo Marques 629b3dbb4ecSPaulo Marques /* increase the counts for this symbol's new tokens */ 6308d605269SMasahiro Yamada learn_symbol(table[i]->sym, len); 6311da177e4SLinus Torvalds } 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds /* search the token with the maximum profit */ 635b3dbb4ecSPaulo Marques static int find_best_token(void) 6361da177e4SLinus Torvalds { 637b3dbb4ecSPaulo Marques int i, best, bestprofit; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds bestprofit=-10000; 640b3dbb4ecSPaulo Marques best = 0; 6411da177e4SLinus Torvalds 642b3dbb4ecSPaulo Marques for (i = 0; i < 0x10000; i++) { 643b3dbb4ecSPaulo Marques if (token_profit[i] > bestprofit) { 644b3dbb4ecSPaulo Marques best = i; 645b3dbb4ecSPaulo Marques bestprofit = token_profit[i]; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds return best; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* this is the core of the algorithm: calculate the "best" table */ 6521da177e4SLinus Torvalds static void optimize_result(void) 6531da177e4SLinus Torvalds { 654b3dbb4ecSPaulo Marques int i, best; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds /* using the '\0' symbol last allows compress_symbols to use standard 6571da177e4SLinus Torvalds * fast string functions */ 6581da177e4SLinus Torvalds for (i = 255; i >= 0; i--) { 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds /* if this table slot is empty (it is not used by an actual 6611da177e4SLinus Torvalds * original char code */ 6621da177e4SLinus Torvalds if (!best_table_len[i]) { 6631da177e4SLinus Torvalds 664cbf7a90eSCao jin /* find the token with the best profit value */ 6651da177e4SLinus Torvalds best = find_best_token(); 666e0a04b11SXiaochen Wang if (token_profit[best] == 0) 667e0a04b11SXiaochen Wang break; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds /* place it in the "best" table */ 670b3dbb4ecSPaulo Marques best_table_len[i] = 2; 671b3dbb4ecSPaulo Marques best_table[i][0] = best & 0xFF; 672b3dbb4ecSPaulo Marques best_table[i][1] = (best >> 8) & 0xFF; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds /* replace this token in all the valid symbols */ 675b3dbb4ecSPaulo Marques compress_symbols(best_table[i], i); 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds /* start by placing the symbols that are actually used on the table */ 6811da177e4SLinus Torvalds static void insert_real_symbols_in_table(void) 6821da177e4SLinus Torvalds { 683b3dbb4ecSPaulo Marques unsigned int i, j, c; 6841da177e4SLinus Torvalds 685b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 6868d605269SMasahiro Yamada for (j = 0; j < table[i]->len; j++) { 6878d605269SMasahiro Yamada c = table[i]->sym[j]; 6881da177e4SLinus Torvalds best_table[c][0]=c; 6891da177e4SLinus Torvalds best_table_len[c]=1; 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds static void optimize_token_table(void) 6951da177e4SLinus Torvalds { 696fcdf7197SZhen Lei build_initial_token_table(); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds insert_real_symbols_in_table(); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds optimize_result(); 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds 703b478b782SLai Jiangshan /* guess for "linker script provide" symbol */ 704b478b782SLai Jiangshan static int may_be_linker_script_provide_symbol(const struct sym_entry *se) 705b478b782SLai Jiangshan { 70629e55ad3SMasahiro Yamada const char *symbol = sym_name(se); 707b478b782SLai Jiangshan int len = se->len - 1; 708b478b782SLai Jiangshan 709b478b782SLai Jiangshan if (len < 8) 710b478b782SLai Jiangshan return 0; 711b478b782SLai Jiangshan 712b478b782SLai Jiangshan if (symbol[0] != '_' || symbol[1] != '_') 713b478b782SLai Jiangshan return 0; 714b478b782SLai Jiangshan 715b478b782SLai Jiangshan /* __start_XXXXX */ 716b478b782SLai Jiangshan if (!memcmp(symbol + 2, "start_", 6)) 717b478b782SLai Jiangshan return 1; 718b478b782SLai Jiangshan 719b478b782SLai Jiangshan /* __stop_XXXXX */ 720b478b782SLai Jiangshan if (!memcmp(symbol + 2, "stop_", 5)) 721b478b782SLai Jiangshan return 1; 722b478b782SLai Jiangshan 723b478b782SLai Jiangshan /* __end_XXXXX */ 724b478b782SLai Jiangshan if (!memcmp(symbol + 2, "end_", 4)) 725b478b782SLai Jiangshan return 1; 726b478b782SLai Jiangshan 727b478b782SLai Jiangshan /* __XXXXX_start */ 728b478b782SLai Jiangshan if (!memcmp(symbol + len - 6, "_start", 6)) 729b478b782SLai Jiangshan return 1; 730b478b782SLai Jiangshan 731b478b782SLai Jiangshan /* __XXXXX_end */ 732b478b782SLai Jiangshan if (!memcmp(symbol + len - 4, "_end", 4)) 733b478b782SLai Jiangshan return 1; 734b478b782SLai Jiangshan 735b478b782SLai Jiangshan return 0; 736b478b782SLai Jiangshan } 737b478b782SLai Jiangshan 738f2df3f65SPaulo Marques static int compare_symbols(const void *a, const void *b) 739f2df3f65SPaulo Marques { 7408d605269SMasahiro Yamada const struct sym_entry *sa = *(const struct sym_entry **)a; 7418d605269SMasahiro Yamada const struct sym_entry *sb = *(const struct sym_entry **)b; 742f2df3f65SPaulo Marques int wa, wb; 743f2df3f65SPaulo Marques 744f2df3f65SPaulo Marques /* sort by address first */ 745f2df3f65SPaulo Marques if (sa->addr > sb->addr) 746f2df3f65SPaulo Marques return 1; 747f2df3f65SPaulo Marques if (sa->addr < sb->addr) 748f2df3f65SPaulo Marques return -1; 749f2df3f65SPaulo Marques 750f2df3f65SPaulo Marques /* sort by "weakness" type */ 751f2df3f65SPaulo Marques wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); 752f2df3f65SPaulo Marques wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); 753f2df3f65SPaulo Marques if (wa != wb) 754f2df3f65SPaulo Marques return wa - wb; 755f2df3f65SPaulo Marques 756b478b782SLai Jiangshan /* sort by "linker script provide" type */ 757b478b782SLai Jiangshan wa = may_be_linker_script_provide_symbol(sa); 758b478b782SLai Jiangshan wb = may_be_linker_script_provide_symbol(sb); 759b478b782SLai Jiangshan if (wa != wb) 760b478b782SLai Jiangshan return wa - wb; 761b478b782SLai Jiangshan 762b478b782SLai Jiangshan /* sort by the number of prefix underscores */ 763aa915245SMasahiro Yamada wa = strspn(sym_name(sa), "_"); 764aa915245SMasahiro Yamada wb = strspn(sym_name(sb), "_"); 765b478b782SLai Jiangshan if (wa != wb) 766b478b782SLai Jiangshan return wa - wb; 767b478b782SLai Jiangshan 768f2df3f65SPaulo Marques /* sort by initial order, so that other symbols are left undisturbed */ 769f2df3f65SPaulo Marques return sa->start_pos - sb->start_pos; 770f2df3f65SPaulo Marques } 771f2df3f65SPaulo Marques 772f2df3f65SPaulo Marques static void sort_symbols(void) 773f2df3f65SPaulo Marques { 7748d605269SMasahiro Yamada qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 775f2df3f65SPaulo Marques } 7761da177e4SLinus Torvalds 777c6bda7c9SRusty Russell static void make_percpus_absolute(void) 778c6bda7c9SRusty Russell { 779c6bda7c9SRusty Russell unsigned int i; 780c6bda7c9SRusty Russell 781c6bda7c9SRusty Russell for (i = 0; i < table_cnt; i++) 7828d605269SMasahiro Yamada if (symbol_in_range(table[i], &percpu_range, 1)) { 7838c996940SArd Biesheuvel /* 7848c996940SArd Biesheuvel * Keep the 'A' override for percpu symbols to 7858c996940SArd Biesheuvel * ensure consistent behavior compared to older 7868c996940SArd Biesheuvel * versions of this tool. 7878c996940SArd Biesheuvel */ 7888d605269SMasahiro Yamada table[i]->sym[0] = 'A'; 7898d605269SMasahiro Yamada table[i]->percpu_absolute = 1; 7908c996940SArd Biesheuvel } 791c6bda7c9SRusty Russell } 792c6bda7c9SRusty Russell 7932213e9a6SArd Biesheuvel /* find the minimum non-absolute symbol address */ 7942213e9a6SArd Biesheuvel static void record_relative_base(void) 7952213e9a6SArd Biesheuvel { 7962213e9a6SArd Biesheuvel unsigned int i; 7972213e9a6SArd Biesheuvel 7982213e9a6SArd Biesheuvel for (i = 0; i < table_cnt; i++) 7998d605269SMasahiro Yamada if (!symbol_absolute(table[i])) { 800f34ea029SMasahiro Yamada /* 801f34ea029SMasahiro Yamada * The table is sorted by address. 802f34ea029SMasahiro Yamada * Take the first non-absolute symbol value. 803f34ea029SMasahiro Yamada */ 8048d605269SMasahiro Yamada relative_base = table[i]->addr; 805f34ea029SMasahiro Yamada return; 806f34ea029SMasahiro Yamada } 8072213e9a6SArd Biesheuvel } 8082213e9a6SArd Biesheuvel 809b3dbb4ecSPaulo Marques int main(int argc, char **argv) 8101da177e4SLinus Torvalds { 811aa221f2eSMasahiro Yamada while (1) { 812aa221f2eSMasahiro Yamada static struct option long_options[] = { 813aa221f2eSMasahiro Yamada {"all-symbols", no_argument, &all_symbols, 1}, 814aa221f2eSMasahiro Yamada {"absolute-percpu", no_argument, &absolute_percpu, 1}, 815aa221f2eSMasahiro Yamada {"base-relative", no_argument, &base_relative, 1}, 816010a0aadSZhen Lei {"lto-clang", no_argument, <o_clang, 1}, 817aa221f2eSMasahiro Yamada {}, 818aa221f2eSMasahiro Yamada }; 819aa221f2eSMasahiro Yamada 820aa221f2eSMasahiro Yamada int c = getopt_long(argc, argv, "", long_options, NULL); 821aa221f2eSMasahiro Yamada 822aa221f2eSMasahiro Yamada if (c == -1) 823aa221f2eSMasahiro Yamada break; 824aa221f2eSMasahiro Yamada if (c != 0) 82541f11a4fSYoshinori Sato usage(); 82641f11a4fSYoshinori Sato } 827aa221f2eSMasahiro Yamada 828aa221f2eSMasahiro Yamada if (optind >= argc) 8291da177e4SLinus Torvalds usage(); 8301da177e4SLinus Torvalds 831aa221f2eSMasahiro Yamada read_map(argv[optind]); 8325e5c4fa7SMasahiro Yamada shrink_table(); 833c6bda7c9SRusty Russell if (absolute_percpu) 834c6bda7c9SRusty Russell make_percpus_absolute(); 835f34ea029SMasahiro Yamada sort_symbols(); 8362213e9a6SArd Biesheuvel if (base_relative) 8372213e9a6SArd Biesheuvel record_relative_base(); 8381da177e4SLinus Torvalds optimize_token_table(); 8391da177e4SLinus Torvalds write_src(); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds return 0; 8421da177e4SLinus Torvalds } 843