Back to home page

LXR

 
 

    


0001 /* Generate assembler source containing symbol information
0002  *
0003  * Copyright 2002       by Kai Germaschewski
0004  *
0005  * This software may be used and distributed according to the terms
0006  * of the GNU General Public License, incorporated herein by reference.
0007  *
0008  * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
0009  *
0010  *      Table compression uses all the unused char codes on the symbols and
0011  *  maps these to the most used substrings (tokens). For instance, it might
0012  *  map char code 0xF7 to represent "write_" and then in every symbol where
0013  *  "write_" appears it can be replaced by 0xF7, saving 5 bytes.
0014  *      The used codes themselves are also placed in the table so that the
0015  *  decompresion can work without "special cases".
0016  *      Applied to kernel symbols, this usually produces a compression ratio
0017  *  of about 50%.
0018  *
0019  */
0020 
0021 #include <stdio.h>
0022 #include <stdlib.h>
0023 #include <string.h>
0024 #include <ctype.h>
0025 #include <limits.h>
0026 
0027 #ifndef ARRAY_SIZE
0028 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
0029 #endif
0030 
0031 #define KSYM_NAME_LEN       128
0032 
0033 struct sym_entry {
0034     unsigned long long addr;
0035     unsigned int len;
0036     unsigned int start_pos;
0037     unsigned char *sym;
0038     unsigned int percpu_absolute;
0039 };
0040 
0041 struct addr_range {
0042     const char *start_sym, *end_sym;
0043     unsigned long long start, end;
0044 };
0045 
0046 static unsigned long long _text;
0047 static unsigned long long relative_base;
0048 static struct addr_range text_ranges[] = {
0049     { "_stext",     "_etext"     },
0050     { "_sinittext", "_einittext" },
0051     { "_stext_l1",  "_etext_l1"  }, /* Blackfin on-chip L1 inst SRAM */
0052     { "_stext_l2",  "_etext_l2"  }, /* Blackfin on-chip L2 SRAM */
0053 };
0054 #define text_range_text     (&text_ranges[0])
0055 #define text_range_inittext (&text_ranges[1])
0056 
0057 static struct addr_range percpu_range = {
0058     "__per_cpu_start", "__per_cpu_end", -1ULL, 0
0059 };
0060 
0061 static struct sym_entry *table;
0062 static unsigned int table_size, table_cnt;
0063 static int all_symbols = 0;
0064 static int absolute_percpu = 0;
0065 static char symbol_prefix_char = '\0';
0066 static int base_relative = 0;
0067 
0068 int token_profit[0x10000];
0069 
0070 /* the table that holds the result of the compression */
0071 unsigned char best_table[256][2];
0072 unsigned char best_table_len[256];
0073 
0074 
0075 static void usage(void)
0076 {
0077     fprintf(stderr, "Usage: kallsyms [--all-symbols] "
0078             "[--symbol-prefix=<prefix char>] "
0079             "[--base-relative] < in.map > out.S\n");
0080     exit(1);
0081 }
0082 
0083 /*
0084  * This ignores the intensely annoying "mapping symbols" found
0085  * in ARM ELF files: $a, $t and $d.
0086  */
0087 static inline int is_arm_mapping_symbol(const char *str)
0088 {
0089     return str[0] == '$' && strchr("axtd", str[1])
0090            && (str[2] == '\0' || str[2] == '.');
0091 }
0092 
0093 static int check_symbol_range(const char *sym, unsigned long long addr,
0094                   struct addr_range *ranges, int entries)
0095 {
0096     size_t i;
0097     struct addr_range *ar;
0098 
0099     for (i = 0; i < entries; ++i) {
0100         ar = &ranges[i];
0101 
0102         if (strcmp(sym, ar->start_sym) == 0) {
0103             ar->start = addr;
0104             return 0;
0105         } else if (strcmp(sym, ar->end_sym) == 0) {
0106             ar->end = addr;
0107             return 0;
0108         }
0109     }
0110 
0111     return 1;
0112 }
0113 
0114 static int read_symbol(FILE *in, struct sym_entry *s)
0115 {
0116     char str[500];
0117     char *sym, stype;
0118     int rc;
0119 
0120     rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
0121     if (rc != 3) {
0122         if (rc != EOF && fgets(str, 500, in) == NULL)
0123             fprintf(stderr, "Read error or end of file.\n");
0124         return -1;
0125     }
0126     if (strlen(str) > KSYM_NAME_LEN) {
0127         fprintf(stderr, "Symbol %s too long for kallsyms (%zu vs %d).\n"
0128                 "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
0129             str, strlen(str), KSYM_NAME_LEN);
0130         return -1;
0131     }
0132 
0133     sym = str;
0134     /* skip prefix char */
0135     if (symbol_prefix_char && str[0] == symbol_prefix_char)
0136         sym++;
0137 
0138     /* Ignore most absolute/undefined (?) symbols. */
0139     if (strcmp(sym, "_text") == 0)
0140         _text = s->addr;
0141     else if (check_symbol_range(sym, s->addr, text_ranges,
0142                     ARRAY_SIZE(text_ranges)) == 0)
0143         /* nothing to do */;
0144     else if (toupper(stype) == 'A')
0145     {
0146         /* Keep these useful absolute symbols */
0147         if (strcmp(sym, "__kernel_syscall_via_break") &&
0148             strcmp(sym, "__kernel_syscall_via_epc") &&
0149             strcmp(sym, "__kernel_sigtramp") &&
0150             strcmp(sym, "__gp"))
0151             return -1;
0152 
0153     }
0154     else if (toupper(stype) == 'U' ||
0155          is_arm_mapping_symbol(sym))
0156         return -1;
0157     /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
0158     else if (str[0] == '$')
0159         return -1;
0160     /* exclude debugging symbols */
0161     else if (stype == 'N')
0162         return -1;
0163 
0164     /* include the type field in the symbol name, so that it gets
0165      * compressed together */
0166     s->len = strlen(str) + 1;
0167     s->sym = malloc(s->len + 1);
0168     if (!s->sym) {
0169         fprintf(stderr, "kallsyms failure: "
0170             "unable to allocate required amount of memory\n");
0171         exit(EXIT_FAILURE);
0172     }
0173     strcpy((char *)s->sym + 1, str);
0174     s->sym[0] = stype;
0175 
0176     s->percpu_absolute = 0;
0177 
0178     /* Record if we've found __per_cpu_start/end. */
0179     check_symbol_range(sym, s->addr, &percpu_range, 1);
0180 
0181     return 0;
0182 }
0183 
0184 static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges,
0185                int entries)
0186 {
0187     size_t i;
0188     struct addr_range *ar;
0189 
0190     for (i = 0; i < entries; ++i) {
0191         ar = &ranges[i];
0192 
0193         if (s->addr >= ar->start && s->addr <= ar->end)
0194             return 1;
0195     }
0196 
0197     return 0;
0198 }
0199 
0200 static int symbol_valid(struct sym_entry *s)
0201 {
0202     /* Symbols which vary between passes.  Passes 1 and 2 must have
0203      * identical symbol lists.  The kallsyms_* symbols below are only added
0204      * after pass 1, they would be included in pass 2 when --all-symbols is
0205      * specified so exclude them to get a stable symbol list.
0206      */
0207     static char *special_symbols[] = {
0208         "kallsyms_addresses",
0209         "kallsyms_offsets",
0210         "kallsyms_relative_base",
0211         "kallsyms_num_syms",
0212         "kallsyms_names",
0213         "kallsyms_markers",
0214         "kallsyms_token_table",
0215         "kallsyms_token_index",
0216 
0217     /* Exclude linker generated symbols which vary between passes */
0218         "_SDA_BASE_",       /* ppc */
0219         "_SDA2_BASE_",      /* ppc */
0220         NULL };
0221 
0222     static char *special_prefixes[] = {
0223         "__crc_",       /* modversions */
0224         NULL };
0225 
0226     static char *special_suffixes[] = {
0227         "_veneer",      /* arm */
0228         "_from_arm",        /* arm */
0229         "_from_thumb",      /* arm */
0230         NULL };
0231 
0232     int i;
0233     char *sym_name = (char *)s->sym + 1;
0234 
0235     /* skip prefix char */
0236     if (symbol_prefix_char && *sym_name == symbol_prefix_char)
0237         sym_name++;
0238 
0239 
0240     /* if --all-symbols is not specified, then symbols outside the text
0241      * and inittext sections are discarded */
0242     if (!all_symbols) {
0243         if (symbol_in_range(s, text_ranges,
0244                     ARRAY_SIZE(text_ranges)) == 0)
0245             return 0;
0246         /* Corner case.  Discard any symbols with the same value as
0247          * _etext _einittext; they can move between pass 1 and 2 when
0248          * the kallsyms data are added.  If these symbols move then
0249          * they may get dropped in pass 2, which breaks the kallsyms
0250          * rules.
0251          */
0252         if ((s->addr == text_range_text->end &&
0253                 strcmp(sym_name,
0254                        text_range_text->end_sym)) ||
0255             (s->addr == text_range_inittext->end &&
0256                 strcmp(sym_name,
0257                        text_range_inittext->end_sym)))
0258             return 0;
0259     }
0260 
0261     /* Exclude symbols which vary between passes. */
0262     for (i = 0; special_symbols[i]; i++)
0263         if (strcmp(sym_name, special_symbols[i]) == 0)
0264             return 0;
0265 
0266     for (i = 0; special_prefixes[i]; i++) {
0267         int l = strlen(special_prefixes[i]);
0268 
0269         if (l <= strlen(sym_name) &&
0270             strncmp(sym_name, special_prefixes[i], l) == 0)
0271             return 0;
0272     }
0273 
0274     for (i = 0; special_suffixes[i]; i++) {
0275         int l = strlen(sym_name) - strlen(special_suffixes[i]);
0276 
0277         if (l >= 0 && strcmp(sym_name + l, special_suffixes[i]) == 0)
0278             return 0;
0279     }
0280 
0281     return 1;
0282 }
0283 
0284 static void read_map(FILE *in)
0285 {
0286     while (!feof(in)) {
0287         if (table_cnt >= table_size) {
0288             table_size += 10000;
0289             table = realloc(table, sizeof(*table) * table_size);
0290             if (!table) {
0291                 fprintf(stderr, "out of memory\n");
0292                 exit (1);
0293             }
0294         }
0295         if (read_symbol(in, &table[table_cnt]) == 0) {
0296             table[table_cnt].start_pos = table_cnt;
0297             table_cnt++;
0298         }
0299     }
0300 }
0301 
0302 static void output_label(char *label)
0303 {
0304     if (symbol_prefix_char)
0305         printf(".globl %c%s\n", symbol_prefix_char, label);
0306     else
0307         printf(".globl %s\n", label);
0308     printf("\tALGN\n");
0309     if (symbol_prefix_char)
0310         printf("%c%s:\n", symbol_prefix_char, label);
0311     else
0312         printf("%s:\n", label);
0313 }
0314 
0315 /* uncompress a compressed symbol. When this function is called, the best table
0316  * might still be compressed itself, so the function needs to be recursive */
0317 static int expand_symbol(unsigned char *data, int len, char *result)
0318 {
0319     int c, rlen, total=0;
0320 
0321     while (len) {
0322         c = *data;
0323         /* if the table holds a single char that is the same as the one
0324          * we are looking for, then end the search */
0325         if (best_table[c][0]==c && best_table_len[c]==1) {
0326             *result++ = c;
0327             total++;
0328         } else {
0329             /* if not, recurse and expand */
0330             rlen = expand_symbol(best_table[c], best_table_len[c], result);
0331             total += rlen;
0332             result += rlen;
0333         }
0334         data++;
0335         len--;
0336     }
0337     *result=0;
0338 
0339     return total;
0340 }
0341 
0342 static int symbol_absolute(struct sym_entry *s)
0343 {
0344     return s->percpu_absolute;
0345 }
0346 
0347 static void write_src(void)
0348 {
0349     unsigned int i, k, off;
0350     unsigned int best_idx[256];
0351     unsigned int *markers;
0352     char buf[KSYM_NAME_LEN];
0353 
0354     printf("#include <asm/types.h>\n");
0355     printf("#if BITS_PER_LONG == 64\n");
0356     printf("#define PTR .quad\n");
0357     printf("#define ALGN .align 8\n");
0358     printf("#else\n");
0359     printf("#define PTR .long\n");
0360     printf("#define ALGN .align 4\n");
0361     printf("#endif\n");
0362 
0363     printf("\t.section .rodata, \"a\"\n");
0364 
0365     /* Provide proper symbols relocatability by their relativeness
0366      * to a fixed anchor point in the runtime image, either '_text'
0367      * for absolute address tables, in which case the linker will
0368      * emit the final addresses at build time. Otherwise, use the
0369      * offset relative to the lowest value encountered of all relative
0370      * symbols, and emit non-relocatable fixed offsets that will be fixed
0371      * up at runtime.
0372      *
0373      * The symbol names cannot be used to construct normal symbol
0374      * references as the list of symbols contains symbols that are
0375      * declared static and are private to their .o files.  This prevents
0376      * .tmp_kallsyms.o or any other object from referencing them.
0377      */
0378     if (!base_relative)
0379         output_label("kallsyms_addresses");
0380     else
0381         output_label("kallsyms_offsets");
0382 
0383     for (i = 0; i < table_cnt; i++) {
0384         if (base_relative) {
0385             long long offset;
0386             int overflow;
0387 
0388             if (!absolute_percpu) {
0389                 offset = table[i].addr - relative_base;
0390                 overflow = (offset < 0 || offset > UINT_MAX);
0391             } else if (symbol_absolute(&table[i])) {
0392                 offset = table[i].addr;
0393                 overflow = (offset < 0 || offset > INT_MAX);
0394             } else {
0395                 offset = relative_base - table[i].addr - 1;
0396                 overflow = (offset < INT_MIN || offset >= 0);
0397             }
0398             if (overflow) {
0399                 fprintf(stderr, "kallsyms failure: "
0400                     "%s symbol value %#llx out of range in relative mode\n",
0401                     symbol_absolute(&table[i]) ? "absolute" : "relative",
0402                     table[i].addr);
0403                 exit(EXIT_FAILURE);
0404             }
0405             printf("\t.long\t%#x\n", (int)offset);
0406         } else if (!symbol_absolute(&table[i])) {
0407             if (_text <= table[i].addr)
0408                 printf("\tPTR\t_text + %#llx\n",
0409                     table[i].addr - _text);
0410             else
0411                 printf("\tPTR\t_text - %#llx\n",
0412                     _text - table[i].addr);
0413         } else {
0414             printf("\tPTR\t%#llx\n", table[i].addr);
0415         }
0416     }
0417     printf("\n");
0418 
0419     if (base_relative) {
0420         output_label("kallsyms_relative_base");
0421         printf("\tPTR\t_text - %#llx\n", _text - relative_base);
0422         printf("\n");
0423     }
0424 
0425     output_label("kallsyms_num_syms");
0426     printf("\tPTR\t%d\n", table_cnt);
0427     printf("\n");
0428 
0429     /* table of offset markers, that give the offset in the compressed stream
0430      * every 256 symbols */
0431     markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
0432     if (!markers) {
0433         fprintf(stderr, "kallsyms failure: "
0434             "unable to allocate required memory\n");
0435         exit(EXIT_FAILURE);
0436     }
0437 
0438     output_label("kallsyms_names");
0439     off = 0;
0440     for (i = 0; i < table_cnt; i++) {
0441         if ((i & 0xFF) == 0)
0442             markers[i >> 8] = off;
0443 
0444         printf("\t.byte 0x%02x", table[i].len);
0445         for (k = 0; k < table[i].len; k++)
0446             printf(", 0x%02x", table[i].sym[k]);
0447         printf("\n");
0448 
0449         off += table[i].len + 1;
0450     }
0451     printf("\n");
0452 
0453     output_label("kallsyms_markers");
0454     for (i = 0; i < ((table_cnt + 255) >> 8); i++)
0455         printf("\tPTR\t%d\n", markers[i]);
0456     printf("\n");
0457 
0458     free(markers);
0459 
0460     output_label("kallsyms_token_table");
0461     off = 0;
0462     for (i = 0; i < 256; i++) {
0463         best_idx[i] = off;
0464         expand_symbol(best_table[i], best_table_len[i], buf);
0465         printf("\t.asciz\t\"%s\"\n", buf);
0466         off += strlen(buf) + 1;
0467     }
0468     printf("\n");
0469 
0470     output_label("kallsyms_token_index");
0471     for (i = 0; i < 256; i++)
0472         printf("\t.short\t%d\n", best_idx[i]);
0473     printf("\n");
0474 }
0475 
0476 
0477 /* table lookup compression functions */
0478 
0479 /* count all the possible tokens in a symbol */
0480 static void learn_symbol(unsigned char *symbol, int len)
0481 {
0482     int i;
0483 
0484     for (i = 0; i < len - 1; i++)
0485         token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
0486 }
0487 
0488 /* decrease the count for all the possible tokens in a symbol */
0489 static void forget_symbol(unsigned char *symbol, int len)
0490 {
0491     int i;
0492 
0493     for (i = 0; i < len - 1; i++)
0494         token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
0495 }
0496 
0497 /* remove all the invalid symbols from the table and do the initial token count */
0498 static void build_initial_tok_table(void)
0499 {
0500     unsigned int i, pos;
0501 
0502     pos = 0;
0503     for (i = 0; i < table_cnt; i++) {
0504         if ( symbol_valid(&table[i]) ) {
0505             if (pos != i)
0506                 table[pos] = table[i];
0507             learn_symbol(table[pos].sym, table[pos].len);
0508             pos++;
0509         }
0510     }
0511     table_cnt = pos;
0512 }
0513 
0514 static void *find_token(unsigned char *str, int len, unsigned char *token)
0515 {
0516     int i;
0517 
0518     for (i = 0; i < len - 1; i++) {
0519         if (str[i] == token[0] && str[i+1] == token[1])
0520             return &str[i];
0521     }
0522     return NULL;
0523 }
0524 
0525 /* replace a given token in all the valid symbols. Use the sampled symbols
0526  * to update the counts */
0527 static void compress_symbols(unsigned char *str, int idx)
0528 {
0529     unsigned int i, len, size;
0530     unsigned char *p1, *p2;
0531 
0532     for (i = 0; i < table_cnt; i++) {
0533 
0534         len = table[i].len;
0535         p1 = table[i].sym;
0536 
0537         /* find the token on the symbol */
0538         p2 = find_token(p1, len, str);
0539         if (!p2) continue;
0540 
0541         /* decrease the counts for this symbol's tokens */
0542         forget_symbol(table[i].sym, len);
0543 
0544         size = len;
0545 
0546         do {
0547             *p2 = idx;
0548             p2++;
0549             size -= (p2 - p1);
0550             memmove(p2, p2 + 1, size);
0551             p1 = p2;
0552             len--;
0553 
0554             if (size < 2) break;
0555 
0556             /* find the token on the symbol */
0557             p2 = find_token(p1, size, str);
0558 
0559         } while (p2);
0560 
0561         table[i].len = len;
0562 
0563         /* increase the counts for this symbol's new tokens */
0564         learn_symbol(table[i].sym, len);
0565     }
0566 }
0567 
0568 /* search the token with the maximum profit */
0569 static int find_best_token(void)
0570 {
0571     int i, best, bestprofit;
0572 
0573     bestprofit=-10000;
0574     best = 0;
0575 
0576     for (i = 0; i < 0x10000; i++) {
0577         if (token_profit[i] > bestprofit) {
0578             best = i;
0579             bestprofit = token_profit[i];
0580         }
0581     }
0582     return best;
0583 }
0584 
0585 /* this is the core of the algorithm: calculate the "best" table */
0586 static void optimize_result(void)
0587 {
0588     int i, best;
0589 
0590     /* using the '\0' symbol last allows compress_symbols to use standard
0591      * fast string functions */
0592     for (i = 255; i >= 0; i--) {
0593 
0594         /* if this table slot is empty (it is not used by an actual
0595          * original char code */
0596         if (!best_table_len[i]) {
0597 
0598             /* find the token with the breates profit value */
0599             best = find_best_token();
0600             if (token_profit[best] == 0)
0601                 break;
0602 
0603             /* place it in the "best" table */
0604             best_table_len[i] = 2;
0605             best_table[i][0] = best & 0xFF;
0606             best_table[i][1] = (best >> 8) & 0xFF;
0607 
0608             /* replace this token in all the valid symbols */
0609             compress_symbols(best_table[i], i);
0610         }
0611     }
0612 }
0613 
0614 /* start by placing the symbols that are actually used on the table */
0615 static void insert_real_symbols_in_table(void)
0616 {
0617     unsigned int i, j, c;
0618 
0619     memset(best_table, 0, sizeof(best_table));
0620     memset(best_table_len, 0, sizeof(best_table_len));
0621 
0622     for (i = 0; i < table_cnt; i++) {
0623         for (j = 0; j < table[i].len; j++) {
0624             c = table[i].sym[j];
0625             best_table[c][0]=c;
0626             best_table_len[c]=1;
0627         }
0628     }
0629 }
0630 
0631 static void optimize_token_table(void)
0632 {
0633     build_initial_tok_table();
0634 
0635     insert_real_symbols_in_table();
0636 
0637     /* When valid symbol is not registered, exit to error */
0638     if (!table_cnt) {
0639         fprintf(stderr, "No valid symbol.\n");
0640         exit(1);
0641     }
0642 
0643     optimize_result();
0644 }
0645 
0646 /* guess for "linker script provide" symbol */
0647 static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
0648 {
0649     const char *symbol = (char *)se->sym + 1;
0650     int len = se->len - 1;
0651 
0652     if (len < 8)
0653         return 0;
0654 
0655     if (symbol[0] != '_' || symbol[1] != '_')
0656         return 0;
0657 
0658     /* __start_XXXXX */
0659     if (!memcmp(symbol + 2, "start_", 6))
0660         return 1;
0661 
0662     /* __stop_XXXXX */
0663     if (!memcmp(symbol + 2, "stop_", 5))
0664         return 1;
0665 
0666     /* __end_XXXXX */
0667     if (!memcmp(symbol + 2, "end_", 4))
0668         return 1;
0669 
0670     /* __XXXXX_start */
0671     if (!memcmp(symbol + len - 6, "_start", 6))
0672         return 1;
0673 
0674     /* __XXXXX_end */
0675     if (!memcmp(symbol + len - 4, "_end", 4))
0676         return 1;
0677 
0678     return 0;
0679 }
0680 
0681 static int prefix_underscores_count(const char *str)
0682 {
0683     const char *tail = str;
0684 
0685     while (*tail == '_')
0686         tail++;
0687 
0688     return tail - str;
0689 }
0690 
0691 static int compare_symbols(const void *a, const void *b)
0692 {
0693     const struct sym_entry *sa;
0694     const struct sym_entry *sb;
0695     int wa, wb;
0696 
0697     sa = a;
0698     sb = b;
0699 
0700     /* sort by address first */
0701     if (sa->addr > sb->addr)
0702         return 1;
0703     if (sa->addr < sb->addr)
0704         return -1;
0705 
0706     /* sort by "weakness" type */
0707     wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
0708     wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
0709     if (wa != wb)
0710         return wa - wb;
0711 
0712     /* sort by "linker script provide" type */
0713     wa = may_be_linker_script_provide_symbol(sa);
0714     wb = may_be_linker_script_provide_symbol(sb);
0715     if (wa != wb)
0716         return wa - wb;
0717 
0718     /* sort by the number of prefix underscores */
0719     wa = prefix_underscores_count((const char *)sa->sym + 1);
0720     wb = prefix_underscores_count((const char *)sb->sym + 1);
0721     if (wa != wb)
0722         return wa - wb;
0723 
0724     /* sort by initial order, so that other symbols are left undisturbed */
0725     return sa->start_pos - sb->start_pos;
0726 }
0727 
0728 static void sort_symbols(void)
0729 {
0730     qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
0731 }
0732 
0733 static void make_percpus_absolute(void)
0734 {
0735     unsigned int i;
0736 
0737     for (i = 0; i < table_cnt; i++)
0738         if (symbol_in_range(&table[i], &percpu_range, 1)) {
0739             /*
0740              * Keep the 'A' override for percpu symbols to
0741              * ensure consistent behavior compared to older
0742              * versions of this tool.
0743              */
0744             table[i].sym[0] = 'A';
0745             table[i].percpu_absolute = 1;
0746         }
0747 }
0748 
0749 /* find the minimum non-absolute symbol address */
0750 static void record_relative_base(void)
0751 {
0752     unsigned int i;
0753 
0754     relative_base = -1ULL;
0755     for (i = 0; i < table_cnt; i++)
0756         if (!symbol_absolute(&table[i]) &&
0757             table[i].addr < relative_base)
0758             relative_base = table[i].addr;
0759 }
0760 
0761 int main(int argc, char **argv)
0762 {
0763     if (argc >= 2) {
0764         int i;
0765         for (i = 1; i < argc; i++) {
0766             if(strcmp(argv[i], "--all-symbols") == 0)
0767                 all_symbols = 1;
0768             else if (strcmp(argv[i], "--absolute-percpu") == 0)
0769                 absolute_percpu = 1;
0770             else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
0771                 char *p = &argv[i][16];
0772                 /* skip quote */
0773                 if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
0774                     p++;
0775                 symbol_prefix_char = *p;
0776             } else if (strcmp(argv[i], "--base-relative") == 0)
0777                 base_relative = 1;
0778             else
0779                 usage();
0780         }
0781     } else if (argc != 1)
0782         usage();
0783 
0784     read_map(stdin);
0785     if (absolute_percpu)
0786         make_percpus_absolute();
0787     if (base_relative)
0788         record_relative_base();
0789     sort_symbols();
0790     optimize_token_table();
0791     write_src();
0792 
0793     return 0;
0794 }