~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/kallsyms.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* Generate assembler source containing symbol information
  2  *
  3  * Copyright 2002       by Kai Germaschewski
  4  *
  5  * This software may be used and distributed according to the terms
  6  * of the GNU General Public License, incorporated herein by reference.
  7  *
  8  * Usage: kallsyms [--all-symbols] [--absolute-percpu]
  9  *                         [--lto-clang] in.map > out.S
 10  *
 11  *      Table compression uses all the unused char codes on the symbols and
 12  *  maps these to the most used substrings (tokens). For instance, it might
 13  *  map char code 0xF7 to represent "write_" and then in every symbol where
 14  *  "write_" appears it can be replaced by 0xF7, saving 5 bytes.
 15  *      The used codes themselves are also placed in the table so that the
 16  *  decompresion can work without "special cases".
 17  *      Applied to kernel symbols, this usually produces a compression ratio
 18  *  of about 50%.
 19  *
 20  */
 21 
 22 #include <errno.h>
 23 #include <getopt.h>
 24 #include <stdbool.h>
 25 #include <stdio.h>
 26 #include <stdlib.h>
 27 #include <string.h>
 28 #include <ctype.h>
 29 #include <limits.h>
 30 
 31 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 32 
 33 #define KSYM_NAME_LEN           512
 34 
 35 struct sym_entry {
 36         unsigned long long addr;
 37         unsigned int len;
 38         unsigned int seq;
 39         bool percpu_absolute;
 40         unsigned char sym[];
 41 };
 42 
 43 struct addr_range {
 44         const char *start_sym, *end_sym;
 45         unsigned long long start, end;
 46 };
 47 
 48 static unsigned long long _text;
 49 static unsigned long long relative_base;
 50 static struct addr_range text_ranges[] = {
 51         { "_stext",     "_etext"     },
 52         { "_sinittext", "_einittext" },
 53 };
 54 #define text_range_text     (&text_ranges[0])
 55 #define text_range_inittext (&text_ranges[1])
 56 
 57 static struct addr_range percpu_range = {
 58         "__per_cpu_start", "__per_cpu_end", -1ULL, 0
 59 };
 60 
 61 static struct sym_entry **table;
 62 static unsigned int table_size, table_cnt;
 63 static int all_symbols;
 64 static int absolute_percpu;
 65 static int lto_clang;
 66 
 67 static int token_profit[0x10000];
 68 
 69 /* the table that holds the result of the compression */
 70 static unsigned char best_table[256][2];
 71 static unsigned char best_table_len[256];
 72 
 73 
 74 static void usage(void)
 75 {
 76         fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] "
 77                         "[--lto-clang] in.map > out.S\n");
 78         exit(1);
 79 }
 80 
 81 static char *sym_name(const struct sym_entry *s)
 82 {
 83         return (char *)s->sym + 1;
 84 }
 85 
 86 static bool is_ignored_symbol(const char *name, char type)
 87 {
 88         if (type == 'u' || type == 'n')
 89                 return true;
 90 
 91         if (toupper(type) == 'A') {
 92                 /* Keep these useful absolute symbols */
 93                 if (strcmp(name, "__kernel_syscall_via_break") &&
 94                     strcmp(name, "__kernel_syscall_via_epc") &&
 95                     strcmp(name, "__kernel_sigtramp") &&
 96                     strcmp(name, "__gp"))
 97                         return true;
 98         }
 99 
100         return false;
101 }
102 
103 static void check_symbol_range(const char *sym, unsigned long long addr,
104                                struct addr_range *ranges, int entries)
105 {
106         size_t i;
107         struct addr_range *ar;
108 
109         for (i = 0; i < entries; ++i) {
110                 ar = &ranges[i];
111 
112                 if (strcmp(sym, ar->start_sym) == 0) {
113                         ar->start = addr;
114                         return;
115                 } else if (strcmp(sym, ar->end_sym) == 0) {
116                         ar->end = addr;
117                         return;
118                 }
119         }
120 }
121 
122 static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
123 {
124         char *name, type, *p;
125         unsigned long long addr;
126         size_t len;
127         ssize_t readlen;
128         struct sym_entry *sym;
129 
130         errno = 0;
131         readlen = getline(buf, buf_len, in);
132         if (readlen < 0) {
133                 if (errno) {
134                         perror("read_symbol");
135                         exit(EXIT_FAILURE);
136                 }
137                 return NULL;
138         }
139 
140         if ((*buf)[readlen - 1] == '\n')
141                 (*buf)[readlen - 1] = 0;
142 
143         addr = strtoull(*buf, &p, 16);
144 
145         if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') {
146                 fprintf(stderr, "line format error\n");
147                 exit(EXIT_FAILURE);
148         }
149 
150         name = p;
151         len = strlen(name);
152 
153         if (len >= KSYM_NAME_LEN) {
154                 fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n"
155                                 "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
156                         name, len, KSYM_NAME_LEN);
157                 return NULL;
158         }
159 
160         if (strcmp(name, "_text") == 0)
161                 _text = addr;
162 
163         /* Ignore most absolute/undefined (?) symbols. */
164         if (is_ignored_symbol(name, type))
165                 return NULL;
166 
167         check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges));
168         check_symbol_range(name, addr, &percpu_range, 1);
169 
170         /* include the type field in the symbol name, so that it gets
171          * compressed together */
172         len++;
173 
174         sym = malloc(sizeof(*sym) + len + 1);
175         if (!sym) {
176                 fprintf(stderr, "kallsyms failure: "
177                         "unable to allocate required amount of memory\n");
178                 exit(EXIT_FAILURE);
179         }
180         sym->addr = addr;
181         sym->len = len;
182         sym->sym[0] = type;
183         strcpy(sym_name(sym), name);
184         sym->percpu_absolute = false;
185 
186         return sym;
187 }
188 
189 static int symbol_in_range(const struct sym_entry *s,
190                            const struct addr_range *ranges, int entries)
191 {
192         size_t i;
193         const struct addr_range *ar;
194 
195         for (i = 0; i < entries; ++i) {
196                 ar = &ranges[i];
197 
198                 if (s->addr >= ar->start && s->addr <= ar->end)
199                         return 1;
200         }
201 
202         return 0;
203 }
204 
205 static bool string_starts_with(const char *s, const char *prefix)
206 {
207         return strncmp(s, prefix, strlen(prefix)) == 0;
208 }
209 
210 static int symbol_valid(const struct sym_entry *s)
211 {
212         const char *name = sym_name(s);
213 
214         /* if --all-symbols is not specified, then symbols outside the text
215          * and inittext sections are discarded */
216         if (!all_symbols) {
217                 /*
218                  * Symbols starting with __start and __stop are used to denote
219                  * section boundaries, and should always be included:
220                  */
221                 if (string_starts_with(name, "__start_") ||
222                     string_starts_with(name, "__stop_"))
223                         return 1;
224 
225                 if (symbol_in_range(s, text_ranges,
226                                     ARRAY_SIZE(text_ranges)) == 0)
227                         return 0;
228                 /* Corner case.  Discard any symbols with the same value as
229                  * _etext _einittext; they can move between pass 1 and 2 when
230                  * the kallsyms data are added.  If these symbols move then
231                  * they may get dropped in pass 2, which breaks the kallsyms
232                  * rules.
233                  */
234                 if ((s->addr == text_range_text->end &&
235                      strcmp(name, text_range_text->end_sym)) ||
236                     (s->addr == text_range_inittext->end &&
237                      strcmp(name, text_range_inittext->end_sym)))
238                         return 0;
239         }
240 
241         return 1;
242 }
243 
244 /* remove all the invalid symbols from the table */
245 static void shrink_table(void)
246 {
247         unsigned int i, pos;
248 
249         pos = 0;
250         for (i = 0; i < table_cnt; i++) {
251                 if (symbol_valid(table[i])) {
252                         if (pos != i)
253                                 table[pos] = table[i];
254                         pos++;
255                 } else {
256                         free(table[i]);
257                 }
258         }
259         table_cnt = pos;
260 }
261 
262 static void read_map(const char *in)
263 {
264         FILE *fp;
265         struct sym_entry *sym;
266         char *buf = NULL;
267         size_t buflen = 0;
268 
269         fp = fopen(in, "r");
270         if (!fp) {
271                 perror(in);
272                 exit(1);
273         }
274 
275         while (!feof(fp)) {
276                 sym = read_symbol(fp, &buf, &buflen);
277                 if (!sym)
278                         continue;
279 
280                 sym->seq = table_cnt;
281 
282                 if (table_cnt >= table_size) {
283                         table_size += 10000;
284                         table = realloc(table, sizeof(*table) * table_size);
285                         if (!table) {
286                                 fprintf(stderr, "out of memory\n");
287                                 fclose(fp);
288                                 exit (1);
289                         }
290                 }
291 
292                 table[table_cnt++] = sym;
293         }
294 
295         free(buf);
296         fclose(fp);
297 }
298 
299 static void output_label(const char *label)
300 {
301         printf(".globl %s\n", label);
302         printf("\tALGN\n");
303         printf("%s:\n", label);
304 }
305 
306 /* Provide proper symbols relocatability by their '_text' relativeness. */
307 static void output_address(unsigned long long addr)
308 {
309         if (_text <= addr)
310                 printf("\tPTR\t_text + %#llx\n", addr - _text);
311         else
312                 printf("\tPTR\t_text - %#llx\n", _text - addr);
313 }
314 
315 /* uncompress a compressed symbol. When this function is called, the best table
316  * might still be compressed itself, so the function needs to be recursive */
317 static int expand_symbol(const unsigned char *data, int len, char *result)
318 {
319         int c, rlen, total=0;
320 
321         while (len) {
322                 c = *data;
323                 /* if the table holds a single char that is the same as the one
324                  * we are looking for, then end the search */
325                 if (best_table[c][0]==c && best_table_len[c]==1) {
326                         *result++ = c;
327                         total++;
328                 } else {
329                         /* if not, recurse and expand */
330                         rlen = expand_symbol(best_table[c], best_table_len[c], result);
331                         total += rlen;
332                         result += rlen;
333                 }
334                 data++;
335                 len--;
336         }
337         *result=0;
338 
339         return total;
340 }
341 
342 static bool symbol_absolute(const struct sym_entry *s)
343 {
344         return s->percpu_absolute;
345 }
346 
347 static void cleanup_symbol_name(char *s)
348 {
349         char *p;
350 
351         /*
352          * ASCII[.]   = 2e
353          * ASCII[0-9] = 30,39
354          * ASCII[A-Z] = 41,5a
355          * ASCII[_]   = 5f
356          * ASCII[a-z] = 61,7a
357          *
358          * As above, replacing the first '.' in ".llvm." with '\0' does not
359          * affect the main sorting, but it helps us with subsorting.
360          */
361         p = strstr(s, ".llvm.");
362         if (p)
363                 *p = '\0';
364 }
365 
366 static int compare_names(const void *a, const void *b)
367 {
368         int ret;
369         const struct sym_entry *sa = *(const struct sym_entry **)a;
370         const struct sym_entry *sb = *(const struct sym_entry **)b;
371 
372         ret = strcmp(sym_name(sa), sym_name(sb));
373         if (!ret) {
374                 if (sa->addr > sb->addr)
375                         return 1;
376                 else if (sa->addr < sb->addr)
377                         return -1;
378 
379                 /* keep old order */
380                 return (int)(sa->seq - sb->seq);
381         }
382 
383         return ret;
384 }
385 
386 static void sort_symbols_by_name(void)
387 {
388         qsort(table, table_cnt, sizeof(table[0]), compare_names);
389 }
390 
391 static void write_src(void)
392 {
393         unsigned int i, k, off;
394         unsigned int best_idx[256];
395         unsigned int *markers, markers_cnt;
396         char buf[KSYM_NAME_LEN];
397 
398         printf("#include <asm/bitsperlong.h>\n");
399         printf("#if BITS_PER_LONG == 64\n");
400         printf("#define PTR .quad\n");
401         printf("#define ALGN .balign 8\n");
402         printf("#else\n");
403         printf("#define PTR .long\n");
404         printf("#define ALGN .balign 4\n");
405         printf("#endif\n");
406 
407         printf("\t.section .rodata, \"a\"\n");
408 
409         output_label("kallsyms_num_syms");
410         printf("\t.long\t%u\n", table_cnt);
411         printf("\n");
412 
413         /* table of offset markers, that give the offset in the compressed stream
414          * every 256 symbols */
415         markers_cnt = (table_cnt + 255) / 256;
416         markers = malloc(sizeof(*markers) * markers_cnt);
417         if (!markers) {
418                 fprintf(stderr, "kallsyms failure: "
419                         "unable to allocate required memory\n");
420                 exit(EXIT_FAILURE);
421         }
422 
423         output_label("kallsyms_names");
424         off = 0;
425         for (i = 0; i < table_cnt; i++) {
426                 if ((i & 0xFF) == 0)
427                         markers[i >> 8] = off;
428                 table[i]->seq = i;
429 
430                 /* There cannot be any symbol of length zero. */
431                 if (table[i]->len == 0) {
432                         fprintf(stderr, "kallsyms failure: "
433                                 "unexpected zero symbol length\n");
434                         exit(EXIT_FAILURE);
435                 }
436 
437                 /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */
438                 if (table[i]->len > 0x3FFF) {
439                         fprintf(stderr, "kallsyms failure: "
440                                 "unexpected huge symbol length\n");
441                         exit(EXIT_FAILURE);
442                 }
443 
444                 /* Encode length with ULEB128. */
445                 if (table[i]->len <= 0x7F) {
446                         /* Most symbols use a single byte for the length. */
447                         printf("\t.byte 0x%02x", table[i]->len);
448                         off += table[i]->len + 1;
449                 } else {
450                         /* "Big" symbols use two bytes. */
451                         printf("\t.byte 0x%02x, 0x%02x",
452                                 (table[i]->len & 0x7F) | 0x80,
453                                 (table[i]->len >> 7) & 0x7F);
454                         off += table[i]->len + 2;
455                 }
456                 for (k = 0; k < table[i]->len; k++)
457                         printf(", 0x%02x", table[i]->sym[k]);
458 
459                 /*
460                  * Now that we wrote out the compressed symbol name, restore the
461                  * original name and print it in the comment.
462                  */
463                 expand_symbol(table[i]->sym, table[i]->len, buf);
464                 strcpy((char *)table[i]->sym, buf);
465                 printf("\t/* %s */\n", table[i]->sym);
466         }
467         printf("\n");
468 
469         output_label("kallsyms_markers");
470         for (i = 0; i < markers_cnt; i++)
471                 printf("\t.long\t%u\n", markers[i]);
472         printf("\n");
473 
474         free(markers);
475 
476         output_label("kallsyms_token_table");
477         off = 0;
478         for (i = 0; i < 256; i++) {
479                 best_idx[i] = off;
480                 expand_symbol(best_table[i], best_table_len[i], buf);
481                 printf("\t.asciz\t\"%s\"\n", buf);
482                 off += strlen(buf) + 1;
483         }
484         printf("\n");
485 
486         output_label("kallsyms_token_index");
487         for (i = 0; i < 256; i++)
488                 printf("\t.short\t%d\n", best_idx[i]);
489         printf("\n");
490 
491         output_label("kallsyms_offsets");
492 
493         for (i = 0; i < table_cnt; i++) {
494                 /*
495                  * Use the offset relative to the lowest value
496                  * encountered of all relative symbols, and emit
497                  * non-relocatable fixed offsets that will be fixed
498                  * up at runtime.
499                  */
500 
501                 long long offset;
502                 int overflow;
503 
504                 if (!absolute_percpu) {
505                         offset = table[i]->addr - relative_base;
506                         overflow = (offset < 0 || offset > UINT_MAX);
507                 } else if (symbol_absolute(table[i])) {
508                         offset = table[i]->addr;
509                         overflow = (offset < 0 || offset > INT_MAX);
510                 } else {
511                         offset = relative_base - table[i]->addr - 1;
512                         overflow = (offset < INT_MIN || offset >= 0);
513                 }
514                 if (overflow) {
515                         fprintf(stderr, "kallsyms failure: "
516                                 "%s symbol value %#llx out of range in relative mode\n",
517                                 symbol_absolute(table[i]) ? "absolute" : "relative",
518                                 table[i]->addr);
519                         exit(EXIT_FAILURE);
520                 }
521                 printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
522         }
523         printf("\n");
524 
525         output_label("kallsyms_relative_base");
526         output_address(relative_base);
527         printf("\n");
528 
529         if (lto_clang)
530                 for (i = 0; i < table_cnt; i++)
531                         cleanup_symbol_name((char *)table[i]->sym);
532 
533         sort_symbols_by_name();
534         output_label("kallsyms_seqs_of_names");
535         for (i = 0; i < table_cnt; i++)
536                 printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n",
537                         (unsigned char)(table[i]->seq >> 16),
538                         (unsigned char)(table[i]->seq >> 8),
539                         (unsigned char)(table[i]->seq >> 0),
540                        table[i]->sym);
541         printf("\n");
542 }
543 
544 
545 /* table lookup compression functions */
546 
547 /* count all the possible tokens in a symbol */
548 static void learn_symbol(const unsigned char *symbol, int len)
549 {
550         int i;
551 
552         for (i = 0; i < len - 1; i++)
553                 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
554 }
555 
556 /* decrease the count for all the possible tokens in a symbol */
557 static void forget_symbol(const unsigned char *symbol, int len)
558 {
559         int i;
560 
561         for (i = 0; i < len - 1; i++)
562                 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
563 }
564 
565 /* do the initial token count */
566 static void build_initial_token_table(void)
567 {
568         unsigned int i;
569 
570         for (i = 0; i < table_cnt; i++)
571                 learn_symbol(table[i]->sym, table[i]->len);
572 }
573 
574 static unsigned char *find_token(unsigned char *str, int len,
575                                  const unsigned char *token)
576 {
577         int i;
578 
579         for (i = 0; i < len - 1; i++) {
580                 if (str[i] == token[0] && str[i+1] == token[1])
581                         return &str[i];
582         }
583         return NULL;
584 }
585 
586 /* replace a given token in all the valid symbols. Use the sampled symbols
587  * to update the counts */
588 static void compress_symbols(const unsigned char *str, int idx)
589 {
590         unsigned int i, len, size;
591         unsigned char *p1, *p2;
592 
593         for (i = 0; i < table_cnt; i++) {
594 
595                 len = table[i]->len;
596                 p1 = table[i]->sym;
597 
598                 /* find the token on the symbol */
599                 p2 = find_token(p1, len, str);
600                 if (!p2) continue;
601 
602                 /* decrease the counts for this symbol's tokens */
603                 forget_symbol(table[i]->sym, len);
604 
605                 size = len;
606 
607                 do {
608                         *p2 = idx;
609                         p2++;
610                         size -= (p2 - p1);
611                         memmove(p2, p2 + 1, size);
612                         p1 = p2;
613                         len--;
614 
615                         if (size < 2) break;
616 
617                         /* find the token on the symbol */
618                         p2 = find_token(p1, size, str);
619 
620                 } while (p2);
621 
622                 table[i]->len = len;
623 
624                 /* increase the counts for this symbol's new tokens */
625                 learn_symbol(table[i]->sym, len);
626         }
627 }
628 
629 /* search the token with the maximum profit */
630 static int find_best_token(void)
631 {
632         int i, best, bestprofit;
633 
634         bestprofit=-10000;
635         best = 0;
636 
637         for (i = 0; i < 0x10000; i++) {
638                 if (token_profit[i] > bestprofit) {
639                         best = i;
640                         bestprofit = token_profit[i];
641                 }
642         }
643         return best;
644 }
645 
646 /* this is the core of the algorithm: calculate the "best" table */
647 static void optimize_result(void)
648 {
649         int i, best;
650 
651         /* using the '\0' symbol last allows compress_symbols to use standard
652          * fast string functions */
653         for (i = 255; i >= 0; i--) {
654 
655                 /* if this table slot is empty (it is not used by an actual
656                  * original char code */
657                 if (!best_table_len[i]) {
658 
659                         /* find the token with the best profit value */
660                         best = find_best_token();
661                         if (token_profit[best] == 0)
662                                 break;
663 
664                         /* place it in the "best" table */
665                         best_table_len[i] = 2;
666                         best_table[i][0] = best & 0xFF;
667                         best_table[i][1] = (best >> 8) & 0xFF;
668 
669                         /* replace this token in all the valid symbols */
670                         compress_symbols(best_table[i], i);
671                 }
672         }
673 }
674 
675 /* start by placing the symbols that are actually used on the table */
676 static void insert_real_symbols_in_table(void)
677 {
678         unsigned int i, j, c;
679 
680         for (i = 0; i < table_cnt; i++) {
681                 for (j = 0; j < table[i]->len; j++) {
682                         c = table[i]->sym[j];
683                         best_table[c][0]=c;
684                         best_table_len[c]=1;
685                 }
686         }
687 }
688 
689 static void optimize_token_table(void)
690 {
691         build_initial_token_table();
692 
693         insert_real_symbols_in_table();
694 
695         optimize_result();
696 }
697 
698 /* guess for "linker script provide" symbol */
699 static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
700 {
701         const char *symbol = sym_name(se);
702         int len = se->len - 1;
703 
704         if (len < 8)
705                 return 0;
706 
707         if (symbol[0] != '_' || symbol[1] != '_')
708                 return 0;
709 
710         /* __start_XXXXX */
711         if (!memcmp(symbol + 2, "start_", 6))
712                 return 1;
713 
714         /* __stop_XXXXX */
715         if (!memcmp(symbol + 2, "stop_", 5))
716                 return 1;
717 
718         /* __end_XXXXX */
719         if (!memcmp(symbol + 2, "end_", 4))
720                 return 1;
721 
722         /* __XXXXX_start */
723         if (!memcmp(symbol + len - 6, "_start", 6))
724                 return 1;
725 
726         /* __XXXXX_end */
727         if (!memcmp(symbol + len - 4, "_end", 4))
728                 return 1;
729 
730         return 0;
731 }
732 
733 static int compare_symbols(const void *a, const void *b)
734 {
735         const struct sym_entry *sa = *(const struct sym_entry **)a;
736         const struct sym_entry *sb = *(const struct sym_entry **)b;
737         int wa, wb;
738 
739         /* sort by address first */
740         if (sa->addr > sb->addr)
741                 return 1;
742         if (sa->addr < sb->addr)
743                 return -1;
744 
745         /* sort by "weakness" type */
746         wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
747         wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
748         if (wa != wb)
749                 return wa - wb;
750 
751         /* sort by "linker script provide" type */
752         wa = may_be_linker_script_provide_symbol(sa);
753         wb = may_be_linker_script_provide_symbol(sb);
754         if (wa != wb)
755                 return wa - wb;
756 
757         /* sort by the number of prefix underscores */
758         wa = strspn(sym_name(sa), "_");
759         wb = strspn(sym_name(sb), "_");
760         if (wa != wb)
761                 return wa - wb;
762 
763         /* sort by initial order, so that other symbols are left undisturbed */
764         return sa->seq - sb->seq;
765 }
766 
767 static void sort_symbols(void)
768 {
769         qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
770 }
771 
772 static void make_percpus_absolute(void)
773 {
774         unsigned int i;
775 
776         for (i = 0; i < table_cnt; i++)
777                 if (symbol_in_range(table[i], &percpu_range, 1)) {
778                         /*
779                          * Keep the 'A' override for percpu symbols to
780                          * ensure consistent behavior compared to older
781                          * versions of this tool.
782                          */
783                         table[i]->sym[0] = 'A';
784                         table[i]->percpu_absolute = true;
785                 }
786 }
787 
788 /* find the minimum non-absolute symbol address */
789 static void record_relative_base(void)
790 {
791         unsigned int i;
792 
793         for (i = 0; i < table_cnt; i++)
794                 if (!symbol_absolute(table[i])) {
795                         /*
796                          * The table is sorted by address.
797                          * Take the first non-absolute symbol value.
798                          */
799                         relative_base = table[i]->addr;
800                         return;
801                 }
802 }
803 
804 int main(int argc, char **argv)
805 {
806         while (1) {
807                 static const struct option long_options[] = {
808                         {"all-symbols",     no_argument, &all_symbols,     1},
809                         {"absolute-percpu", no_argument, &absolute_percpu, 1},
810                         {"lto-clang",       no_argument, &lto_clang,       1},
811                         {},
812                 };
813 
814                 int c = getopt_long(argc, argv, "", long_options, NULL);
815 
816                 if (c == -1)
817                         break;
818                 if (c != 0)
819                         usage();
820         }
821 
822         if (optind >= argc)
823                 usage();
824 
825         read_map(argv[optind]);
826         shrink_table();
827         if (absolute_percpu)
828                 make_percpus_absolute();
829         sort_symbols();
830         record_relative_base();
831         optimize_token_table();
832         write_src();
833 
834         return 0;
835 }
836 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php