[PATCH 08/23] kallsyms: reimplement mksysmap in C
From: Lorenzo Stoakes (ARM)
Date: Tue Sep 08 2026 - 18:12:32 EST
mksysmap is a sed script consisting of 30 patterns which link-vmlinux.sh
uses to generate *.syms files, and which kallsyms is then called against to
generate *.kallsyms files, with the final vmlinux build ultimately
generating System.map.
For an x86-64 allmodconfig build, this involves three nm runs over a 250
MiB file and half a million lines written and read each time - 0.5s per
pass for llvm-nm, and 0.2s for GNU nm, with parsing on top of that.
This is unnecessary, instead have kallsyms simply read the ELF file
directly making use of the existing elf-parse library in scripts/.
This changes kallsyms such that its input is no longer the output from nm,
but rather an ELF file.
However, if the input file is empty, it outputs an empty table, which
retains the same behaviour on first pass that the build system expects.
System.map is byte-identical to nm | mksysmap for GNU nm and llvm-nm on
two x86 configurations each, and for llvm-nm on arm64, arm, s390 and
loongarch defconfigs, so are the kallsyms tables of every pass.
Relinking vmlinux, link steps included:
before after
allmodconfig clang 9.1s 7.9s
allmodconfig gcc 7.8s 7.6s
defconfig clang 3.7s 3.0s
defconfig gcc 3.5s 3.4s
Whole build, 128-thread Threadripper 9980X, best of N runs:
before after delta
-------------------------------
x86 defconfig, touch mm/vma.c, gcc 9.4s 8.9s -0.45s (-5%)
x86 defconfig, touch mm/vma.c, clang 9.2s 8.1s -1.1s (-12%)
x86 defconfig, clean, gcc 28.1s 27.6s -0.51s (-2%)
x86 defconfig, clean, clang 28.2s 27.2s -1.0s (-4%)
x86 allmodconfig, touch mm/vma.c, gcc 42.7s 42.0s -0.70s (-2%)
x86 allmodconfig, touch mm/vma.c, clang 40.2s 38.1s -2.1s (-5%)
Assisted-by: LLM
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx>
---
scripts/Makefile | 4 +-
scripts/kallsyms-sysmap.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++
scripts/kallsyms.c | 162 ++++++++++++++++------------
scripts/kallsyms.h | 44 ++++++++
scripts/link-vmlinux.sh | 15 +--
scripts/mksysmap | 94 ----------------
6 files changed, 415 insertions(+), 173 deletions(-)
diff --git a/scripts/Makefile b/scripts/Makefile
index 3434a82a119f..d46932113b5f 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -3,7 +3,7 @@
# scripts contains sources for various helper programs used throughout
# the kernel for the build process.
-hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms
+hostprogs-always-y += kallsyms
hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
@@ -13,6 +13,7 @@ hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder
hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen
hostprogs-always-$(CONFIG_TRACEPOINTS) += tracepoint-update
+kallsyms-objs := kallsyms.o kallsyms-sysmap.o elf-parse.o
sorttable-objs := sorttable.o elf-parse.o
tracepoint-update-objs := tracepoint-update.o elf-parse.o
@@ -30,6 +31,7 @@ rustdoc_test_builder-rust := y
rustdoc_test_gen-rust := y
HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include
+HOSTCFLAGS_kallsyms-sysmap.o = -I$(srctree)/tools/include
HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
HOSTLDLIBS_sorttable = -lpthread
diff --git a/scripts/kallsyms-sysmap.c b/scripts/kallsyms-sysmap.c
new file mode 100644
index 000000000000..64b2e11d0344
--- /dev/null
+++ b/scripts/kallsyms-sysmap.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Obtain symbols from vmlinux for usage by kallsyms. Replaces mksysmap.
+ *
+ * To retain compatibility, it provides the same output as nm, only faster.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xalloc.h>
+
+#include "elf-parse.h"
+#include "kallsyms.h"
+
+/* The mapped file and its symbol table. */
+struct elf_file {
+ void *base;
+ size_t size;
+ const char *shdrs;
+ unsigned int shnum, shentsize;
+ const char *shstrtab;
+ Elf_Shdr *symtab;
+ const char *strtab;
+ size_t nr_syms;
+};
+
+/* What mksysmap dropped from System.map, by name. */
+static const char *const sysmap_omit_prefixes[] = {
+ "$", ".L", "__efistub_", "__pi_$", "__pi_.L", "__kvm_nvhe_$",
+ "__kvm_nvhe_.L", "__kcfi_typeid_", "__kvm_nvhe___kcfi_typeid_",
+ "__pi___kcfi_typeid_", "__crc_", "__kstrtab_", "__kstrtabns_",
+ "__mod_device_table__",
+};
+static const char *const sysmap_omit_suffixes[] = {
+ "_from_arm", "_from_thumb", "_veneer",
+};
+static const char *const sysmap_omit_names[] = {
+ "L0", "_SDA_BASE_", "_SDA2_BASE_",
+};
+
+/* __<alnum>*Thunk_: the linker's range extension thunks on arm. */
+static bool is_range_thunk(const char *name)
+{
+ const char *p;
+
+ if (!string_starts_with(name, "__"))
+ return false;
+ for (p = name + 2; isalnum((unsigned char)*p); p++)
+ ;
+ return p - name >= 7 && *p == '_' && strncmp(p - 5, "Thunk", 5) == 0;
+}
+
+/* __UNIQUE_ID_modinfo_<n>: the MODULE_INFO() strings of built-in code. */
+static bool is_modinfo_id(const char *name)
+{
+ static const char prefix[] = "__UNIQUE_ID_modinfo_";
+ const char *p;
+
+ if (!string_starts_with(name, prefix))
+ return false;
+ for (p = name + strlen(prefix); isdigit((unsigned char)*p); p++)
+ ;
+ return !*p;
+}
+
+static bool sysmap_omits(const char *name, char type)
+{
+ size_t i;
+
+ /* Absolute, undefined and debugging symbols. */
+ if (type == 'a' || type == 'N' || type == 'U' || type == 'w')
+ return true;
+
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_prefixes); i++)
+ if (string_starts_with(name, sysmap_omit_prefixes[i]))
+ return true;
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_suffixes); i++)
+ if (string_ends_with(name, sysmap_omit_suffixes[i]))
+ return true;
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_names); i++)
+ if (strcmp(name, sysmap_omit_names[i]) == 0)
+ return true;
+
+ return is_range_thunk(name) || is_modinfo_id(name) ||
+ strstr(name, ".long_branch.") || strstr(name, ".plt_branch.");
+}
+
+static Elf_Shdr *elf_section(const struct elf_file *elf, unsigned int index)
+{
+ return (Elf_Shdr *)(elf->shdrs + (size_t)index * elf->shentsize);
+}
+
+static const char *elf_section_name(const struct elf_file *elf, Elf_Shdr *shdr)
+{
+ return elf->shstrtab + shdr_name(shdr);
+}
+
+static Elf_Sym *elf_symbol(const struct elf_file *elf, size_t index)
+{
+ const char *base = elf->base;
+
+ return (Elf_Sym *)(base + shdr_offset(elf->symtab) +
+ index * shdr_entsize(elf->symtab));
+}
+
+/* nm's letter for a symbol defined in a section, as BFD classifies it. */
+static char section_symbol_type(Elf_Shdr *shdr, const char *secname)
+{
+ static const char *const debug_prefixes[] = {
+ ".debug", ".zdebug", ".gnu.debuglto_.debug_",
+ ".gnu.linkonce.wi.", ".line", ".stab",
+ };
+ const uint64_t flags = shdr_flags(shdr);
+ size_t i;
+
+ if (flags & SHF_EXECINSTR)
+ return 't';
+ if (flags & SHF_ALLOC) {
+ if (shdr_type(shdr) == SHT_NOBITS)
+ return 'b';
+ return flags & SHF_WRITE ? 'd' : 'r';
+ }
+ for (i = 0; i < ARRAY_SIZE(debug_prefixes); i++)
+ if (string_starts_with(secname, debug_prefixes[i]))
+ return 'N';
+ if (shdr_type(shdr) != SHT_NOBITS && !(flags & SHF_WRITE))
+ return 'n';
+ return '?';
+}
+
+/* The letter nm prints for a symbol, or 0 for one it leaves out. */
+static char elf_symbol_type(const struct elf_file *elf, Elf_Sym *sym)
+{
+ unsigned int bind = sym_bind(sym), type = sym_type(sym);
+ unsigned int shndx = sym_shndx(sym);
+ Elf_Shdr *shdr;
+ char c;
+
+ if (type == STT_SECTION || type == STT_FILE)
+ return 0;
+ if (shndx == SHN_COMMON)
+ return 'C';
+ if (shndx == SHN_UNDEF) {
+ if (bind == STB_WEAK)
+ return type == STT_OBJECT ? 'v' : 'w';
+ return 'U';
+ }
+ if (type == STT_GNU_IFUNC)
+ return 'i';
+ if (bind == STB_WEAK)
+ return type == STT_OBJECT ? 'V' : 'W';
+ if (bind == STB_GNU_UNIQUE)
+ return 'u';
+ if (bind != STB_GLOBAL && bind != STB_LOCAL)
+ return '?';
+
+ if (shndx == SHN_ABS) {
+ c = 'a';
+ } else if (shndx < elf->shnum) {
+ shdr = elf_section(elf, shndx);
+ c = section_symbol_type(shdr, elf_section_name(elf, shdr));
+ } else {
+ return '?';
+ }
+
+ return bind == STB_GLOBAL ? toupper(c) : c;
+}
+
+/* nm -n order: by address, then by name. */
+static int compare_symbols(const void *a, const void *b)
+{
+ const struct sysmap_symbol *sa = a, *sb = b;
+
+ if (sa->addr != sb->addr)
+ return sa->addr < sb->addr ? -1 : 1;
+ return strcmp(sa->name, sb->name);
+}
+
+static void elf_open(struct elf_file *elf, const char *path)
+{
+ Elf_Ehdr *ehdr;
+ unsigned int i;
+
+ elf->base = elf_map_ro(path, &elf->size, (1 << ET_EXEC) | (1 << ET_DYN));
+ if (!elf->base)
+ exit(EXIT_FAILURE);
+
+ ehdr = elf->base;
+ elf->shdrs = (const char *)elf->base + ehdr_shoff(ehdr);
+ elf->shnum = ehdr_shnum(ehdr);
+ elf->shentsize = ehdr_shentsize(ehdr);
+ elf->shstrtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, ehdr_shstrndx(ehdr)));
+
+ for (i = 0; i < elf->shnum && !elf->symtab; i++)
+ if (shdr_type(elf_section(elf, i)) == SHT_SYMTAB)
+ elf->symtab = elf_section(elf, i);
+
+ if (!elf->symtab) {
+ fprintf(stderr, "%s: no symbol table\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ elf->strtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, shdr_link(elf->symtab)));
+ elf->nr_syms = shdr_size(elf->symtab) / shdr_entsize(elf->symtab);
+}
+
+/* The symbols "nm -n | mksysmap" would list, in that order. */
+static struct sysmap_symbol *elf_read_symbols(const struct elf_file *elf,
+ size_t *nr_kept)
+{
+ struct sysmap_symbol *syms = xmalloc(elf->nr_syms * sizeof(*syms));
+ size_t i, n = 0;
+
+ for (i = 1; i < elf->nr_syms; i++) {
+ Elf_Sym *sym = elf_symbol(elf, i);
+ const char *name = elf->strtab + sym_name(sym);
+ char type = elf_symbol_type(elf, sym);
+
+ if (!type || sysmap_omits(name, type))
+ continue;
+
+ syms[n].addr = sym_value(sym);
+ syms[n].name = name;
+ syms[n].type = type;
+ n++;
+ }
+
+ qsort(syms, n, sizeof(*syms), compare_symbols);
+ *nr_kept = n;
+ return syms;
+}
+
+struct sysmap *sysmap_read(const char *path)
+{
+ struct sysmap *map = xcalloc(1, sizeof(*map));
+ struct elf_file elf = {};
+
+ elf_open(&elf, path);
+ map->syms = elf_read_symbols(&elf, &map->nr_syms);
+ map->addr_width = elf_map_long_size(elf.base) * 2;
+ /* The names point into the mapping; keep it until the map is freed. */
+ map->file = elf.base;
+ map->file_size = elf.size;
+
+ return map;
+}
+
+void sysmap_write(const struct sysmap *map, FILE *out)
+{
+ size_t i;
+
+ for (i = 0; i < map->nr_syms; i++) {
+ const struct sysmap_symbol *s = &map->syms[i];
+
+ fprintf(out, "%0*llx %c %s\n", map->addr_width, s->addr, s->type,
+ s->name);
+ }
+}
+
+void sysmap_free(struct sysmap *map)
+{
+ free(map->syms);
+ elf_unmap(map->file, map->file_size);
+ free(map);
+}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 61c5eb537ed4..b383696c3d81 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -5,7 +5,12 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- * Usage: kallsyms [--all-symbols] [--pc-relative] in.map out.bin > out.S
+ * Usage: kallsyms [--all-symbols] [--pc-relative] [--sysmap=out.map] in out.bin > out.S
+ * kallsyms --sysmap=out.map in
+ *
+ * in is vmlinux; an empty file stands for the first link, which has no
+ * symbols yet, and gives an empty table. --sysmap also writes the symbols
+ * in System.map format.
*
* The byte tables go to out.bin and are pulled into out.S with .incbin;
* wider tables stay assembler source for endianness and relocations.
@@ -21,7 +26,6 @@
*
*/
-#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
@@ -29,10 +33,10 @@
#include <string.h>
#include <ctype.h>
#include <limits.h>
-
+#include <sys/stat.h>
#include <xalloc.h>
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+#include "kallsyms.h"
#define KSYM_NAME_LEN 512
@@ -105,11 +109,13 @@ static void sym_arr_free(struct sym_arr *arr)
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] [--pc-relative] in.map out.bin > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] [--pc-relative] [--sysmap=out.map]\n"
+ " in out.bin > out.S\n"
+ " kallsyms --sysmap=out.map vmlinux\n");
exit(1);
}
-static char *sym_name(const struct sym_entry *s)
+static char *sym_entry_name(const struct sym_entry *s)
{
return (char *)s->sym + 1;
}
@@ -150,37 +156,12 @@ static void check_symbol_range(const char *sym, unsigned long long addr,
}
}
-static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
+static struct sym_entry *add_symbol(unsigned long long addr, char type,
+ const char *name)
{
- char *name, type, *p;
- unsigned long long addr;
- size_t len;
- ssize_t readlen;
+ size_t len = strlen(name);
struct sym_entry *sym;
- errno = 0;
- readlen = getline(buf, buf_len, in);
- if (readlen < 0) {
- if (errno) {
- perror("read_symbol");
- exit(EXIT_FAILURE);
- }
- return NULL;
- }
-
- if ((*buf)[readlen - 1] == '\n')
- (*buf)[readlen - 1] = 0;
-
- addr = strtoull(*buf, &p, 16);
-
- if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') {
- fprintf(stderr, "line format error\n");
- exit(EXIT_FAILURE);
- }
-
- name = p;
- len = strlen(name);
-
if (len >= KSYM_NAME_LEN) {
fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n"
"Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
@@ -205,7 +186,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
sym->addr = addr;
sym->len = len;
sym->sym[0] = type;
- strcpy(sym_name(sym), name);
+ strcpy(sym_entry_name(sym), name);
return sym;
}
@@ -226,14 +207,9 @@ static int symbol_in_range(const struct sym_entry *s,
return 0;
}
-static bool string_starts_with(const char *s, const char *prefix)
-{
- return strncmp(s, prefix, strlen(prefix)) == 0;
-}
-
static int symbol_valid(const struct sym_entry *s)
{
- const char *name = sym_name(s);
+ const char *name = sym_entry_name(s);
/* if --all-symbols is not specified, then symbols outside the text
* and inittext sections are discarded */
@@ -283,36 +259,55 @@ static void shrink_table(void)
table_cnt = pos;
}
-static void read_map(const char *in)
+static void add_table_entry(struct sym_entry *sym)
{
- FILE *fp;
- struct sym_entry *sym;
- char *buf = NULL;
- size_t buflen = 0;
+ sym->seq = table_cnt;
- fp = fopen(in, "r");
- if (!fp) {
- perror(in);
- exit(1);
+ if (table_cnt >= table_size) {
+ table_size += 10000;
+ table = xrealloc(table, sizeof(*table) * table_size);
}
- while (!feof(fp)) {
- sym = read_symbol(fp, &buf, &buflen);
- if (!sym)
- continue;
+ table[table_cnt++] = sym;
+}
- sym->seq = table_cnt;
+static bool file_is_empty(const char *path)
+{
+ struct stat st;
- if (table_cnt >= table_size) {
- table_size += 10000;
- table = xrealloc(table, sizeof(*table) * table_size);
- }
+ if (stat(path, &st)) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ return st.st_size == 0;
+}
+
+/*
+ * Read the symbols from vmlinux, writing System.map if asked to. The first
+ * link has no symbols yet: an empty file gives an empty table.
+ */
+static void read_elf(const char *path, FILE *sysmap_out)
+{
+ struct sysmap *map;
+ size_t i;
+
+ if (file_is_empty(path))
+ return;
+
+ map = sysmap_read(path);
+ if (sysmap_out)
+ sysmap_write(map, sysmap_out);
+
+ for (i = 0; i < map->nr_syms; i++) {
+ const struct sysmap_symbol *s = &map->syms[i];
+ struct sym_entry *sym = add_symbol(s->addr, s->type, s->name);
- table[table_cnt++] = sym;
+ if (sym)
+ add_table_entry(sym);
}
- free(buf);
- fclose(fp);
+ sysmap_free(map);
}
static void output_label(const char *label)
@@ -389,7 +384,7 @@ static int compare_names(const void *a, const void *b)
const struct sym_entry *sa = *(const struct sym_entry **)a;
const struct sym_entry *sb = *(const struct sym_entry **)b;
- ret = strcmp(sym_name(sa), sym_name(sb));
+ ret = strcmp(sym_entry_name(sa), sym_entry_name(sb));
if (!ret) {
if (sa->addr > sb->addr)
return 1;
@@ -765,7 +760,7 @@ static void optimize_token_table(void)
/* guess for "linker script provide" symbol */
static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
{
- const char *symbol = sym_name(se);
+ const char *symbol = sym_entry_name(se);
int len = se->len - 1;
if (len < 8)
@@ -822,8 +817,8 @@ static int compare_symbols(const void *a, const void *b)
return wa - wb;
/* sort by the number of prefix underscores */
- wa = strspn(sym_name(sa), "_");
- wb = strspn(sym_name(sb), "_");
+ wa = strspn(sym_entry_name(sa), "_");
+ wb = strspn(sym_entry_name(sb), "_");
if (wa != wb)
return wa - wb;
@@ -838,13 +833,14 @@ static void sort_symbols(void)
int main(int argc, char **argv)
{
- const char *out_bin_name;
- FILE *out_bin_file;
+ const char *in, *sysmap = NULL, *out_bin_name;
+ FILE *sysmap_out = NULL, *out_bin_file;
while (1) {
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
{"pc-relative", no_argument, &pc_relative, 1},
+ {"sysmap", required_argument, NULL, 's'},
{},
};
@@ -852,13 +848,33 @@ int main(int argc, char **argv)
if (c == -1)
break;
- if (c != 0)
+ if (c == 's')
+ sysmap = optarg;
+ else if (c != 0)
usage();
}
- if (optind + 2 != argc)
+ if (optind + 2 != argc && !(sysmap && optind + 1 == argc))
usage();
+ in = argv[optind];
+ if (sysmap) {
+ sysmap_out = fopen(sysmap, "w");
+ if (!sysmap_out) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind + 1 == argc) {
+ read_elf(in, sysmap_out);
+ if (fclose(sysmap_out)) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+ }
+
out_bin_name = argv[optind + 1];
out_bin_file = fopen(out_bin_name, "w");
if (!out_bin_file) {
@@ -866,7 +882,11 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
- read_map(argv[optind]);
+ read_elf(in, sysmap_out);
+ if (sysmap_out && fclose(sysmap_out)) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
shrink_table();
sort_symbols();
optimize_token_table();
diff --git a/scripts/kallsyms.h b/scripts/kallsyms.h
new file mode 100644
index 000000000000..12096978075f
--- /dev/null
+++ b/scripts/kallsyms.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef KALLSYMS_H
+#define KALLSYMS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <array_size.h>
+
+static inline bool string_starts_with(const char *s, const char *prefix)
+{
+ return strncmp(s, prefix, strlen(prefix)) == 0;
+}
+
+static inline bool string_ends_with(const char *s, const char *suffix)
+{
+ size_t len = strlen(s), suffix_len = strlen(suffix);
+
+ return len >= suffix_len && strcmp(s + len - suffix_len, suffix) == 0;
+}
+
+/* A symbol as nm lists it. */
+struct sysmap_symbol {
+ unsigned long long addr;
+ const char *name;
+ char type;
+};
+
+/* The symbols of an ELF file that System.map lists, in its order. */
+struct sysmap {
+ struct sysmap_symbol *syms;
+ size_t nr_syms;
+ int addr_width; /* hex digits of an address */
+ void *file; /* the mapping the names point into */
+ size_t file_size;
+};
+
+struct sysmap *sysmap_read(const char *path);
+void sysmap_write(const struct sysmap *map, FILE *out);
+void sysmap_free(struct sysmap *map);
+
+#endif /* KALLSYMS_H */
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 09c5222ccb94..7e9d0676f59f 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -124,11 +124,15 @@ kallsymso_changed()
! cmp -s "${kallsymso_prev}.sym" "${kallsymso}.sym"
}
-# Create ${2}.o file with all symbols from the ${1} object file
+# Create ${2}.o with the kallsyms tables for ${1} (the vmlinux, or an empty
+# listing for the first pass); list the symbols used in ${3} if given.
kallsyms()
{
local kallsymopt;
+ if [ -n "${3:-}" ]; then
+ kallsymopt="--sysmap=${3}"
+ fi
if is_enabled CONFIG_KALLSYMS_ALL; then
kallsymopt="${kallsymopt} --all-symbols"
fi
@@ -151,18 +155,15 @@ kallsyms()
# Perform kallsyms for the given temporary vmlinux.
sysmap_and_kallsyms()
{
- mksysmap "${1}" "${1}.syms"
- kallsyms "${1}.syms" "${1}.kallsyms"
-
+ kallsyms "${1}" "${1}.kallsyms" "${1}.syms"
kallsyms_sysmap=${1}.syms
}
# Create map file with all symbols from ${1}
-# See mksymap for additional details
mksysmap()
{
- info NM ${2}
- ${NM} -n "${1}" | sed -f "${srctree}/scripts/mksysmap" > "${2}"
+ info SYSMAP ${2}
+ scripts/kallsyms --sysmap="${2}" "${1}"
}
sorttable()
diff --git a/scripts/mksysmap b/scripts/mksysmap
deleted file mode 100755
index 856b26ba2ac0..000000000000
--- a/scripts/mksysmap
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sed -f
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# sed script to filter out symbols that are not needed for System.map,
-# or not suitable for kallsyms. The input should be 'nm -n <file>'.
-#
-# System.map is used by module-init tools and some debugging
-# tools to retrieve the actual addresses of symbols in the kernel.
-#
-# readprofile starts reading symbols when _stext is found, and
-# continue until it finds a symbol which is not either of 'T', 't',
-# 'W' or 'w'.
-#
-# ---------------------------------------------------------------------------
-# Ignored symbol types
-#
-
-# a: local absolute symbols
-# N: debugging symbols
-# U: undefined global symbols
-# w: local weak symbols
-/ [aNUw] /d
-
-# ---------------------------------------------------------------------------
-# Ignored prefixes
-# (do not forget a space before each pattern)
-
-# local symbols for ARM, MIPS, etc.
-/ \$/d
-
-# local labels, .LBB, .Ltmpxxx, .L__unnamed_xx, .LASANPC, etc.
-/ \.L/d
-
-# arm64 EFI stub namespace
-/ __efistub_/d
-
-# arm64 local symbols in PIE namespace
-/ __pi_\$/d
-/ __pi_\.L/d
-
-# arm64 local symbols in non-VHE KVM namespace
-/ __kvm_nvhe_\$/d
-/ __kvm_nvhe_\.L/d
-
-# lld arm/aarch64/mips thunks
-/ __[[:alnum:]]*Thunk_/d
-
-# CFI type identifiers
-/ __kcfi_typeid_/d
-/ __kvm_nvhe___kcfi_typeid_/d
-/ __pi___kcfi_typeid_/d
-
-# CRC from modversions
-/ __crc_/d
-
-# EXPORT_SYMBOL (symbol name)
-/ __kstrtab_/d
-
-# EXPORT_SYMBOL (namespace)
-/ __kstrtabns_/d
-
-# MODULE_DEVICE_TABLE (symbol name)
-/ __mod_device_table__/d
-
-# ---------------------------------------------------------------------------
-# Ignored suffixes
-# (do not forget '$' after each pattern)
-
-# arm
-/_from_arm$/d
-/_from_thumb$/d
-/_veneer$/d
-
-# ---------------------------------------------------------------------------
-# Ignored symbols (exact match)
-# (do not forget a space before and '$' after each pattern)
-
-# for LoongArch?
-/ L0$/d
-
-# ppc
-/ _SDA_BASE_$/d
-/ _SDA2_BASE_$/d
-
-# MODULE_INFO()
-/ __UNIQUE_ID_modinfo_[0-9]*$/d
-
-# ---------------------------------------------------------------------------
-# Ignored patterns
-# (symbols that contain the pattern are ignored)
-
-# ppc stub
-/\.long_branch\./d
-/\.plt_branch\./d
--
2.55.0