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] 964e16609SJann Horn * [--lto-clang] 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 221c975da5SMasahiro Yamada #include <errno.h> 23aa221f2eSMasahiro Yamada #include <getopt.h> 24a41333e0SMasahiro Yamada #include <stdbool.h> 251da177e4SLinus Torvalds #include <stdio.h> 261da177e4SLinus Torvalds #include <stdlib.h> 271da177e4SLinus Torvalds #include <string.h> 281da177e4SLinus Torvalds #include <ctype.h> 292213e9a6SArd Biesheuvel #include <limits.h> 301da177e4SLinus Torvalds 3117b1f0deSMike Frysinger #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 3217b1f0deSMike Frysinger 33b8a94bfbSMiguel Ojeda #define KSYM_NAME_LEN 512 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds struct sym_entry { 361da177e4SLinus Torvalds unsigned long long addr; 37b3dbb4ecSPaulo Marques unsigned int len; 3860443c88SZhen Lei unsigned int seq; 39*1a7c8d24SMasahiro Yamada bool percpu_absolute; 409d82973eSLinus Torvalds unsigned char sym[]; 411da177e4SLinus Torvalds }; 421da177e4SLinus Torvalds 4378eb7159SKees Cook struct addr_range { 4478eb7159SKees Cook const char *start_sym, *end_sym; 4517b1f0deSMike Frysinger unsigned long long start, end; 4617b1f0deSMike Frysinger }; 4717b1f0deSMike Frysinger 4817b1f0deSMike Frysinger static unsigned long long _text; 492213e9a6SArd Biesheuvel static unsigned long long relative_base; 5078eb7159SKees Cook static struct addr_range text_ranges[] = { 5117b1f0deSMike Frysinger { "_stext", "_etext" }, 5217b1f0deSMike Frysinger { "_sinittext", "_einittext" }, 5317b1f0deSMike Frysinger }; 5417b1f0deSMike Frysinger #define text_range_text (&text_ranges[0]) 5517b1f0deSMike Frysinger #define text_range_inittext (&text_ranges[1]) 5617b1f0deSMike Frysinger 57c6bda7c9SRusty Russell static struct addr_range percpu_range = { 58c6bda7c9SRusty Russell "__per_cpu_start", "__per_cpu_end", -1ULL, 0 59c6bda7c9SRusty Russell }; 60c6bda7c9SRusty Russell 618d605269SMasahiro Yamada static struct sym_entry **table; 62b3dbb4ecSPaulo Marques static unsigned int table_size, table_cnt; 63831362fcSMasahiro Yamada static int all_symbols; 64831362fcSMasahiro Yamada static int absolute_percpu; 65010a0aadSZhen Lei static int lto_clang; 661da177e4SLinus Torvalds 67f43e9daaSMasahiro Yamada static int token_profit[0x10000]; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* the table that holds the result of the compression */ 70f43e9daaSMasahiro Yamada static unsigned char best_table[256][2]; 71f43e9daaSMasahiro Yamada static unsigned char best_table_len[256]; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds 74b3dbb4ecSPaulo Marques static void usage(void) 751da177e4SLinus Torvalds { 768d3a7507SYuntao Wang fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " 7764e16609SJann Horn "[--lto-clang] in.map > out.S\n"); 781da177e4SLinus Torvalds exit(1); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 8129e55ad3SMasahiro Yamada static char *sym_name(const struct sym_entry *s) 8229e55ad3SMasahiro Yamada { 8329e55ad3SMasahiro Yamada return (char *)s->sym + 1; 8429e55ad3SMasahiro Yamada } 8529e55ad3SMasahiro Yamada 86a41333e0SMasahiro Yamada static bool is_ignored_symbol(const char *name, char type) 87a41333e0SMasahiro Yamada { 88a7b00a18SMasahiro Yamada if (type == 'u' || type == 'n') 89887df76dSMasahiro Yamada return true; 90887df76dSMasahiro Yamada 91887df76dSMasahiro Yamada if (toupper(type) == 'A') { 92887df76dSMasahiro Yamada /* Keep these useful absolute symbols */ 93887df76dSMasahiro Yamada if (strcmp(name, "__kernel_syscall_via_break") && 94887df76dSMasahiro Yamada strcmp(name, "__kernel_syscall_via_epc") && 95887df76dSMasahiro Yamada strcmp(name, "__kernel_sigtramp") && 96887df76dSMasahiro Yamada strcmp(name, "__gp")) 97887df76dSMasahiro Yamada return true; 98887df76dSMasahiro Yamada } 99887df76dSMasahiro Yamada 100a41333e0SMasahiro Yamada return false; 101a41333e0SMasahiro Yamada } 102a41333e0SMasahiro Yamada 103b6233d0dSMasahiro Yamada static void check_symbol_range(const char *sym, unsigned long long addr, 10478eb7159SKees Cook struct addr_range *ranges, int entries) 10517b1f0deSMike Frysinger { 10617b1f0deSMike Frysinger size_t i; 10778eb7159SKees Cook struct addr_range *ar; 10817b1f0deSMike Frysinger 10978eb7159SKees Cook for (i = 0; i < entries; ++i) { 11078eb7159SKees Cook ar = &ranges[i]; 11117b1f0deSMike Frysinger 11278eb7159SKees Cook if (strcmp(sym, ar->start_sym) == 0) { 11378eb7159SKees Cook ar->start = addr; 114b6233d0dSMasahiro Yamada return; 11578eb7159SKees Cook } else if (strcmp(sym, ar->end_sym) == 0) { 11678eb7159SKees Cook ar->end = addr; 117b6233d0dSMasahiro Yamada return; 11817b1f0deSMike Frysinger } 11917b1f0deSMike Frysinger } 12017b1f0deSMike Frysinger } 12117b1f0deSMike Frysinger 1221c975da5SMasahiro Yamada static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len) 1231da177e4SLinus Torvalds { 1241c975da5SMasahiro Yamada char *name, type, *p; 1258d605269SMasahiro Yamada unsigned long long addr; 1261c975da5SMasahiro Yamada size_t len; 1271c975da5SMasahiro Yamada ssize_t readlen; 1288d605269SMasahiro Yamada struct sym_entry *sym; 1291da177e4SLinus Torvalds 13023835308SJames Clark errno = 0; 1311c975da5SMasahiro Yamada readlen = getline(buf, buf_len, in); 1321c975da5SMasahiro Yamada if (readlen < 0) { 1331c975da5SMasahiro Yamada if (errno) { 1341c975da5SMasahiro Yamada perror("read_symbol"); 1351c975da5SMasahiro Yamada exit(EXIT_FAILURE); 1361c975da5SMasahiro Yamada } 1378d605269SMasahiro Yamada return NULL; 1381da177e4SLinus Torvalds } 1391c975da5SMasahiro Yamada 1401c975da5SMasahiro Yamada if ((*buf)[readlen - 1] == '\n') 1411c975da5SMasahiro Yamada (*buf)[readlen - 1] = 0; 1421c975da5SMasahiro Yamada 1431c975da5SMasahiro Yamada addr = strtoull(*buf, &p, 16); 1441c975da5SMasahiro Yamada 1451c975da5SMasahiro Yamada if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') { 1461c975da5SMasahiro Yamada fprintf(stderr, "line format error\n"); 1471c975da5SMasahiro Yamada exit(EXIT_FAILURE); 1481c975da5SMasahiro Yamada } 1491c975da5SMasahiro Yamada 1501c975da5SMasahiro Yamada name = p; 1511c975da5SMasahiro Yamada len = strlen(name); 1521c975da5SMasahiro Yamada 1531c975da5SMasahiro Yamada if (len >= 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", 1561c975da5SMasahiro Yamada name, len, 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 */ 1721c975da5SMasahiro Yamada len++; 1738d605269SMasahiro Yamada 1749d1b3895SMasahiro Yamada sym = malloc(sizeof(*sym) + len + 1); 1758d605269SMasahiro Yamada if (!sym) { 176f1a136e0SJesper Juhl fprintf(stderr, "kallsyms failure: " 177f1a136e0SJesper Juhl "unable to allocate required amount of memory\n"); 178f1a136e0SJesper Juhl exit(EXIT_FAILURE); 179f1a136e0SJesper Juhl } 1808d605269SMasahiro Yamada sym->addr = addr; 1818d605269SMasahiro Yamada sym->len = len; 1828d605269SMasahiro Yamada sym->sym[0] = type; 1839d1b3895SMasahiro Yamada strcpy(sym_name(sym), name); 184*1a7c8d24SMasahiro Yamada sym->percpu_absolute = false; 1851da177e4SLinus Torvalds 1868d605269SMasahiro Yamada return sym; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1894bfe2b78SMasahiro Yamada static int symbol_in_range(const struct sym_entry *s, 1904bfe2b78SMasahiro Yamada const struct addr_range *ranges, int entries) 19117b1f0deSMike Frysinger { 19217b1f0deSMike Frysinger size_t i; 1934bfe2b78SMasahiro Yamada const struct addr_range *ar; 19417b1f0deSMike Frysinger 19578eb7159SKees Cook for (i = 0; i < entries; ++i) { 19678eb7159SKees Cook ar = &ranges[i]; 19717b1f0deSMike Frysinger 19878eb7159SKees Cook if (s->addr >= ar->start && s->addr <= ar->end) 199ac6ca5c8SMike Frysinger return 1; 20017b1f0deSMike Frysinger } 20117b1f0deSMike Frysinger 202ac6ca5c8SMike Frysinger return 0; 20317b1f0deSMike Frysinger } 20417b1f0deSMike Frysinger 205a7f13d0fSKent Overstreet static bool string_starts_with(const char *s, const char *prefix) 206a7f13d0fSKent Overstreet { 207a7f13d0fSKent Overstreet return strncmp(s, prefix, strlen(prefix)) == 0; 208a7f13d0fSKent Overstreet } 209a7f13d0fSKent Overstreet 2104bfe2b78SMasahiro Yamada static int symbol_valid(const struct sym_entry *s) 2111da177e4SLinus Torvalds { 21229e55ad3SMasahiro Yamada const char *name = sym_name(s); 213bd8b22d2SArd Biesheuvel 2141da177e4SLinus Torvalds /* if --all-symbols is not specified, then symbols outside the text 2151da177e4SLinus Torvalds * and inittext sections are discarded */ 2161da177e4SLinus Torvalds if (!all_symbols) { 217a7f13d0fSKent Overstreet /* 218a7f13d0fSKent Overstreet * Symbols starting with __start and __stop are used to denote 219a7f13d0fSKent Overstreet * section boundaries, and should always be included: 220a7f13d0fSKent Overstreet */ 221a7f13d0fSKent Overstreet if (string_starts_with(name, "__start_") || 222a7f13d0fSKent Overstreet string_starts_with(name, "__stop_")) 223a7f13d0fSKent Overstreet return 1; 224a7f13d0fSKent Overstreet 22578eb7159SKees Cook if (symbol_in_range(s, text_ranges, 22678eb7159SKees Cook ARRAY_SIZE(text_ranges)) == 0) 2271da177e4SLinus Torvalds return 0; 2281da177e4SLinus Torvalds /* Corner case. Discard any symbols with the same value as 229a3b81113SRobin Getz * _etext _einittext; they can move between pass 1 and 2 when 230a3b81113SRobin Getz * the kallsyms data are added. If these symbols move then 231a3b81113SRobin Getz * they may get dropped in pass 2, which breaks the kallsyms 232a3b81113SRobin Getz * rules. 2331da177e4SLinus Torvalds */ 23417b1f0deSMike Frysinger if ((s->addr == text_range_text->end && 23529e55ad3SMasahiro Yamada strcmp(name, text_range_text->end_sym)) || 23617b1f0deSMike Frysinger (s->addr == text_range_inittext->end && 23729e55ad3SMasahiro Yamada strcmp(name, text_range_inittext->end_sym))) 2381da177e4SLinus Torvalds return 0; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds return 1; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 2445e5c4fa7SMasahiro Yamada /* remove all the invalid symbols from the table */ 2455e5c4fa7SMasahiro Yamada static void shrink_table(void) 2465e5c4fa7SMasahiro Yamada { 2475e5c4fa7SMasahiro Yamada unsigned int i, pos; 2485e5c4fa7SMasahiro Yamada 2495e5c4fa7SMasahiro Yamada pos = 0; 2505e5c4fa7SMasahiro Yamada for (i = 0; i < table_cnt; i++) { 2518d605269SMasahiro Yamada if (symbol_valid(table[i])) { 2525e5c4fa7SMasahiro Yamada if (pos != i) 2535e5c4fa7SMasahiro Yamada table[pos] = table[i]; 2545e5c4fa7SMasahiro Yamada pos++; 2555e5c4fa7SMasahiro Yamada } else { 2568d605269SMasahiro Yamada free(table[i]); 2575e5c4fa7SMasahiro Yamada } 2585e5c4fa7SMasahiro Yamada } 2595e5c4fa7SMasahiro Yamada table_cnt = pos; 2605e5c4fa7SMasahiro Yamada } 2615e5c4fa7SMasahiro Yamada 262aa221f2eSMasahiro Yamada static void read_map(const char *in) 2631da177e4SLinus Torvalds { 264aa221f2eSMasahiro Yamada FILE *fp; 2658d605269SMasahiro Yamada struct sym_entry *sym; 2661c975da5SMasahiro Yamada char *buf = NULL; 2671c975da5SMasahiro Yamada size_t buflen = 0; 2688d605269SMasahiro Yamada 269aa221f2eSMasahiro Yamada fp = fopen(in, "r"); 270aa221f2eSMasahiro Yamada if (!fp) { 271aa221f2eSMasahiro Yamada perror(in); 272aa221f2eSMasahiro Yamada exit(1); 273aa221f2eSMasahiro Yamada } 274aa221f2eSMasahiro Yamada 275aa221f2eSMasahiro Yamada while (!feof(fp)) { 2761c975da5SMasahiro Yamada sym = read_symbol(fp, &buf, &buflen); 2778d605269SMasahiro Yamada if (!sym) 2788d605269SMasahiro Yamada continue; 2798d605269SMasahiro Yamada 2801d48f8feSMasahiro Yamada sym->seq = table_cnt; 2818d605269SMasahiro Yamada 282b3dbb4ecSPaulo Marques if (table_cnt >= table_size) { 283b3dbb4ecSPaulo Marques table_size += 10000; 284b3dbb4ecSPaulo Marques table = realloc(table, sizeof(*table) * table_size); 2851da177e4SLinus Torvalds if (!table) { 2861da177e4SLinus Torvalds fprintf(stderr, "out of memory\n"); 287aa221f2eSMasahiro Yamada fclose(fp); 2881da177e4SLinus Torvalds exit (1); 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds } 2918d605269SMasahiro Yamada 2928d605269SMasahiro Yamada table[table_cnt++] = sym; 2931da177e4SLinus Torvalds } 294aa221f2eSMasahiro Yamada 2951c975da5SMasahiro Yamada free(buf); 296aa221f2eSMasahiro Yamada fclose(fp); 297f2df3f65SPaulo Marques } 2981da177e4SLinus Torvalds 2994bfe2b78SMasahiro Yamada static void output_label(const char *label) 3001da177e4SLinus Torvalds { 3011da177e4SLinus Torvalds printf(".globl %s\n", label); 3021da177e4SLinus Torvalds printf("\tALGN\n"); 3031da177e4SLinus Torvalds printf("%s:\n", label); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 306fd2ab2f6SMasahiro Yamada /* Provide proper symbols relocatability by their '_text' relativeness. */ 307fd2ab2f6SMasahiro Yamada static void output_address(unsigned long long addr) 308fd2ab2f6SMasahiro Yamada { 309fd2ab2f6SMasahiro Yamada if (_text <= addr) 310fd2ab2f6SMasahiro Yamada printf("\tPTR\t_text + %#llx\n", addr - _text); 311fd2ab2f6SMasahiro Yamada else 312fd2ab2f6SMasahiro Yamada printf("\tPTR\t_text - %#llx\n", _text - addr); 313fd2ab2f6SMasahiro Yamada } 314fd2ab2f6SMasahiro Yamada 3151da177e4SLinus Torvalds /* uncompress a compressed symbol. When this function is called, the best table 3161da177e4SLinus Torvalds * might still be compressed itself, so the function needs to be recursive */ 3174bfe2b78SMasahiro Yamada static int expand_symbol(const unsigned char *data, int len, char *result) 3181da177e4SLinus Torvalds { 3191da177e4SLinus Torvalds int c, rlen, total=0; 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds while (len) { 3221da177e4SLinus Torvalds c = *data; 3231da177e4SLinus Torvalds /* if the table holds a single char that is the same as the one 3241da177e4SLinus Torvalds * we are looking for, then end the search */ 3251da177e4SLinus Torvalds if (best_table[c][0]==c && best_table_len[c]==1) { 3261da177e4SLinus Torvalds *result++ = c; 3271da177e4SLinus Torvalds total++; 3281da177e4SLinus Torvalds } else { 3291da177e4SLinus Torvalds /* if not, recurse and expand */ 3301da177e4SLinus Torvalds rlen = expand_symbol(best_table[c], best_table_len[c], result); 3311da177e4SLinus Torvalds total += rlen; 3321da177e4SLinus Torvalds result += rlen; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds data++; 3351da177e4SLinus Torvalds len--; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds *result=0; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds return total; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 342*1a7c8d24SMasahiro Yamada static bool symbol_absolute(const struct sym_entry *s) 34378eb7159SKees Cook { 3448c996940SArd Biesheuvel return s->percpu_absolute; 34578eb7159SKees Cook } 34678eb7159SKees Cook 347010a0aadSZhen Lei static void cleanup_symbol_name(char *s) 348010a0aadSZhen Lei { 349010a0aadSZhen Lei char *p; 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 * 3588cc32a9bSYonghong Song * As above, replacing the first '.' in ".llvm." with '\0' does not 3598cc32a9bSYonghong Song * affect the main sorting, but it helps us with subsorting. 360010a0aadSZhen Lei */ 3618cc32a9bSYonghong Song p = strstr(s, ".llvm."); 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 const struct sym_entry *sa = *(const struct sym_entry **)a; 37060443c88SZhen Lei const struct sym_entry *sb = *(const struct sym_entry **)b; 37160443c88SZhen Lei 372dd1553b8SMasahiro Yamada ret = strcmp(sym_name(sa), sym_name(sb)); 37360443c88SZhen Lei if (!ret) { 37460443c88SZhen Lei if (sa->addr > sb->addr) 37560443c88SZhen Lei return 1; 37660443c88SZhen Lei else if (sa->addr < sb->addr) 37760443c88SZhen Lei return -1; 37860443c88SZhen Lei 37960443c88SZhen Lei /* keep old order */ 38060443c88SZhen Lei return (int)(sa->seq - sb->seq); 38160443c88SZhen Lei } 38260443c88SZhen Lei 38360443c88SZhen Lei return ret; 38460443c88SZhen Lei } 38560443c88SZhen Lei 38660443c88SZhen Lei static void sort_symbols_by_name(void) 38760443c88SZhen Lei { 38860443c88SZhen Lei qsort(table, table_cnt, sizeof(table[0]), compare_names); 38960443c88SZhen Lei } 39060443c88SZhen Lei 391b3dbb4ecSPaulo Marques static void write_src(void) 3921da177e4SLinus Torvalds { 393b3dbb4ecSPaulo Marques unsigned int i, k, off; 3941da177e4SLinus Torvalds unsigned int best_idx[256]; 395bde6fb37SMasahiro Yamada unsigned int *markers, markers_cnt; 3969281aceaSTejun Heo char buf[KSYM_NAME_LEN]; 3971da177e4SLinus Torvalds 398500193ecSMasahiro Yamada printf("#include <asm/bitsperlong.h>\n"); 3991da177e4SLinus Torvalds printf("#if BITS_PER_LONG == 64\n"); 4001da177e4SLinus Torvalds printf("#define PTR .quad\n"); 40172d3ebb9SMathias Krause printf("#define ALGN .balign 8\n"); 4021da177e4SLinus Torvalds printf("#else\n"); 4031da177e4SLinus Torvalds printf("#define PTR .long\n"); 40472d3ebb9SMathias Krause printf("#define ALGN .balign 4\n"); 4051da177e4SLinus Torvalds printf("#endif\n"); 4061da177e4SLinus Torvalds 407aad09470SJan Beulich printf("\t.section .rodata, \"a\"\n"); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds output_label("kallsyms_num_syms"); 41080ffbaa5SJan Beulich printf("\t.long\t%u\n", table_cnt); 4111da177e4SLinus Torvalds printf("\n"); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /* table of offset markers, that give the offset in the compressed stream 4141da177e4SLinus Torvalds * every 256 symbols */ 415bde6fb37SMasahiro Yamada markers_cnt = (table_cnt + 255) / 256; 416bde6fb37SMasahiro Yamada markers = malloc(sizeof(*markers) * markers_cnt); 417f1a136e0SJesper Juhl if (!markers) { 418f1a136e0SJesper Juhl fprintf(stderr, "kallsyms failure: " 419f1a136e0SJesper Juhl "unable to allocate required memory\n"); 420f1a136e0SJesper Juhl exit(EXIT_FAILURE); 421f1a136e0SJesper Juhl } 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds output_label("kallsyms_names"); 4241da177e4SLinus Torvalds off = 0; 425b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 426b3dbb4ecSPaulo Marques if ((i & 0xFF) == 0) 427b3dbb4ecSPaulo Marques markers[i >> 8] = off; 42860443c88SZhen Lei table[i]->seq = i; 4291da177e4SLinus Torvalds 43073bbb944SMiguel Ojeda /* There cannot be any symbol of length zero. */ 43173bbb944SMiguel Ojeda if (table[i]->len == 0) { 43273bbb944SMiguel Ojeda fprintf(stderr, "kallsyms failure: " 43373bbb944SMiguel Ojeda "unexpected zero symbol length\n"); 43473bbb944SMiguel Ojeda exit(EXIT_FAILURE); 43573bbb944SMiguel Ojeda } 43673bbb944SMiguel Ojeda 43773bbb944SMiguel Ojeda /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ 43873bbb944SMiguel Ojeda if (table[i]->len > 0x3FFF) { 43973bbb944SMiguel Ojeda fprintf(stderr, "kallsyms failure: " 44073bbb944SMiguel Ojeda "unexpected huge symbol length\n"); 44173bbb944SMiguel Ojeda exit(EXIT_FAILURE); 44273bbb944SMiguel Ojeda } 44373bbb944SMiguel Ojeda 44473bbb944SMiguel Ojeda /* Encode length with ULEB128. */ 44573bbb944SMiguel Ojeda if (table[i]->len <= 0x7F) { 44673bbb944SMiguel Ojeda /* Most symbols use a single byte for the length. */ 4478d605269SMasahiro Yamada printf("\t.byte 0x%02x", table[i]->len); 44873bbb944SMiguel Ojeda off += table[i]->len + 1; 44973bbb944SMiguel Ojeda } else { 45073bbb944SMiguel Ojeda /* "Big" symbols use two bytes. */ 45173bbb944SMiguel Ojeda printf("\t.byte 0x%02x, 0x%02x", 45273bbb944SMiguel Ojeda (table[i]->len & 0x7F) | 0x80, 45373bbb944SMiguel Ojeda (table[i]->len >> 7) & 0x7F); 45473bbb944SMiguel Ojeda off += table[i]->len + 2; 45573bbb944SMiguel Ojeda } 4568d605269SMasahiro Yamada for (k = 0; k < table[i]->len; k++) 4578d605269SMasahiro Yamada printf(", 0x%02x", table[i]->sym[k]); 4581da177e4SLinus Torvalds 459dd1553b8SMasahiro Yamada /* 460f9c3d671SMasahiro Yamada * Now that we wrote out the compressed symbol name, restore the 461f9c3d671SMasahiro Yamada * original name and print it in the comment. 462dd1553b8SMasahiro Yamada */ 463dd1553b8SMasahiro Yamada expand_symbol(table[i]->sym, table[i]->len, buf); 464dd1553b8SMasahiro Yamada strcpy((char *)table[i]->sym, buf); 465f9c3d671SMasahiro Yamada printf("\t/* %s */\n", table[i]->sym); 466dd1553b8SMasahiro Yamada } 467f9c3d671SMasahiro Yamada printf("\n"); 468dd1553b8SMasahiro Yamada 4691da177e4SLinus Torvalds output_label("kallsyms_markers"); 470bde6fb37SMasahiro Yamada for (i = 0; i < markers_cnt; i++) 47180ffbaa5SJan Beulich printf("\t.long\t%u\n", markers[i]); 4721da177e4SLinus Torvalds printf("\n"); 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds free(markers); 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds output_label("kallsyms_token_table"); 4771da177e4SLinus Torvalds off = 0; 4781da177e4SLinus Torvalds for (i = 0; i < 256; i++) { 4791da177e4SLinus Torvalds best_idx[i] = off; 4801da177e4SLinus Torvalds expand_symbol(best_table[i], best_table_len[i], buf); 4811da177e4SLinus Torvalds printf("\t.asciz\t\"%s\"\n", buf); 4821da177e4SLinus Torvalds off += strlen(buf) + 1; 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds printf("\n"); 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds output_label("kallsyms_token_index"); 4871da177e4SLinus Torvalds for (i = 0; i < 256; i++) 4881da177e4SLinus Torvalds printf("\t.short\t%d\n", best_idx[i]); 4891da177e4SLinus Torvalds printf("\n"); 490404bad70SMasahiro Yamada 491404bad70SMasahiro Yamada output_label("kallsyms_offsets"); 492404bad70SMasahiro Yamada 493404bad70SMasahiro Yamada for (i = 0; i < table_cnt; i++) { 494404bad70SMasahiro Yamada /* 495404bad70SMasahiro Yamada * Use the offset relative to the lowest value 496404bad70SMasahiro Yamada * encountered of all relative symbols, and emit 497404bad70SMasahiro Yamada * non-relocatable fixed offsets that will be fixed 498404bad70SMasahiro Yamada * up at runtime. 499404bad70SMasahiro Yamada */ 500404bad70SMasahiro Yamada 501404bad70SMasahiro Yamada long long offset; 502404bad70SMasahiro Yamada int overflow; 503404bad70SMasahiro Yamada 504404bad70SMasahiro Yamada if (!absolute_percpu) { 505404bad70SMasahiro Yamada offset = table[i]->addr - relative_base; 506404bad70SMasahiro Yamada overflow = (offset < 0 || offset > UINT_MAX); 507404bad70SMasahiro Yamada } else if (symbol_absolute(table[i])) { 508404bad70SMasahiro Yamada offset = table[i]->addr; 509404bad70SMasahiro Yamada overflow = (offset < 0 || offset > INT_MAX); 510404bad70SMasahiro Yamada } else { 511404bad70SMasahiro Yamada offset = relative_base - table[i]->addr - 1; 512404bad70SMasahiro Yamada overflow = (offset < INT_MIN || offset >= 0); 513404bad70SMasahiro Yamada } 514404bad70SMasahiro Yamada if (overflow) { 515404bad70SMasahiro Yamada fprintf(stderr, "kallsyms failure: " 516404bad70SMasahiro Yamada "%s symbol value %#llx out of range in relative mode\n", 517404bad70SMasahiro Yamada symbol_absolute(table[i]) ? "absolute" : "relative", 518404bad70SMasahiro Yamada table[i]->addr); 519404bad70SMasahiro Yamada exit(EXIT_FAILURE); 520404bad70SMasahiro Yamada } 521b07e1810SMasahiro Yamada printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym); 522404bad70SMasahiro Yamada } 523404bad70SMasahiro Yamada printf("\n"); 524404bad70SMasahiro Yamada 525404bad70SMasahiro Yamada output_label("kallsyms_relative_base"); 526404bad70SMasahiro Yamada output_address(relative_base); 527404bad70SMasahiro Yamada printf("\n"); 528404bad70SMasahiro Yamada 529dd1553b8SMasahiro Yamada if (lto_clang) 530dd1553b8SMasahiro Yamada for (i = 0; i < table_cnt; i++) 531dd1553b8SMasahiro Yamada cleanup_symbol_name((char *)table[i]->sym); 532dd1553b8SMasahiro Yamada 533404bad70SMasahiro Yamada sort_symbols_by_name(); 534404bad70SMasahiro Yamada output_label("kallsyms_seqs_of_names"); 535404bad70SMasahiro Yamada for (i = 0; i < table_cnt; i++) 536f9c3d671SMasahiro Yamada printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n", 537404bad70SMasahiro Yamada (unsigned char)(table[i]->seq >> 16), 538404bad70SMasahiro Yamada (unsigned char)(table[i]->seq >> 8), 539f9c3d671SMasahiro Yamada (unsigned char)(table[i]->seq >> 0), 540f9c3d671SMasahiro Yamada table[i]->sym); 541404bad70SMasahiro Yamada printf("\n"); 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds /* table lookup compression functions */ 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds /* count all the possible tokens in a symbol */ 5484bfe2b78SMasahiro Yamada static void learn_symbol(const unsigned char *symbol, int len) 5491da177e4SLinus Torvalds { 5501da177e4SLinus Torvalds int i; 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds for (i = 0; i < len - 1; i++) 553b3dbb4ecSPaulo Marques token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /* decrease the count for all the possible tokens in a symbol */ 5574bfe2b78SMasahiro Yamada static void forget_symbol(const unsigned char *symbol, int len) 5581da177e4SLinus Torvalds { 5591da177e4SLinus Torvalds int i; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds for (i = 0; i < len - 1; i++) 562b3dbb4ecSPaulo Marques token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5655e5c4fa7SMasahiro Yamada /* do the initial token count */ 566fcdf7197SZhen Lei static void build_initial_token_table(void) 5671da177e4SLinus Torvalds { 5685e5c4fa7SMasahiro Yamada unsigned int i; 5691da177e4SLinus Torvalds 5705e5c4fa7SMasahiro Yamada for (i = 0; i < table_cnt; i++) 5718d605269SMasahiro Yamada learn_symbol(table[i]->sym, table[i]->len); 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 5742558c138SMasahiro Yamada static unsigned char *find_token(unsigned char *str, int len, 5754bfe2b78SMasahiro Yamada const unsigned char *token) 5767c5d249aSPaulo Marques { 5777c5d249aSPaulo Marques int i; 5787c5d249aSPaulo Marques 5797c5d249aSPaulo Marques for (i = 0; i < len - 1; i++) { 5807c5d249aSPaulo Marques if (str[i] == token[0] && str[i+1] == token[1]) 5817c5d249aSPaulo Marques return &str[i]; 5827c5d249aSPaulo Marques } 5837c5d249aSPaulo Marques return NULL; 5847c5d249aSPaulo Marques } 5857c5d249aSPaulo Marques 5861da177e4SLinus Torvalds /* replace a given token in all the valid symbols. Use the sampled symbols 5871da177e4SLinus Torvalds * to update the counts */ 5884bfe2b78SMasahiro Yamada static void compress_symbols(const unsigned char *str, int idx) 5891da177e4SLinus Torvalds { 590b3dbb4ecSPaulo Marques unsigned int i, len, size; 591b3dbb4ecSPaulo Marques unsigned char *p1, *p2; 5921da177e4SLinus Torvalds 593b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 5941da177e4SLinus Torvalds 5958d605269SMasahiro Yamada len = table[i]->len; 5968d605269SMasahiro Yamada p1 = table[i]->sym; 597b3dbb4ecSPaulo Marques 598b3dbb4ecSPaulo Marques /* find the token on the symbol */ 5997c5d249aSPaulo Marques p2 = find_token(p1, len, str); 600b3dbb4ecSPaulo Marques if (!p2) continue; 601b3dbb4ecSPaulo Marques 602b3dbb4ecSPaulo Marques /* decrease the counts for this symbol's tokens */ 6038d605269SMasahiro Yamada forget_symbol(table[i]->sym, len); 604b3dbb4ecSPaulo Marques 605b3dbb4ecSPaulo Marques size = len; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds do { 608b3dbb4ecSPaulo Marques *p2 = idx; 609b3dbb4ecSPaulo Marques p2++; 610b3dbb4ecSPaulo Marques size -= (p2 - p1); 611b3dbb4ecSPaulo Marques memmove(p2, p2 + 1, size); 612b3dbb4ecSPaulo Marques p1 = p2; 613b3dbb4ecSPaulo Marques len--; 614b3dbb4ecSPaulo Marques 615b3dbb4ecSPaulo Marques if (size < 2) break; 616b3dbb4ecSPaulo Marques 6171da177e4SLinus Torvalds /* find the token on the symbol */ 6187c5d249aSPaulo Marques p2 = find_token(p1, size, str); 6191da177e4SLinus Torvalds 620b3dbb4ecSPaulo Marques } while (p2); 6211da177e4SLinus Torvalds 6228d605269SMasahiro Yamada table[i]->len = len; 623b3dbb4ecSPaulo Marques 624b3dbb4ecSPaulo Marques /* increase the counts for this symbol's new tokens */ 6258d605269SMasahiro Yamada learn_symbol(table[i]->sym, len); 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /* search the token with the maximum profit */ 630b3dbb4ecSPaulo Marques static int find_best_token(void) 6311da177e4SLinus Torvalds { 632b3dbb4ecSPaulo Marques int i, best, bestprofit; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds bestprofit=-10000; 635b3dbb4ecSPaulo Marques best = 0; 6361da177e4SLinus Torvalds 637b3dbb4ecSPaulo Marques for (i = 0; i < 0x10000; i++) { 638b3dbb4ecSPaulo Marques if (token_profit[i] > bestprofit) { 639b3dbb4ecSPaulo Marques best = i; 640b3dbb4ecSPaulo Marques bestprofit = token_profit[i]; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds return best; 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds /* this is the core of the algorithm: calculate the "best" table */ 6471da177e4SLinus Torvalds static void optimize_result(void) 6481da177e4SLinus Torvalds { 649b3dbb4ecSPaulo Marques int i, best; 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* using the '\0' symbol last allows compress_symbols to use standard 6521da177e4SLinus Torvalds * fast string functions */ 6531da177e4SLinus Torvalds for (i = 255; i >= 0; i--) { 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds /* if this table slot is empty (it is not used by an actual 6561da177e4SLinus Torvalds * original char code */ 6571da177e4SLinus Torvalds if (!best_table_len[i]) { 6581da177e4SLinus Torvalds 659cbf7a90eSCao jin /* find the token with the best profit value */ 6601da177e4SLinus Torvalds best = find_best_token(); 661e0a04b11SXiaochen Wang if (token_profit[best] == 0) 662e0a04b11SXiaochen Wang break; 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds /* place it in the "best" table */ 665b3dbb4ecSPaulo Marques best_table_len[i] = 2; 666b3dbb4ecSPaulo Marques best_table[i][0] = best & 0xFF; 667b3dbb4ecSPaulo Marques best_table[i][1] = (best >> 8) & 0xFF; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds /* replace this token in all the valid symbols */ 670b3dbb4ecSPaulo Marques compress_symbols(best_table[i], i); 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds /* start by placing the symbols that are actually used on the table */ 6761da177e4SLinus Torvalds static void insert_real_symbols_in_table(void) 6771da177e4SLinus Torvalds { 678b3dbb4ecSPaulo Marques unsigned int i, j, c; 6791da177e4SLinus Torvalds 680b3dbb4ecSPaulo Marques for (i = 0; i < table_cnt; i++) { 6818d605269SMasahiro Yamada for (j = 0; j < table[i]->len; j++) { 6828d605269SMasahiro Yamada c = table[i]->sym[j]; 6831da177e4SLinus Torvalds best_table[c][0]=c; 6841da177e4SLinus Torvalds best_table_len[c]=1; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds static void optimize_token_table(void) 6901da177e4SLinus Torvalds { 691fcdf7197SZhen Lei build_initial_token_table(); 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds insert_real_symbols_in_table(); 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds optimize_result(); 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds 698b478b782SLai Jiangshan /* guess for "linker script provide" symbol */ 699b478b782SLai Jiangshan static int may_be_linker_script_provide_symbol(const struct sym_entry *se) 700b478b782SLai Jiangshan { 70129e55ad3SMasahiro Yamada const char *symbol = sym_name(se); 702b478b782SLai Jiangshan int len = se->len - 1; 703b478b782SLai Jiangshan 704b478b782SLai Jiangshan if (len < 8) 705b478b782SLai Jiangshan return 0; 706b478b782SLai Jiangshan 707b478b782SLai Jiangshan if (symbol[0] != '_' || symbol[1] != '_') 708b478b782SLai Jiangshan return 0; 709b478b782SLai Jiangshan 710b478b782SLai Jiangshan /* __start_XXXXX */ 711b478b782SLai Jiangshan if (!memcmp(symbol + 2, "start_", 6)) 712b478b782SLai Jiangshan return 1; 713b478b782SLai Jiangshan 714b478b782SLai Jiangshan /* __stop_XXXXX */ 715b478b782SLai Jiangshan if (!memcmp(symbol + 2, "stop_", 5)) 716b478b782SLai Jiangshan return 1; 717b478b782SLai Jiangshan 718b478b782SLai Jiangshan /* __end_XXXXX */ 719b478b782SLai Jiangshan if (!memcmp(symbol + 2, "end_", 4)) 720b478b782SLai Jiangshan return 1; 721b478b782SLai Jiangshan 722b478b782SLai Jiangshan /* __XXXXX_start */ 723b478b782SLai Jiangshan if (!memcmp(symbol + len - 6, "_start", 6)) 724b478b782SLai Jiangshan return 1; 725b478b782SLai Jiangshan 726b478b782SLai Jiangshan /* __XXXXX_end */ 727b478b782SLai Jiangshan if (!memcmp(symbol + len - 4, "_end", 4)) 728b478b782SLai Jiangshan return 1; 729b478b782SLai Jiangshan 730b478b782SLai Jiangshan return 0; 731b478b782SLai Jiangshan } 732b478b782SLai Jiangshan 733f2df3f65SPaulo Marques static int compare_symbols(const void *a, const void *b) 734f2df3f65SPaulo Marques { 7358d605269SMasahiro Yamada const struct sym_entry *sa = *(const struct sym_entry **)a; 7368d605269SMasahiro Yamada const struct sym_entry *sb = *(const struct sym_entry **)b; 737f2df3f65SPaulo Marques int wa, wb; 738f2df3f65SPaulo Marques 739f2df3f65SPaulo Marques /* sort by address first */ 740f2df3f65SPaulo Marques if (sa->addr > sb->addr) 741f2df3f65SPaulo Marques return 1; 742f2df3f65SPaulo Marques if (sa->addr < sb->addr) 743f2df3f65SPaulo Marques return -1; 744f2df3f65SPaulo Marques 745f2df3f65SPaulo Marques /* sort by "weakness" type */ 746f2df3f65SPaulo Marques wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); 747f2df3f65SPaulo Marques wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); 748f2df3f65SPaulo Marques if (wa != wb) 749f2df3f65SPaulo Marques return wa - wb; 750f2df3f65SPaulo Marques 751b478b782SLai Jiangshan /* sort by "linker script provide" type */ 752b478b782SLai Jiangshan wa = may_be_linker_script_provide_symbol(sa); 753b478b782SLai Jiangshan wb = may_be_linker_script_provide_symbol(sb); 754b478b782SLai Jiangshan if (wa != wb) 755b478b782SLai Jiangshan return wa - wb; 756b478b782SLai Jiangshan 757b478b782SLai Jiangshan /* sort by the number of prefix underscores */ 758aa915245SMasahiro Yamada wa = strspn(sym_name(sa), "_"); 759aa915245SMasahiro Yamada wb = strspn(sym_name(sb), "_"); 760b478b782SLai Jiangshan if (wa != wb) 761b478b782SLai Jiangshan return wa - wb; 762b478b782SLai Jiangshan 763f2df3f65SPaulo Marques /* sort by initial order, so that other symbols are left undisturbed */ 7641d48f8feSMasahiro Yamada return sa->seq - sb->seq; 765f2df3f65SPaulo Marques } 766f2df3f65SPaulo Marques 767f2df3f65SPaulo Marques static void sort_symbols(void) 768f2df3f65SPaulo Marques { 7698d605269SMasahiro Yamada qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 770f2df3f65SPaulo Marques } 7711da177e4SLinus Torvalds 772c6bda7c9SRusty Russell static void make_percpus_absolute(void) 773c6bda7c9SRusty Russell { 774c6bda7c9SRusty Russell unsigned int i; 775c6bda7c9SRusty Russell 776c6bda7c9SRusty Russell for (i = 0; i < table_cnt; i++) 7778d605269SMasahiro Yamada if (symbol_in_range(table[i], &percpu_range, 1)) { 7788c996940SArd Biesheuvel /* 7798c996940SArd Biesheuvel * Keep the 'A' override for percpu symbols to 7808c996940SArd Biesheuvel * ensure consistent behavior compared to older 7818c996940SArd Biesheuvel * versions of this tool. 7828c996940SArd Biesheuvel */ 7838d605269SMasahiro Yamada table[i]->sym[0] = 'A'; 784*1a7c8d24SMasahiro Yamada table[i]->percpu_absolute = true; 7858c996940SArd Biesheuvel } 786c6bda7c9SRusty Russell } 787c6bda7c9SRusty Russell 7882213e9a6SArd Biesheuvel /* find the minimum non-absolute symbol address */ 7892213e9a6SArd Biesheuvel static void record_relative_base(void) 7902213e9a6SArd Biesheuvel { 7912213e9a6SArd Biesheuvel unsigned int i; 7922213e9a6SArd Biesheuvel 7932213e9a6SArd Biesheuvel for (i = 0; i < table_cnt; i++) 7948d605269SMasahiro Yamada if (!symbol_absolute(table[i])) { 795f34ea029SMasahiro Yamada /* 796f34ea029SMasahiro Yamada * The table is sorted by address. 797f34ea029SMasahiro Yamada * Take the first non-absolute symbol value. 798f34ea029SMasahiro Yamada */ 7998d605269SMasahiro Yamada relative_base = table[i]->addr; 800f34ea029SMasahiro Yamada return; 801f34ea029SMasahiro Yamada } 8022213e9a6SArd Biesheuvel } 8032213e9a6SArd Biesheuvel 804b3dbb4ecSPaulo Marques int main(int argc, char **argv) 8051da177e4SLinus Torvalds { 806aa221f2eSMasahiro Yamada while (1) { 80792e74fb6SMasahiro Yamada static const struct option long_options[] = { 808aa221f2eSMasahiro Yamada {"all-symbols", no_argument, &all_symbols, 1}, 809aa221f2eSMasahiro Yamada {"absolute-percpu", no_argument, &absolute_percpu, 1}, 810010a0aadSZhen Lei {"lto-clang", no_argument, <o_clang, 1}, 811aa221f2eSMasahiro Yamada {}, 812aa221f2eSMasahiro Yamada }; 813aa221f2eSMasahiro Yamada 814aa221f2eSMasahiro Yamada int c = getopt_long(argc, argv, "", long_options, NULL); 815aa221f2eSMasahiro Yamada 816aa221f2eSMasahiro Yamada if (c == -1) 817aa221f2eSMasahiro Yamada break; 818aa221f2eSMasahiro Yamada if (c != 0) 81941f11a4fSYoshinori Sato usage(); 82041f11a4fSYoshinori Sato } 821aa221f2eSMasahiro Yamada 822aa221f2eSMasahiro Yamada if (optind >= argc) 8231da177e4SLinus Torvalds usage(); 8241da177e4SLinus Torvalds 825aa221f2eSMasahiro Yamada read_map(argv[optind]); 8265e5c4fa7SMasahiro Yamada shrink_table(); 827c6bda7c9SRusty Russell if (absolute_percpu) 828c6bda7c9SRusty Russell make_percpus_absolute(); 829f34ea029SMasahiro Yamada sort_symbols(); 8302213e9a6SArd Biesheuvel record_relative_base(); 8311da177e4SLinus Torvalds optimize_token_table(); 8321da177e4SLinus Torvalds write_src(); 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds return 0; 8351da177e4SLinus Torvalds } 836