18c2ecf20Sopenharmony_ci/* Generate assembler source containing symbol information 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright 2002 by Kai Germaschewski 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms 68c2ecf20Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Table compression uses all the unused char codes on the symbols and 118c2ecf20Sopenharmony_ci * maps these to the most used substrings (tokens). For instance, it might 128c2ecf20Sopenharmony_ci * map char code 0xF7 to represent "write_" and then in every symbol where 138c2ecf20Sopenharmony_ci * "write_" appears it can be replaced by 0xF7, saving 5 bytes. 148c2ecf20Sopenharmony_ci * The used codes themselves are also placed in the table so that the 158c2ecf20Sopenharmony_ci * decompresion can work without "special cases". 168c2ecf20Sopenharmony_ci * Applied to kernel symbols, this usually produces a compression ratio 178c2ecf20Sopenharmony_ci * of about 50%. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <stdbool.h> 228c2ecf20Sopenharmony_ci#include <stdio.h> 238c2ecf20Sopenharmony_ci#include <stdlib.h> 248c2ecf20Sopenharmony_ci#include <string.h> 258c2ecf20Sopenharmony_ci#include <ctype.h> 268c2ecf20Sopenharmony_ci#include <limits.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define KSYM_NAME_LEN 128 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct sym_entry { 338c2ecf20Sopenharmony_ci unsigned long long addr; 348c2ecf20Sopenharmony_ci unsigned int len; 358c2ecf20Sopenharmony_ci unsigned int start_pos; 368c2ecf20Sopenharmony_ci unsigned int percpu_absolute; 378c2ecf20Sopenharmony_ci unsigned char sym[]; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct addr_range { 418c2ecf20Sopenharmony_ci const char *start_sym, *end_sym; 428c2ecf20Sopenharmony_ci unsigned long long start, end; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic unsigned long long _text; 468c2ecf20Sopenharmony_cistatic unsigned long long relative_base; 478c2ecf20Sopenharmony_cistatic struct addr_range text_ranges[] = { 488c2ecf20Sopenharmony_ci { "_stext", "_etext" }, 498c2ecf20Sopenharmony_ci { "_sinittext", "_einittext" }, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci#define text_range_text (&text_ranges[0]) 528c2ecf20Sopenharmony_ci#define text_range_inittext (&text_ranges[1]) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic struct addr_range percpu_range = { 558c2ecf20Sopenharmony_ci "__per_cpu_start", "__per_cpu_end", -1ULL, 0 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct sym_entry **table; 598c2ecf20Sopenharmony_cistatic unsigned int table_size, table_cnt; 608c2ecf20Sopenharmony_cistatic int all_symbols; 618c2ecf20Sopenharmony_cistatic int absolute_percpu; 628c2ecf20Sopenharmony_cistatic int base_relative; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int token_profit[0x10000]; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* the table that holds the result of the compression */ 678c2ecf20Sopenharmony_cistatic unsigned char best_table[256][2]; 688c2ecf20Sopenharmony_cistatic unsigned char best_table_len[256]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void usage(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: kallsyms [--all-symbols] " 748c2ecf20Sopenharmony_ci "[--base-relative] < in.map > out.S\n"); 758c2ecf20Sopenharmony_ci exit(1); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic char *sym_name(const struct sym_entry *s) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return (char *)s->sym + 1; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic bool is_ignored_symbol(const char *name, char type) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci /* Symbol names that exactly match to the following are ignored.*/ 868c2ecf20Sopenharmony_ci static const char * const ignored_symbols[] = { 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * Symbols which vary between passes. Passes 1 and 2 must have 898c2ecf20Sopenharmony_ci * identical symbol lists. The kallsyms_* symbols below are 908c2ecf20Sopenharmony_ci * only added after pass 1, they would be included in pass 2 918c2ecf20Sopenharmony_ci * when --all-symbols is specified so exclude them to get a 928c2ecf20Sopenharmony_ci * stable symbol list. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci "kallsyms_addresses", 958c2ecf20Sopenharmony_ci "kallsyms_offsets", 968c2ecf20Sopenharmony_ci "kallsyms_relative_base", 978c2ecf20Sopenharmony_ci "kallsyms_num_syms", 988c2ecf20Sopenharmony_ci "kallsyms_names", 998c2ecf20Sopenharmony_ci "kallsyms_markers", 1008c2ecf20Sopenharmony_ci "kallsyms_token_table", 1018c2ecf20Sopenharmony_ci "kallsyms_token_index", 1028c2ecf20Sopenharmony_ci /* Exclude linker generated symbols which vary between passes */ 1038c2ecf20Sopenharmony_ci "_SDA_BASE_", /* ppc */ 1048c2ecf20Sopenharmony_ci "_SDA2_BASE_", /* ppc */ 1058c2ecf20Sopenharmony_ci NULL 1068c2ecf20Sopenharmony_ci }; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Symbol names that begin with the following are ignored.*/ 1098c2ecf20Sopenharmony_ci static const char * const ignored_prefixes[] = { 1108c2ecf20Sopenharmony_ci "$", /* local symbols for ARM, MIPS, etc. */ 1118c2ecf20Sopenharmony_ci "L0", /* LoongArch local symbols */ 1128c2ecf20Sopenharmony_ci ".L", /* LoongArch/S390 local symbols */ 1138c2ecf20Sopenharmony_ci "__crc_", /* modversions */ 1148c2ecf20Sopenharmony_ci "__efistub_", /* arm64 EFI stub namespace */ 1158c2ecf20Sopenharmony_ci "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ 1168c2ecf20Sopenharmony_ci "__AArch64ADRPThunk_", /* arm64 lld */ 1178c2ecf20Sopenharmony_ci "__ARMV5PILongThunk_", /* arm lld */ 1188c2ecf20Sopenharmony_ci "__ARMV7PILongThunk_", 1198c2ecf20Sopenharmony_ci "__ThumbV7PILongThunk_", 1208c2ecf20Sopenharmony_ci "__LA25Thunk_", /* mips lld */ 1218c2ecf20Sopenharmony_ci "__microLA25Thunk_", 1228c2ecf20Sopenharmony_ci NULL 1238c2ecf20Sopenharmony_ci }; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Symbol names that end with the following are ignored.*/ 1268c2ecf20Sopenharmony_ci static const char * const ignored_suffixes[] = { 1278c2ecf20Sopenharmony_ci "_from_arm", /* arm */ 1288c2ecf20Sopenharmony_ci "_from_thumb", /* arm */ 1298c2ecf20Sopenharmony_ci "_veneer", /* arm */ 1308c2ecf20Sopenharmony_ci NULL 1318c2ecf20Sopenharmony_ci }; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Symbol names that contain the following are ignored.*/ 1348c2ecf20Sopenharmony_ci static const char * const ignored_matches[] = { 1358c2ecf20Sopenharmony_ci ".long_branch.", /* ppc stub */ 1368c2ecf20Sopenharmony_ci ".plt_branch.", /* ppc stub */ 1378c2ecf20Sopenharmony_ci NULL 1388c2ecf20Sopenharmony_ci }; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci const char * const *p; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for (p = ignored_symbols; *p; p++) 1438c2ecf20Sopenharmony_ci if (!strcmp(name, *p)) 1448c2ecf20Sopenharmony_ci return true; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (p = ignored_prefixes; *p; p++) 1478c2ecf20Sopenharmony_ci if (!strncmp(name, *p, strlen(*p))) 1488c2ecf20Sopenharmony_ci return true; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci for (p = ignored_suffixes; *p; p++) { 1518c2ecf20Sopenharmony_ci int l = strlen(name) - strlen(*p); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (l >= 0 && !strcmp(name + l, *p)) 1548c2ecf20Sopenharmony_ci return true; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci for (p = ignored_matches; *p; p++) { 1588c2ecf20Sopenharmony_ci if (strstr(name, *p)) 1598c2ecf20Sopenharmony_ci return true; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (type == 'U' || type == 'u') 1638c2ecf20Sopenharmony_ci return true; 1648c2ecf20Sopenharmony_ci /* exclude debugging symbols */ 1658c2ecf20Sopenharmony_ci if (type == 'N' || type == 'n') 1668c2ecf20Sopenharmony_ci return true; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (toupper(type) == 'A') { 1698c2ecf20Sopenharmony_ci /* Keep these useful absolute symbols */ 1708c2ecf20Sopenharmony_ci if (strcmp(name, "__kernel_syscall_via_break") && 1718c2ecf20Sopenharmony_ci strcmp(name, "__kernel_syscall_via_epc") && 1728c2ecf20Sopenharmony_ci strcmp(name, "__kernel_sigtramp") && 1738c2ecf20Sopenharmony_ci strcmp(name, "__gp")) 1748c2ecf20Sopenharmony_ci return true; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return false; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void check_symbol_range(const char *sym, unsigned long long addr, 1818c2ecf20Sopenharmony_ci struct addr_range *ranges, int entries) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci size_t i; 1848c2ecf20Sopenharmony_ci struct addr_range *ar; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci for (i = 0; i < entries; ++i) { 1878c2ecf20Sopenharmony_ci ar = &ranges[i]; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (strcmp(sym, ar->start_sym) == 0) { 1908c2ecf20Sopenharmony_ci ar->start = addr; 1918c2ecf20Sopenharmony_ci return; 1928c2ecf20Sopenharmony_ci } else if (strcmp(sym, ar->end_sym) == 0) { 1938c2ecf20Sopenharmony_ci ar->end = addr; 1948c2ecf20Sopenharmony_ci return; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic struct sym_entry *read_symbol(FILE *in) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci char name[500], type; 2028c2ecf20Sopenharmony_ci unsigned long long addr; 2038c2ecf20Sopenharmony_ci unsigned int len; 2048c2ecf20Sopenharmony_ci struct sym_entry *sym; 2058c2ecf20Sopenharmony_ci int rc; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name); 2088c2ecf20Sopenharmony_ci if (rc != 3) { 2098c2ecf20Sopenharmony_ci if (rc != EOF && fgets(name, 500, in) == NULL) 2108c2ecf20Sopenharmony_ci fprintf(stderr, "Read error or end of file.\n"); 2118c2ecf20Sopenharmony_ci return NULL; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if (strlen(name) >= KSYM_NAME_LEN) { 2148c2ecf20Sopenharmony_ci fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n" 2158c2ecf20Sopenharmony_ci "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", 2168c2ecf20Sopenharmony_ci name, strlen(name), KSYM_NAME_LEN); 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (strcmp(name, "_text") == 0) 2218c2ecf20Sopenharmony_ci _text = addr; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Ignore most absolute/undefined (?) symbols. */ 2248c2ecf20Sopenharmony_ci if (is_ignored_symbol(name, type)) 2258c2ecf20Sopenharmony_ci return NULL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); 2288c2ecf20Sopenharmony_ci check_symbol_range(name, addr, &percpu_range, 1); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* include the type field in the symbol name, so that it gets 2318c2ecf20Sopenharmony_ci * compressed together */ 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci len = strlen(name) + 1; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci sym = malloc(sizeof(*sym) + len + 1); 2368c2ecf20Sopenharmony_ci if (!sym) { 2378c2ecf20Sopenharmony_ci fprintf(stderr, "kallsyms failure: " 2388c2ecf20Sopenharmony_ci "unable to allocate required amount of memory\n"); 2398c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci sym->addr = addr; 2428c2ecf20Sopenharmony_ci sym->len = len; 2438c2ecf20Sopenharmony_ci sym->sym[0] = type; 2448c2ecf20Sopenharmony_ci strcpy(sym_name(sym), name); 2458c2ecf20Sopenharmony_ci sym->percpu_absolute = 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return sym; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int symbol_in_range(const struct sym_entry *s, 2518c2ecf20Sopenharmony_ci const struct addr_range *ranges, int entries) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci size_t i; 2548c2ecf20Sopenharmony_ci const struct addr_range *ar; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (i = 0; i < entries; ++i) { 2578c2ecf20Sopenharmony_ci ar = &ranges[i]; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (s->addr >= ar->start && s->addr <= ar->end) 2608c2ecf20Sopenharmony_ci return 1; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int symbol_valid(const struct sym_entry *s) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci const char *name = sym_name(s); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* if --all-symbols is not specified, then symbols outside the text 2718c2ecf20Sopenharmony_ci * and inittext sections are discarded */ 2728c2ecf20Sopenharmony_ci if (!all_symbols) { 2738c2ecf20Sopenharmony_ci if (symbol_in_range(s, text_ranges, 2748c2ecf20Sopenharmony_ci ARRAY_SIZE(text_ranges)) == 0) 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci /* Corner case. Discard any symbols with the same value as 2778c2ecf20Sopenharmony_ci * _etext _einittext; they can move between pass 1 and 2 when 2788c2ecf20Sopenharmony_ci * the kallsyms data are added. If these symbols move then 2798c2ecf20Sopenharmony_ci * they may get dropped in pass 2, which breaks the kallsyms 2808c2ecf20Sopenharmony_ci * rules. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci if ((s->addr == text_range_text->end && 2838c2ecf20Sopenharmony_ci strcmp(name, text_range_text->end_sym)) || 2848c2ecf20Sopenharmony_ci (s->addr == text_range_inittext->end && 2858c2ecf20Sopenharmony_ci strcmp(name, text_range_inittext->end_sym))) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 1; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* remove all the invalid symbols from the table */ 2938c2ecf20Sopenharmony_cistatic void shrink_table(void) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci unsigned int i, pos; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci pos = 0; 2988c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) { 2998c2ecf20Sopenharmony_ci if (symbol_valid(table[i])) { 3008c2ecf20Sopenharmony_ci if (pos != i) 3018c2ecf20Sopenharmony_ci table[pos] = table[i]; 3028c2ecf20Sopenharmony_ci pos++; 3038c2ecf20Sopenharmony_ci } else { 3048c2ecf20Sopenharmony_ci free(table[i]); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci table_cnt = pos; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* When valid symbol is not registered, exit to error */ 3108c2ecf20Sopenharmony_ci if (!table_cnt) { 3118c2ecf20Sopenharmony_ci fprintf(stderr, "No valid symbol.\n"); 3128c2ecf20Sopenharmony_ci exit(1); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void read_map(FILE *in) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct sym_entry *sym; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci while (!feof(in)) { 3218c2ecf20Sopenharmony_ci sym = read_symbol(in); 3228c2ecf20Sopenharmony_ci if (!sym) 3238c2ecf20Sopenharmony_ci continue; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci sym->start_pos = table_cnt; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (table_cnt >= table_size) { 3288c2ecf20Sopenharmony_ci table_size += 10000; 3298c2ecf20Sopenharmony_ci table = realloc(table, sizeof(*table) * table_size); 3308c2ecf20Sopenharmony_ci if (!table) { 3318c2ecf20Sopenharmony_ci fprintf(stderr, "out of memory\n"); 3328c2ecf20Sopenharmony_ci exit (1); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci table[table_cnt++] = sym; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void output_label(const char *label) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci printf(".globl %s\n", label); 3438c2ecf20Sopenharmony_ci printf("\tALGN\n"); 3448c2ecf20Sopenharmony_ci printf("%s:\n", label); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* Provide proper symbols relocatability by their '_text' relativeness. */ 3488c2ecf20Sopenharmony_cistatic void output_address(unsigned long long addr) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci if (_text <= addr) 3518c2ecf20Sopenharmony_ci printf("\tPTR\t_text + %#llx\n", addr - _text); 3528c2ecf20Sopenharmony_ci else 3538c2ecf20Sopenharmony_ci printf("\tPTR\t_text - %#llx\n", _text - addr); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* uncompress a compressed symbol. When this function is called, the best table 3578c2ecf20Sopenharmony_ci * might still be compressed itself, so the function needs to be recursive */ 3588c2ecf20Sopenharmony_cistatic int expand_symbol(const unsigned char *data, int len, char *result) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int c, rlen, total=0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci while (len) { 3638c2ecf20Sopenharmony_ci c = *data; 3648c2ecf20Sopenharmony_ci /* if the table holds a single char that is the same as the one 3658c2ecf20Sopenharmony_ci * we are looking for, then end the search */ 3668c2ecf20Sopenharmony_ci if (best_table[c][0]==c && best_table_len[c]==1) { 3678c2ecf20Sopenharmony_ci *result++ = c; 3688c2ecf20Sopenharmony_ci total++; 3698c2ecf20Sopenharmony_ci } else { 3708c2ecf20Sopenharmony_ci /* if not, recurse and expand */ 3718c2ecf20Sopenharmony_ci rlen = expand_symbol(best_table[c], best_table_len[c], result); 3728c2ecf20Sopenharmony_ci total += rlen; 3738c2ecf20Sopenharmony_ci result += rlen; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci data++; 3768c2ecf20Sopenharmony_ci len--; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci *result=0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return total; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int symbol_absolute(const struct sym_entry *s) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci return s->percpu_absolute; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void write_src(void) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned int i, k, off; 3918c2ecf20Sopenharmony_ci unsigned int best_idx[256]; 3928c2ecf20Sopenharmony_ci unsigned int *markers; 3938c2ecf20Sopenharmony_ci char buf[KSYM_NAME_LEN]; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci printf("#include <asm/bitsperlong.h>\n"); 3968c2ecf20Sopenharmony_ci printf("#if BITS_PER_LONG == 64\n"); 3978c2ecf20Sopenharmony_ci printf("#define PTR .quad\n"); 3988c2ecf20Sopenharmony_ci printf("#define ALGN .balign 8\n"); 3998c2ecf20Sopenharmony_ci printf("#else\n"); 4008c2ecf20Sopenharmony_ci printf("#define PTR .long\n"); 4018c2ecf20Sopenharmony_ci printf("#define ALGN .balign 4\n"); 4028c2ecf20Sopenharmony_ci printf("#endif\n"); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci printf("\t.section .rodata, \"a\"\n"); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!base_relative) 4078c2ecf20Sopenharmony_ci output_label("kallsyms_addresses"); 4088c2ecf20Sopenharmony_ci else 4098c2ecf20Sopenharmony_ci output_label("kallsyms_offsets"); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) { 4128c2ecf20Sopenharmony_ci if (base_relative) { 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * Use the offset relative to the lowest value 4158c2ecf20Sopenharmony_ci * encountered of all relative symbols, and emit 4168c2ecf20Sopenharmony_ci * non-relocatable fixed offsets that will be fixed 4178c2ecf20Sopenharmony_ci * up at runtime. 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci long long offset; 4218c2ecf20Sopenharmony_ci int overflow; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (!absolute_percpu) { 4248c2ecf20Sopenharmony_ci offset = table[i]->addr - relative_base; 4258c2ecf20Sopenharmony_ci overflow = (offset < 0 || offset > UINT_MAX); 4268c2ecf20Sopenharmony_ci } else if (symbol_absolute(table[i])) { 4278c2ecf20Sopenharmony_ci offset = table[i]->addr; 4288c2ecf20Sopenharmony_ci overflow = (offset < 0 || offset > INT_MAX); 4298c2ecf20Sopenharmony_ci } else { 4308c2ecf20Sopenharmony_ci offset = relative_base - table[i]->addr - 1; 4318c2ecf20Sopenharmony_ci overflow = (offset < INT_MIN || offset >= 0); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci if (overflow) { 4348c2ecf20Sopenharmony_ci fprintf(stderr, "kallsyms failure: " 4358c2ecf20Sopenharmony_ci "%s symbol value %#llx out of range in relative mode\n", 4368c2ecf20Sopenharmony_ci symbol_absolute(table[i]) ? "absolute" : "relative", 4378c2ecf20Sopenharmony_ci table[i]->addr); 4388c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci printf("\t.long\t%#x\n", (int)offset); 4418c2ecf20Sopenharmony_ci } else if (!symbol_absolute(table[i])) { 4428c2ecf20Sopenharmony_ci output_address(table[i]->addr); 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci printf("\tPTR\t%#llx\n", table[i]->addr); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci printf("\n"); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (base_relative) { 4508c2ecf20Sopenharmony_ci output_label("kallsyms_relative_base"); 4518c2ecf20Sopenharmony_ci output_address(relative_base); 4528c2ecf20Sopenharmony_ci printf("\n"); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci output_label("kallsyms_num_syms"); 4568c2ecf20Sopenharmony_ci printf("\t.long\t%u\n", table_cnt); 4578c2ecf20Sopenharmony_ci printf("\n"); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* table of offset markers, that give the offset in the compressed stream 4608c2ecf20Sopenharmony_ci * every 256 symbols */ 4618c2ecf20Sopenharmony_ci markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); 4628c2ecf20Sopenharmony_ci if (!markers) { 4638c2ecf20Sopenharmony_ci fprintf(stderr, "kallsyms failure: " 4648c2ecf20Sopenharmony_ci "unable to allocate required memory\n"); 4658c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci output_label("kallsyms_names"); 4698c2ecf20Sopenharmony_ci off = 0; 4708c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) { 4718c2ecf20Sopenharmony_ci if ((i & 0xFF) == 0) 4728c2ecf20Sopenharmony_ci markers[i >> 8] = off; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci printf("\t.byte 0x%02x", table[i]->len); 4758c2ecf20Sopenharmony_ci for (k = 0; k < table[i]->len; k++) 4768c2ecf20Sopenharmony_ci printf(", 0x%02x", table[i]->sym[k]); 4778c2ecf20Sopenharmony_ci printf("\n"); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci off += table[i]->len + 1; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci printf("\n"); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci output_label("kallsyms_markers"); 4848c2ecf20Sopenharmony_ci for (i = 0; i < ((table_cnt + 255) >> 8); i++) 4858c2ecf20Sopenharmony_ci printf("\t.long\t%u\n", markers[i]); 4868c2ecf20Sopenharmony_ci printf("\n"); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci free(markers); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci output_label("kallsyms_token_table"); 4918c2ecf20Sopenharmony_ci off = 0; 4928c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 4938c2ecf20Sopenharmony_ci best_idx[i] = off; 4948c2ecf20Sopenharmony_ci expand_symbol(best_table[i], best_table_len[i], buf); 4958c2ecf20Sopenharmony_ci printf("\t.asciz\t\"%s\"\n", buf); 4968c2ecf20Sopenharmony_ci off += strlen(buf) + 1; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci printf("\n"); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci output_label("kallsyms_token_index"); 5018c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) 5028c2ecf20Sopenharmony_ci printf("\t.short\t%d\n", best_idx[i]); 5038c2ecf20Sopenharmony_ci printf("\n"); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* table lookup compression functions */ 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* count all the possible tokens in a symbol */ 5108c2ecf20Sopenharmony_cistatic void learn_symbol(const unsigned char *symbol, int len) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci int i; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci for (i = 0; i < len - 1; i++) 5158c2ecf20Sopenharmony_ci token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/* decrease the count for all the possible tokens in a symbol */ 5198c2ecf20Sopenharmony_cistatic void forget_symbol(const unsigned char *symbol, int len) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci int i; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci for (i = 0; i < len - 1; i++) 5248c2ecf20Sopenharmony_ci token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* do the initial token count */ 5288c2ecf20Sopenharmony_cistatic void build_initial_tok_table(void) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci unsigned int i; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) 5338c2ecf20Sopenharmony_ci learn_symbol(table[i]->sym, table[i]->len); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic unsigned char *find_token(unsigned char *str, int len, 5378c2ecf20Sopenharmony_ci const unsigned char *token) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci int i; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci for (i = 0; i < len - 1; i++) { 5428c2ecf20Sopenharmony_ci if (str[i] == token[0] && str[i+1] == token[1]) 5438c2ecf20Sopenharmony_ci return &str[i]; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci return NULL; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* replace a given token in all the valid symbols. Use the sampled symbols 5498c2ecf20Sopenharmony_ci * to update the counts */ 5508c2ecf20Sopenharmony_cistatic void compress_symbols(const unsigned char *str, int idx) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci unsigned int i, len, size; 5538c2ecf20Sopenharmony_ci unsigned char *p1, *p2; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) { 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci len = table[i]->len; 5588c2ecf20Sopenharmony_ci p1 = table[i]->sym; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* find the token on the symbol */ 5618c2ecf20Sopenharmony_ci p2 = find_token(p1, len, str); 5628c2ecf20Sopenharmony_ci if (!p2) continue; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* decrease the counts for this symbol's tokens */ 5658c2ecf20Sopenharmony_ci forget_symbol(table[i]->sym, len); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci size = len; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci do { 5708c2ecf20Sopenharmony_ci *p2 = idx; 5718c2ecf20Sopenharmony_ci p2++; 5728c2ecf20Sopenharmony_ci size -= (p2 - p1); 5738c2ecf20Sopenharmony_ci memmove(p2, p2 + 1, size); 5748c2ecf20Sopenharmony_ci p1 = p2; 5758c2ecf20Sopenharmony_ci len--; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (size < 2) break; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* find the token on the symbol */ 5808c2ecf20Sopenharmony_ci p2 = find_token(p1, size, str); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci } while (p2); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci table[i]->len = len; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* increase the counts for this symbol's new tokens */ 5878c2ecf20Sopenharmony_ci learn_symbol(table[i]->sym, len); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/* search the token with the maximum profit */ 5928c2ecf20Sopenharmony_cistatic int find_best_token(void) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci int i, best, bestprofit; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci bestprofit=-10000; 5978c2ecf20Sopenharmony_ci best = 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci for (i = 0; i < 0x10000; i++) { 6008c2ecf20Sopenharmony_ci if (token_profit[i] > bestprofit) { 6018c2ecf20Sopenharmony_ci best = i; 6028c2ecf20Sopenharmony_ci bestprofit = token_profit[i]; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci return best; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/* this is the core of the algorithm: calculate the "best" table */ 6098c2ecf20Sopenharmony_cistatic void optimize_result(void) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci int i, best; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* using the '\0' symbol last allows compress_symbols to use standard 6148c2ecf20Sopenharmony_ci * fast string functions */ 6158c2ecf20Sopenharmony_ci for (i = 255; i >= 0; i--) { 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* if this table slot is empty (it is not used by an actual 6188c2ecf20Sopenharmony_ci * original char code */ 6198c2ecf20Sopenharmony_ci if (!best_table_len[i]) { 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* find the token with the best profit value */ 6228c2ecf20Sopenharmony_ci best = find_best_token(); 6238c2ecf20Sopenharmony_ci if (token_profit[best] == 0) 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* place it in the "best" table */ 6278c2ecf20Sopenharmony_ci best_table_len[i] = 2; 6288c2ecf20Sopenharmony_ci best_table[i][0] = best & 0xFF; 6298c2ecf20Sopenharmony_ci best_table[i][1] = (best >> 8) & 0xFF; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* replace this token in all the valid symbols */ 6328c2ecf20Sopenharmony_ci compress_symbols(best_table[i], i); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/* start by placing the symbols that are actually used on the table */ 6388c2ecf20Sopenharmony_cistatic void insert_real_symbols_in_table(void) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci unsigned int i, j, c; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) { 6438c2ecf20Sopenharmony_ci for (j = 0; j < table[i]->len; j++) { 6448c2ecf20Sopenharmony_ci c = table[i]->sym[j]; 6458c2ecf20Sopenharmony_ci best_table[c][0]=c; 6468c2ecf20Sopenharmony_ci best_table_len[c]=1; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void optimize_token_table(void) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci build_initial_tok_table(); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci insert_real_symbols_in_table(); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci optimize_result(); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* guess for "linker script provide" symbol */ 6618c2ecf20Sopenharmony_cistatic int may_be_linker_script_provide_symbol(const struct sym_entry *se) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci const char *symbol = sym_name(se); 6648c2ecf20Sopenharmony_ci int len = se->len - 1; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (len < 8) 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (symbol[0] != '_' || symbol[1] != '_') 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* __start_XXXXX */ 6738c2ecf20Sopenharmony_ci if (!memcmp(symbol + 2, "start_", 6)) 6748c2ecf20Sopenharmony_ci return 1; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* __stop_XXXXX */ 6778c2ecf20Sopenharmony_ci if (!memcmp(symbol + 2, "stop_", 5)) 6788c2ecf20Sopenharmony_ci return 1; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* __end_XXXXX */ 6818c2ecf20Sopenharmony_ci if (!memcmp(symbol + 2, "end_", 4)) 6828c2ecf20Sopenharmony_ci return 1; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* __XXXXX_start */ 6858c2ecf20Sopenharmony_ci if (!memcmp(symbol + len - 6, "_start", 6)) 6868c2ecf20Sopenharmony_ci return 1; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* __XXXXX_end */ 6898c2ecf20Sopenharmony_ci if (!memcmp(symbol + len - 4, "_end", 4)) 6908c2ecf20Sopenharmony_ci return 1; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int compare_symbols(const void *a, const void *b) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci const struct sym_entry *sa = *(const struct sym_entry **)a; 6988c2ecf20Sopenharmony_ci const struct sym_entry *sb = *(const struct sym_entry **)b; 6998c2ecf20Sopenharmony_ci int wa, wb; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* sort by address first */ 7028c2ecf20Sopenharmony_ci if (sa->addr > sb->addr) 7038c2ecf20Sopenharmony_ci return 1; 7048c2ecf20Sopenharmony_ci if (sa->addr < sb->addr) 7058c2ecf20Sopenharmony_ci return -1; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* sort by "weakness" type */ 7088c2ecf20Sopenharmony_ci wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); 7098c2ecf20Sopenharmony_ci wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); 7108c2ecf20Sopenharmony_ci if (wa != wb) 7118c2ecf20Sopenharmony_ci return wa - wb; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* sort by "linker script provide" type */ 7148c2ecf20Sopenharmony_ci wa = may_be_linker_script_provide_symbol(sa); 7158c2ecf20Sopenharmony_ci wb = may_be_linker_script_provide_symbol(sb); 7168c2ecf20Sopenharmony_ci if (wa != wb) 7178c2ecf20Sopenharmony_ci return wa - wb; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* sort by the number of prefix underscores */ 7208c2ecf20Sopenharmony_ci wa = strspn(sym_name(sa), "_"); 7218c2ecf20Sopenharmony_ci wb = strspn(sym_name(sb), "_"); 7228c2ecf20Sopenharmony_ci if (wa != wb) 7238c2ecf20Sopenharmony_ci return wa - wb; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* sort by initial order, so that other symbols are left undisturbed */ 7268c2ecf20Sopenharmony_ci return sa->start_pos - sb->start_pos; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void sort_symbols(void) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci qsort(table, table_cnt, sizeof(table[0]), compare_symbols); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void make_percpus_absolute(void) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci unsigned int i; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) 7398c2ecf20Sopenharmony_ci if (symbol_in_range(table[i], &percpu_range, 1)) { 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * Keep the 'A' override for percpu symbols to 7428c2ecf20Sopenharmony_ci * ensure consistent behavior compared to older 7438c2ecf20Sopenharmony_ci * versions of this tool. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_ci table[i]->sym[0] = 'A'; 7468c2ecf20Sopenharmony_ci table[i]->percpu_absolute = 1; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/* find the minimum non-absolute symbol address */ 7518c2ecf20Sopenharmony_cistatic void record_relative_base(void) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci unsigned int i; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci for (i = 0; i < table_cnt; i++) 7568c2ecf20Sopenharmony_ci if (!symbol_absolute(table[i])) { 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * The table is sorted by address. 7598c2ecf20Sopenharmony_ci * Take the first non-absolute symbol value. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci relative_base = table[i]->addr; 7628c2ecf20Sopenharmony_ci return; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ciint main(int argc, char **argv) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci if (argc >= 2) { 7698c2ecf20Sopenharmony_ci int i; 7708c2ecf20Sopenharmony_ci for (i = 1; i < argc; i++) { 7718c2ecf20Sopenharmony_ci if(strcmp(argv[i], "--all-symbols") == 0) 7728c2ecf20Sopenharmony_ci all_symbols = 1; 7738c2ecf20Sopenharmony_ci else if (strcmp(argv[i], "--absolute-percpu") == 0) 7748c2ecf20Sopenharmony_ci absolute_percpu = 1; 7758c2ecf20Sopenharmony_ci else if (strcmp(argv[i], "--base-relative") == 0) 7768c2ecf20Sopenharmony_ci base_relative = 1; 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci usage(); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci } else if (argc != 1) 7818c2ecf20Sopenharmony_ci usage(); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci read_map(stdin); 7848c2ecf20Sopenharmony_ci shrink_table(); 7858c2ecf20Sopenharmony_ci if (absolute_percpu) 7868c2ecf20Sopenharmony_ci make_percpus_absolute(); 7878c2ecf20Sopenharmony_ci sort_symbols(); 7888c2ecf20Sopenharmony_ci if (base_relative) 7898c2ecf20Sopenharmony_ci record_relative_base(); 7908c2ecf20Sopenharmony_ci optimize_token_table(); 7918c2ecf20Sopenharmony_ci write_src(); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci} 795