From 21ffd6a4df43c2e1fe679312fc618a8d5b48d4b3 Mon Sep 17 00:00:00 2001 From: Ylarod Date: Sun, 5 Apr 2026 12:24:51 +0800 Subject: [PATCH 01/16] kernel: trim non-exported symbols (#3397) --- .github/workflows/ddk-lkm.yml | 4 +- kernel/.gitignore | 3 + kernel/Makefile | 13 +- kernel/build-all.sh | 3 +- kernel/tools/gen_keep_globals.c | 445 +++++++++++++++++++++++++++++ kernel/tools/localize_symbols.sh | 120 ++++++++ kernel/tools/trim_local_symnames.c | 284 ++++++++++++++++++ 7 files changed, 865 insertions(+), 7 deletions(-) create mode 100644 kernel/tools/gen_keep_globals.c create mode 100755 kernel/tools/localize_symbols.sh create mode 100644 kernel/tools/trim_local_symnames.c diff --git a/.github/workflows/ddk-lkm.yml b/.github/workflows/ddk-lkm.yml index 0b1b43f155c1..2d42384e118e 100644 --- a/.github/workflows/ddk-lkm.yml +++ b/.github/workflows/ddk-lkm.yml @@ -58,7 +58,7 @@ jobs: if [ -n "$EXPECTED_SIZE2" ]; then EXTRA_ARGS="KSU_EXPECTED_SIZE2=$EXPECTED_SIZE2 KSU_EXPECTED_HASH2=$EXPECTED_HASH2" fi - CONFIG_KSU=m CC=clang make $EXTRA_ARGS + CONFIG_KSU=m CC=clang make release $EXTRA_ARGS echo "=== Build completed ===" @@ -72,8 +72,6 @@ jobs: echo "Copied to: /github/workspace/out/$OUTPUT_NAME" ls -la "/github/workspace/out/$OUTPUT_NAME" echo "Size: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)" - llvm-strip -d "/github/workspace/out/$OUTPUT_NAME" - echo "Size after stripping: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)" - name: Upload kernelsu.ko artifact uses: actions/upload-artifact@v7 diff --git a/kernel/.gitignore b/kernel/.gitignore index b661888af7c6..3c8c6223bc01 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -21,4 +21,7 @@ CLAUDE.md .ddk-version .vscode/settings.json check_symbol +gen_keep_globals +trim_local_symnames ksu_uapi.h +.codex diff --git a/kernel/Makefile b/kernel/Makefile index 068476e00ce0..8c0b25f9f1cc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -4,19 +4,28 @@ MDIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) $(info -- KDIR: $(KDIR)) $(info -- MDIR: $(MDIR)) -.PHONY: all compdb clean format check-format +.PHONY: all release tools compdb clean format check-format all: check_symbol make -C $(KDIR) M=$(MDIR) modules -j$(shell nproc) ./check_symbol kernelsu.ko $(KDIR)/vmlinux +release: all tools + ./tools/localize_symbols.sh kernelsu.ko kernelsu.ko + +tools: check_symbol gen_keep_globals trim_local_symnames + compdb: python3 $(MDIR)/.vscode/generate_compdb.py -O $(KDIR) $(MDIR) clean: make -C $(KDIR) M=$(MDIR) clean - rm check_symbol + rm -f check_symbol gen_keep_globals trim_local_symnames check_symbol: tools/check_symbol.c $(CC) tools/check_symbol.c -o check_symbol +gen_keep_globals: tools/gen_keep_globals.c + $(CC) -O2 -Wall -Wextra -std=c11 tools/gen_keep_globals.c -o gen_keep_globals +trim_local_symnames: tools/trim_local_symnames.c + $(CC) -O2 -Wall -Wextra -std=c11 tools/trim_local_symnames.c -o trim_local_symnames format: find . \( -name "*.c" -o -name "*.h" \) -print0 | xargs -0 clang-format -i check-format: diff --git a/kernel/build-all.sh b/kernel/build-all.sh index 3eef2614e415..7e2c030526b1 100755 --- a/kernel/build-all.sh +++ b/kernel/build-all.sh @@ -10,10 +10,9 @@ mv .ddk-version .ddk-version.bak || true for kmi in $KMIS; do echo "========== Building $kmi ==========" export DDK_TARGET=$kmi - if ddk build -e CONFIG_KSU=m; then + if ddk build -e CONFIG_KSU=m -- release; then if [ -f kernelsu.ko ]; then cp kernelsu.ko "kernelsu-${kmi}.ko" - llvm-objcopy --strip-unneeded --discard-locals "kernelsu-${kmi}.ko" echo "✓ Built kernelsu-${kmi}.ko" fi else diff --git a/kernel/tools/gen_keep_globals.c b/kernel/tools/gen_keep_globals.c new file mode 100644 index 000000000000..0f16f825c9d5 --- /dev/null +++ b/kernel/tools/gen_keep_globals.c @@ -0,0 +1,445 @@ +#define _XOPEN_SOURCE 700 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + char **items; + size_t len; + size_t cap; +} strset_t; + +typedef struct { + void *data; + size_t size; + int fd; + Elf64_Ehdr *ehdr; + Elf64_Shdr *shdr; +} elf_file_t; + +static strset_t g_keep; + +static void die(const char *msg) +{ + fprintf(stderr, "error: %s\n", msg); + exit(1); +} + +static void die_perror(const char *msg) +{ + fprintf(stderr, "error: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static void strset_init(strset_t *s) +{ + memset(s, 0, sizeof(*s)); +} + +static void strset_free(strset_t *s) +{ + for (size_t i = 0; i < s->len; i++) { + free(s->items[i]); + } + free(s->items); + memset(s, 0, sizeof(*s)); +} + +static bool strset_contains(const strset_t *s, const char *v) +{ + for (size_t i = 0; i < s->len; i++) { + if (strcmp(s->items[i], v) == 0) { + return true; + } + } + return false; +} + +static void strset_add(strset_t *s, const char *v) +{ + if (!v || v[0] == '\0' || strset_contains(s, v)) { + return; + } + if (s->len == s->cap) { + size_t ncap = s->cap ? s->cap * 2 : 64; + char **n = realloc(s->items, ncap * sizeof(*n)); + if (!n) { + die("out of memory"); + } + s->items = n; + s->cap = ncap; + } + s->items[s->len] = strdup(v); + if (!s->items[s->len]) { + die("out of memory"); + } + s->len++; +} + +static int cmp_strptr(const void *a, const void *b) +{ + const char *const *sa = a; + const char *const *sb = b; + return strcmp(*sa, *sb); +} + +static bool ends_with(const char *s, const char *suffix) +{ + size_t a = strlen(s); + size_t b = strlen(suffix); + if (a < b) { + return false; + } + return strcmp(s + a - b, suffix) == 0; +} + +static bool is_ident_start(char c) +{ + return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +static bool is_ident_char(char c) +{ + return is_ident_start(c) || (c >= '0' && c <= '9'); +} + +static char *read_whole_file(const char *path, size_t *out_size) +{ + int fd = open(path, O_RDONLY); + if (fd < 0) { + return NULL; + } + struct stat st; + if (fstat(fd, &st) < 0 || st.st_size < 0) { + close(fd); + return NULL; + } + size_t sz = (size_t)st.st_size; + char *buf = malloc(sz + 1); + if (!buf) { + close(fd); + return NULL; + } + size_t off = 0; + while (off < sz) { + ssize_t n = read(fd, buf + off, sz - off); + if (n <= 0) { + free(buf); + close(fd); + return NULL; + } + off += (size_t)n; + } + close(fd); + buf[sz] = '\0'; + if (out_size) { + *out_size = sz; + } + return buf; +} + +static void parse_export_macros(const char *buf, size_t sz, strset_t *out) +{ + size_t i = 0; + while (i < sz) { + const char *needle = "EXPORT_SYMBOL"; + size_t nlen = strlen(needle); + + if (i + nlen >= sz || strncmp(buf + i, needle, nlen) != 0) { + i++; + continue; + } + if (i > 0 && is_ident_char(buf[i - 1])) { + i++; + continue; + } + + size_t j = i + nlen; + if (j + 4 <= sz && strncmp(buf + j, "_GPL", 4) == 0) { + j += 4; + } + while (j < sz && isspace((unsigned char)buf[j])) { + j++; + } + if (j >= sz || buf[j] != '(') { + i++; + continue; + } + j++; + while (j < sz && isspace((unsigned char)buf[j])) { + j++; + } + if (j >= sz || !is_ident_start(buf[j])) { + i++; + continue; + } + size_t st = j++; + while (j < sz && is_ident_char(buf[j])) { + j++; + } + size_t len = j - st; + while (j < sz && isspace((unsigned char)buf[j])) { + j++; + } + if (j >= sz || buf[j] != ')' || len == 0 || len >= 512) { + i++; + continue; + } + char sym[512]; + memcpy(sym, buf + st, len); + sym[len] = '\0'; + strset_add(out, sym); + i = j + 1; + } +} + +static int collect_src_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) +{ + (void)sb; + (void)ftwbuf; + if (typeflag != FTW_F) { + return 0; + } + if (!ends_with(fpath, ".c") && !ends_with(fpath, ".h")) { + return 0; + } + size_t sz = 0; + char *buf = read_whole_file(fpath, &sz); + if (!buf) { + return 0; + } + parse_export_macros(buf, sz, &g_keep); + free(buf); + return 0; +} + +static void collect_exported_from_source(const char *src_root, strset_t *keep) +{ + g_keep = *keep; + if (nftw(src_root, collect_src_cb, 16, FTW_PHYS) != 0) { + die_perror("nftw"); + } + *keep = g_keep; +} + +static bool elf_open_ro(const char *path, elf_file_t *elf) +{ + memset(elf, 0, sizeof(*elf)); + elf->fd = open(path, O_RDONLY); + if (elf->fd < 0) { + return false; + } + struct stat st; + if (fstat(elf->fd, &st) < 0) { + close(elf->fd); + return false; + } + elf->size = (size_t)st.st_size; + elf->data = mmap(NULL, elf->size, PROT_READ, MAP_PRIVATE, elf->fd, 0); + if (elf->data == MAP_FAILED) { + close(elf->fd); + return false; + } + elf->ehdr = (Elf64_Ehdr *)elf->data; + if (memcmp(elf->ehdr->e_ident, ELFMAG, SELFMAG) != 0 || elf->ehdr->e_ident[EI_CLASS] != ELFCLASS64) { + munmap(elf->data, elf->size); + close(elf->fd); + return false; + } + elf->shdr = (Elf64_Shdr *)((char *)elf->data + elf->ehdr->e_shoff); + return true; +} + +static void elf_close(elf_file_t *elf) +{ + if (!elf || !elf->data) { + return; + } + munmap(elf->data, elf->size); + close(elf->fd); + memset(elf, 0, sizeof(*elf)); +} + +static Elf64_Shdr *find_symtab(elf_file_t *elf) +{ + for (int i = 0; i < elf->ehdr->e_shnum; i++) { + if (elf->shdr[i].sh_type == SHT_SYMTAB) { + return &elf->shdr[i]; + } + } + return NULL; +} + +static void collect_exported_from_elf(const char *ko_path, strset_t *keep) +{ + elf_file_t elf; + if (!elf_open_ro(ko_path, &elf)) { + die("failed to open ELF"); + } + Elf64_Shdr *symtab = find_symtab(&elf); + if (!symtab) { + elf_close(&elf); + die("no .symtab"); + } + Elf64_Shdr *strsec = &elf.shdr[symtab->sh_link]; + Elf64_Sym *syms = (Elf64_Sym *)((char *)elf.data + symtab->sh_offset); + const char *strtab = (const char *)elf.data + strsec->sh_offset; + size_t n = symtab->sh_size / sizeof(Elf64_Sym); + for (size_t i = 0; i < n; i++) { + if (syms[i].st_name == 0) { + continue; + } + const char *name = strtab + syms[i].st_name; + if (strncmp(name, "__ksymtab_", 10) == 0 && name[10] != '\0') { + strset_add(keep, name + 10); + } + } + elf_close(&elf); +} + +static void split_csv_keep(strset_t *keep, const char *csv) +{ + if (!csv || csv[0] == '\0') { + return; + } + const char *p = csv; + while (*p) { + while (*p == ',' || isspace((unsigned char)*p)) { + p++; + } + const char *s = p; + while (*p && *p != ',') { + p++; + } + const char *e = p; + while (e > s && isspace((unsigned char)e[-1])) { + e--; + } + if (e > s) { + size_t len = (size_t)(e - s); + if (len < 512) { + char tmp[512]; + memcpy(tmp, s, len); + tmp[len] = '\0'; + strset_add(keep, tmp); + } + } + if (*p == ',') { + p++; + } + } +} + +static void add_keep_file(strset_t *keep, const char *path) +{ + FILE *fp = fopen(path, "r"); + if (!fp) { + die_perror("open keep file"); + } + char line[1024]; + while (fgets(line, sizeof(line), fp)) { + char *hash = strchr(line, '#'); + if (hash) { + *hash = '\0'; + } + char *p = line; + while (*p && isspace((unsigned char)*p)) { + p++; + } + char *e = p + strlen(p); + while (e > p && isspace((unsigned char)e[-1])) { + *--e = '\0'; + } + if (*p) { + strset_add(keep, p); + } + } + fclose(fp); +} + +static void usage(const char *argv0) +{ + fprintf(stderr, + "Usage: %s [options]\n" + "Options:\n" + " --src-root \n" + " --keep \n" + " --keep-file \n" + " --no-default-keep\n" + " --out (default stdout)\n", + argv0); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + usage(argv[0]); + return 1; + } + const char *input_ko = argv[1]; + const char *src_root = "."; + const char *extra_keep = NULL; + const char *keep_file = NULL; + const char *out_path = NULL; + bool default_keep = true; + + for (int i = 2; i < argc; i++) { + if (strcmp(argv[i], "--src-root") == 0 && i + 1 < argc) { + src_root = argv[++i]; + } else if (strcmp(argv[i], "--keep") == 0 && i + 1 < argc) { + extra_keep = argv[++i]; + } else if (strcmp(argv[i], "--keep-file") == 0 && i + 1 < argc) { + keep_file = argv[++i]; + } else if (strcmp(argv[i], "--no-default-keep") == 0) { + default_keep = false; + } else if (strcmp(argv[i], "--out") == 0 && i + 1 < argc) { + out_path = argv[++i]; + } else { + usage(argv[0]); + return 1; + } + } + + strset_t keep; + strset_init(&keep); + collect_exported_from_elf(input_ko, &keep); + collect_exported_from_source(src_root, &keep); + if (default_keep) { + strset_add(&keep, "init_module"); + strset_add(&keep, "cleanup_module"); + strset_add(&keep, "__this_module"); + } + split_csv_keep(&keep, extra_keep); + if (keep_file) { + add_keep_file(&keep, keep_file); + } + + qsort(keep.items, keep.len, sizeof(char *), cmp_strptr); + + FILE *out = stdout; + if (out_path) { + out = fopen(out_path, "w"); + if (!out) { + strset_free(&keep); + die_perror("open output"); + } + } + for (size_t i = 0; i < keep.len; i++) { + fprintf(out, "%s\n", keep.items[i]); + } + if (out_path) { + fclose(out); + } + strset_free(&keep); + return 0; +} diff --git a/kernel/tools/localize_symbols.sh b/kernel/tools/localize_symbols.sh new file mode 100755 index 000000000000..3f6a25d91ed5 --- /dev/null +++ b/kernel/tools/localize_symbols.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: + tools/localize_symbols.sh [options] + +Options: + --keep + --keep-file + --no-default-keep + --no-anon-locals +USAGE +} + +if [[ $# -lt 2 ]]; then + usage + exit 1 +fi + +in_ko="$1" +out_ko="$2" +shift 2 + +extra_keep="" +extra_keep_file="" +no_default_keep=0 +anon_locals=1 +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd "${script_dir}/.." && pwd)" +gen_bin="${repo_root}/gen_keep_globals" +trim_bin="${repo_root}/trim_local_symnames" + +while [[ $# -gt 0 ]]; do + case "$1" in + --keep) + extra_keep="$2" + shift 2 + ;; + --keep-file) + extra_keep_file="$2" + shift 2 + ;; + --no-default-keep) + no_default_keep=1 + shift + ;; + --no-anon-locals) + anon_locals=0 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown arg: $1" >&2 + usage + exit 1 + ;; + esac +done + +if [[ ! -f "$in_ko" ]]; then + echo "input file not found: $in_ko" >&2 + exit 1 +fi + +if ! command -v llvm-objcopy >/dev/null 2>&1; then + echo "llvm-objcopy not found" >&2 + exit 1 +fi + +if [[ ! -x "${gen_bin}" || ! -x "${trim_bin}" ]]; then + echo "missing tools: ${gen_bin} or ${trim_bin}" >&2 + echo "run: make tools" >&2 + exit 1 +fi + +tmp_keep="$(mktemp /tmp/ksu-keep.XXXXXX)" +tmp_out="" +trap 'rm -f "$tmp_keep" "${tmp_out}"' EXIT + +gen_args=("$in_ko" "--out" "$tmp_keep") +if [[ -n "$extra_keep" ]]; then + gen_args+=("--keep" "$extra_keep") +fi +if [[ -n "$extra_keep_file" ]]; then + gen_args+=("--keep-file" "$extra_keep_file") +fi +if [[ "$no_default_keep" -eq 1 ]]; then + gen_args+=("--no-default-keep") +fi + +"${gen_bin}" "${gen_args[@]}" + +work_ko="$out_ko" +if [[ "$in_ko" == "$out_ko" ]]; then + tmp_out="$(mktemp /tmp/ksu-localize.XXXXXX.ko)" + cp -f "$in_ko" "$tmp_out" + work_ko="$tmp_out" +else + cp -f "$in_ko" "$work_ko" +fi + +llvm-objcopy --keep-global-symbols="$tmp_keep" "$work_ko" +llvm-objcopy --strip-unneeded "$work_ko" + +if [[ "$anon_locals" -eq 1 ]]; then + "${trim_bin}" "$work_ko" --keep-file "$tmp_keep" +fi + +if [[ "$in_ko" == "$out_ko" ]]; then + mv -f "$work_ko" "$out_ko" + tmp_out="" +fi + +echo "final stats:" +readelf -Ws "$out_ko" | awk 'NR>3{all++; if($5=="LOCAL")l++; if($5=="GLOBAL")g++; if($5=="WEAK")w++} END{printf("all=%d local=%d global=%d weak=%d\n",all,l,g,w)}' diff --git a/kernel/tools/trim_local_symnames.c b/kernel/tools/trim_local_symnames.c new file mode 100644 index 000000000000..597ebf00395b --- /dev/null +++ b/kernel/tools/trim_local_symnames.c @@ -0,0 +1,284 @@ +#define _XOPEN_SOURCE 700 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + char **items; + size_t len; + size_t cap; +} strset_t; + +typedef struct { + void *data; + size_t size; + int fd; + Elf64_Ehdr *ehdr; + Elf64_Shdr *shdr; +} elf_file_t; + +static void die(const char *msg) +{ + fprintf(stderr, "error: %s\n", msg); + exit(1); +} + +static void die_perror(const char *msg) +{ + fprintf(stderr, "error: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static void strset_init(strset_t *s) +{ + memset(s, 0, sizeof(*s)); +} + +static void strset_free(strset_t *s) +{ + for (size_t i = 0; i < s->len; i++) { + free(s->items[i]); + } + free(s->items); + memset(s, 0, sizeof(*s)); +} + +static bool strset_contains(const strset_t *s, const char *v) +{ + for (size_t i = 0; i < s->len; i++) { + if (strcmp(s->items[i], v) == 0) { + return true; + } + } + return false; +} + +static void strset_add(strset_t *s, const char *v) +{ + if (!v || v[0] == '\0' || strset_contains(s, v)) { + return; + } + if (s->len == s->cap) { + size_t ncap = s->cap ? s->cap * 2 : 64; + char **n = realloc(s->items, ncap * sizeof(*n)); + if (!n) { + die("out of memory"); + } + s->items = n; + s->cap = ncap; + } + s->items[s->len] = strdup(v); + if (!s->items[s->len]) { + die("out of memory"); + } + s->len++; +} + +static void add_keep_file(strset_t *keep, const char *path) +{ + FILE *fp = fopen(path, "r"); + if (!fp) { + die_perror("open keep file"); + } + char line[1024]; + while (fgets(line, sizeof(line), fp)) { + char *hash = strchr(line, '#'); + if (hash) { + *hash = '\0'; + } + char *p = line; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') { + p++; + } + char *e = p + strlen(p); + while (e > p && (e[-1] == ' ' || e[-1] == '\t' || e[-1] == '\n' || e[-1] == '\r')) { + *--e = '\0'; + } + if (*p) { + strset_add(keep, p); + } + } + fclose(fp); +} + +static bool elf_open_rw(const char *path, elf_file_t *elf) +{ + memset(elf, 0, sizeof(*elf)); + elf->fd = open(path, O_RDWR); + if (elf->fd < 0) { + return false; + } + struct stat st; + if (fstat(elf->fd, &st) < 0) { + close(elf->fd); + return false; + } + elf->size = (size_t)st.st_size; + elf->data = mmap(NULL, elf->size, PROT_READ | PROT_WRITE, MAP_SHARED, elf->fd, 0); + if (elf->data == MAP_FAILED) { + close(elf->fd); + return false; + } + elf->ehdr = (Elf64_Ehdr *)elf->data; + if (memcmp(elf->ehdr->e_ident, ELFMAG, SELFMAG) != 0 || elf->ehdr->e_ident[EI_CLASS] != ELFCLASS64) { + munmap(elf->data, elf->size); + close(elf->fd); + return false; + } + elf->shdr = (Elf64_Shdr *)((char *)elf->data + elf->ehdr->e_shoff); + return true; +} + +static void elf_close(elf_file_t *elf) +{ + if (!elf || !elf->data) { + return; + } + msync(elf->data, elf->size, MS_SYNC); + munmap(elf->data, elf->size); + close(elf->fd); + memset(elf, 0, sizeof(*elf)); +} + +static Elf64_Shdr *find_symtab(elf_file_t *elf) +{ + for (int i = 0; i < elf->ehdr->e_shnum; i++) { + if (elf->shdr[i].sh_type == SHT_SYMTAB) { + return &elf->shdr[i]; + } + } + return NULL; +} + +static void usage(const char *argv0) +{ + fprintf(stderr, + "Usage: %s [--keep-file ]\n" + "Anonymize names of defined LOCAL symbols and compact .strtab\n", + argv0); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + usage(argv[0]); + return 1; + } + const char *target = argv[1]; + const char *keep_file = NULL; + for (int i = 2; i < argc; i++) { + if (strcmp(argv[i], "--keep-file") == 0 && i + 1 < argc) { + keep_file = argv[++i]; + } else { + usage(argv[0]); + return 1; + } + } + + strset_t keep; + strset_init(&keep); + if (keep_file) { + add_keep_file(&keep, keep_file); + } + + elf_file_t elf; + if (!elf_open_rw(target, &elf)) { + strset_free(&keep); + die("failed to open target ELF"); + } + + Elf64_Shdr *symtab = find_symtab(&elf); + if (!symtab) { + elf_close(&elf); + strset_free(&keep); + die("no .symtab found"); + } + Elf64_Shdr *strsec = &elf.shdr[symtab->sh_link]; + Elf64_Sym *syms = (Elf64_Sym *)((char *)elf.data + symtab->sh_offset); + char *strtab = (char *)elf.data + strsec->sh_offset; + size_t sym_count = symtab->sh_size / sizeof(Elf64_Sym); + size_t str_size = strsec->sh_size; + size_t old_str_size = str_size; + + size_t anonymized = 0; + for (size_t i = 0; i < sym_count; i++) { + unsigned bind = ELF64_ST_BIND(syms[i].st_info); + unsigned type = ELF64_ST_TYPE(syms[i].st_info); + if (bind != STB_LOCAL || syms[i].st_name == 0 || syms[i].st_shndx == SHN_UNDEF || type == STT_FILE || + type == STT_SECTION) { + continue; + } + const char *name = strtab + syms[i].st_name; + if (name[0] == '\0' || strset_contains(&keep, name)) { + continue; + } + syms[i].st_name = 0; + anonymized++; + } + + uint32_t *map = malloc((str_size ? str_size : 1) * sizeof(uint32_t)); + char *newtab = malloc(str_size ? str_size : 1); + if (!map || !newtab) { + free(map); + free(newtab); + elf_close(&elf); + strset_free(&keep); + die("out of memory"); + } + for (size_t i = 0; i < str_size; i++) { + map[i] = UINT32_MAX; + } + size_t new_size = 1; + newtab[0] = '\0'; + if (str_size > 0) { + map[0] = 0; + } + + for (size_t i = 0; i < sym_count; i++) { + uint32_t old = syms[i].st_name; + if (old == 0) { + continue; + } + if (old >= str_size) { + syms[i].st_name = 0; + continue; + } + if (map[old] != UINT32_MAX) { + syms[i].st_name = map[old]; + continue; + } + size_t max = str_size - old; + size_t len = strnlen(strtab + old, max); + if (len == max || new_size + len + 1 > str_size) { + syms[i].st_name = 0; + continue; + } + map[old] = (uint32_t)new_size; + memcpy(newtab + new_size, strtab + old, len + 1); + syms[i].st_name = (uint32_t)new_size; + new_size += len + 1; + } + + memcpy(strtab, newtab, new_size); + if (new_size < str_size) { + memset(strtab + new_size, 0, str_size - new_size); + } + strsec->sh_size = new_size; + + printf("trimmed: anonymized=%zu strtab=%zu->%zu\n", anonymized, old_str_size, new_size); + + free(map); + free(newtab); + elf_close(&elf); + strset_free(&keep); + return 0; +} From 59fcbc2d3b3299e2c687308f4b20adf152350de2 Mon Sep 17 00:00:00 2001 From: I3elphegor Date: Thu, 23 Apr 2026 00:33:37 +0200 Subject: [PATCH 02/16] Added translation using Weblate (Czech) --- manager/app/src/main/res/values-cs/strings.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 manager/app/src/main/res/values-cs/strings.xml diff --git a/manager/app/src/main/res/values-cs/strings.xml b/manager/app/src/main/res/values-cs/strings.xml new file mode 100644 index 000000000000..55344e51920f --- /dev/null +++ b/manager/app/src/main/res/values-cs/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file From dfa3bec4922b8a3ed868a32fd1d0d48f5c6949cb Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:04 +0200 Subject: [PATCH 03/16] Translated using Weblate (Kannada) Currently translated at 20.0% (55 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/kn/ --- manager/app/src/main/res/values-kn/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-kn/strings.xml b/manager/app/src/main/res/values-kn/strings.xml index db651c171fbe..7a47d806ec3b 100644 --- a/manager/app/src/main/res/values-kn/strings.xml +++ b/manager/app/src/main/res/values-kn/strings.xml @@ -58,7 +58,7 @@ ಕರ್ನಲ್ %s ಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನವೀಕರಿಸಲು ವಿಫಲವಾಗಿದೆ https://kernelsu.org/guide/what-is-kernelsu.html - %1$s ನಲ್ಲಿ ಮೂಲ ಕೋಡ್ ಅನ್ನು ವೀಕ್ಷಿಸಿ
ನಮ್ಮ %2$s ಚಾನಲ್‌ಗೆ ಸೇರಿ
+ ನಮ್ಮ %2$s ಚಾನಲ್‌ಗೆ ಸೇರಿ]]> ಮ್ಯಾನೇಜರ್ ವರ್ಷನ್ ಹೊಸ ಆವೃತ್ತಿ: %s ಲಭ್ಯವಿದೆ, ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ ಲಾಗ್ಗಳನ್ನು ಉಳಿಸಿ From 48f29438600eb8bda361c7eeb43d124eec29ab8d Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:33:53 +0200 Subject: [PATCH 04/16] Translated using Weblate (Azerbaijani) Currently translated at 29.0% (80 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/az/ --- manager/app/src/main/res/values-az/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-az/strings.xml b/manager/app/src/main/res/values-az/strings.xml index d6469a6f37c2..bba367316a16 100644 --- a/manager/app/src/main/res/values-az/strings.xml +++ b/manager/app/src/main/res/values-az/strings.xml @@ -49,8 +49,7 @@ Defolt Özəl KernelSU pulsuz və açıq mənbəlidir,həmişə belə olacaqdır. Bununla belə, ianə etməklə bizə qayğı göstərdiyinizi göstərə bilərsiniz. - Mənbə kodlarımıza baxın %1$s
-Kanalımıza %2$s qoşulun
+ Kanalımıza %2$s qoşulun]]> Profil adı Bacarıqlar Modulları umount et From 15c13226bb378a442cdbda3e6dd85375f114b5d2 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:33:58 +0200 Subject: [PATCH 05/16] Translated using Weblate (Persian) Currently translated at 19.6% (54 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/fa/ --- manager/app/src/main/res/values-fa/strings.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/manager/app/src/main/res/values-fa/strings.xml b/manager/app/src/main/res/values-fa/strings.xml index 8000037eb778..3644b9c250c6 100644 --- a/manager/app/src/main/res/values-fa/strings.xml +++ b/manager/app/src/main/res/values-fa/strings.xml @@ -46,9 +46,7 @@ یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید از ما حمایت کنید KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است. - -Join our %2$s channel ]]> - + Join our %2$s channel ]]> پروفایل برنامه پیش‌فرض قالب From 7cb93bb50b3953d06f10e82fda2ee34d38fcfb8e Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:06 +0200 Subject: [PATCH 06/16] Translated using Weblate (Marathi) Currently translated at 23.6% (65 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/mr/ --- manager/app/src/main/res/values-mr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-mr/strings.xml b/manager/app/src/main/res/values-mr/strings.xml index b1d37a5f91bb..66dcb4d39bf6 100644 --- a/manager/app/src/main/res/values-mr/strings.xml +++ b/manager/app/src/main/res/values-mr/strings.xml @@ -52,7 +52,7 @@ साचा वैयक्तिक क्षमता - %1$s वर स्रोत कोड पहा
आमच्या %2$s चॅनेलमध्ये सामील व्हा
+ आमच्या %2$s चॅनेलमध्ये सामील व्हा]]> प्रोफाइल नाव इनहेरीटेड जागतिक From 38f8d3887c55f4dc247e60ee2ba93b927e15717b Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:06 +0200 Subject: [PATCH 07/16] Translated using Weblate (Latvian) Currently translated at 32.3% (89 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/lv/ --- manager/app/src/main/res/values-lv/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-lv/strings.xml b/manager/app/src/main/res/values-lv/strings.xml index 6eeb688413d9..1b9d2c344801 100644 --- a/manager/app/src/main/res/values-lv/strings.xml +++ b/manager/app/src/main/res/values-lv/strings.xml @@ -46,7 +46,7 @@ https://kernelsu.org/guide/what-is-kernelsu.html Uzzināt, kā instalēt KernelSU un izmantot moduļus Atbalsti mūs - Skatiet avota kodu vietnē %1$s
Pievienojies mūsu %2$s kanālam
+ Pievienojies mūsu %2$s kanālam]]> Noklusējums Veidne Pielāgots From e6c5831cb18c617777febbf9d3047e24e43d4f17 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:00 +0200 Subject: [PATCH 08/16] Translated using Weblate (Hindi) Currently translated at 24.0% (66 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/hi/ --- manager/app/src/main/res/values-hi/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-hi/strings.xml b/manager/app/src/main/res/values-hi/strings.xml index d8e0db9657ef..031b6d3f5df4 100644 --- a/manager/app/src/main/res/values-hi/strings.xml +++ b/manager/app/src/main/res/values-hi/strings.xml @@ -72,8 +72,7 @@ https://kernelsu.org/guide/what-is-kernelsu.html %s के लिए SELinux नियमों को अपटेड करने में विफल बुटलोडर में रिबूट करें - %1$s पर स्रोत कोड देखें
-हमारे %2$s चैनल से जुड़ें
+ हमारे %2$s चैनल से जुड़ें]]> मैनेजर वर्जन नया वर्जन: %s उपलब्ध है,अपग्रेड के लिए क्लिक करें लॉग सहेजें From 5697faca006c64599ce29c0bd5069e4263257341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20Moln=C3=A1r?= Date: Mon, 11 May 2026 11:34:01 +0200 Subject: [PATCH 09/16] Translated using Weblate (Hungarian) Currently translated at 38.9% (107 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/hu/ --- manager/app/src/main/res/values-hu/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-hu/strings.xml b/manager/app/src/main/res/values-hu/strings.xml index b25111cb5ba4..04f7aa637b93 100644 --- a/manager/app/src/main/res/values-hu/strings.xml +++ b/manager/app/src/main/res/values-hu/strings.xml @@ -19,8 +19,7 @@ Tudjon meg többet a KernelSU-ról Ismerje meg a KernelSU telepítését és a modulok használatát Támogasson minket - Tekintse meg a forráskódot a %1$s-on
-Csatlakozzon a %2$s csatornánkhoz
+ Csatlakozzon a %2$s csatornánkhoz]]> Alapértelmezett Sablon Egyedi From b3968c8e2c81721253ef8c230e1af989a217ab94 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:03 +0200 Subject: [PATCH 10/16] Translated using Weblate (Hebrew) Currently translated at 21.0% (58 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/he/ --- manager/app/src/main/res/values-iw/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-iw/strings.xml b/manager/app/src/main/res/values-iw/strings.xml index b64a08016faf..1bc126500e14 100644 --- a/manager/app/src/main/res/values-iw/strings.xml +++ b/manager/app/src/main/res/values-iw/strings.xml @@ -72,7 +72,7 @@ https://kernelsu.org/guide/what-is-kernelsu.html נכשל עדכון כללי SELinux עבור: %s הפעלה מחדש לבוטלאודר - ראה את קוד המקור ב%1$s
הצטרף אלינו %2$s בערוץ
+ הצטרף אלינו %2$s בערוץ]]> גרסת מנהל גרסה חדשה עבור: %s זמינה, לחץ כדי לשדרג שמור יומנים From 46e7f023e931f140658a8d6d5d704afd8ac25b8d Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:09 +0200 Subject: [PATCH 11/16] Translated using Weblate (Portuguese) Currently translated at 23.6% (65 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/pt/ --- manager/app/src/main/res/values-pt/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-pt/strings.xml b/manager/app/src/main/res/values-pt/strings.xml index 8fe87b18415f..7dd79b7b3703 100644 --- a/manager/app/src/main/res/values-pt/strings.xml +++ b/manager/app/src/main/res/values-pt/strings.xml @@ -40,8 +40,7 @@ Mostrar aplicativos do sistema Aprenda a instalar o KernelSU e usar os módulos O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode nos mostrar que se importa fazendo uma doação. - Veja o código-fonte em %1$s
-Junte-se ao nosso canal %2$s
+ Junte-se ao nosso canal %2$s]]> Individual Global Herdado From 5330d63b1b43cb5537f307bf8e54444dc7afe2fc Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:33:58 +0200 Subject: [PATCH 12/16] Translated using Weblate (Estonian) Currently translated at 38.1% (105 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/et/ --- manager/app/src/main/res/values-et/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-et/strings.xml b/manager/app/src/main/res/values-et/strings.xml index 294a68ea871a..9f158acbc6ea 100644 --- a/manager/app/src/main/res/values-et/strings.xml +++ b/manager/app/src/main/res/values-et/strings.xml @@ -60,8 +60,7 @@ Grupid KernelSU on, ja alati jääb, tasuta ning avatud lähtekoodiga kättesaadavaks. Sellegipoolest võid sa näidata, et hoolid, ning teha annetuse. Mall - Vaata lähtekoodi %1$sis
-Liitu meie %2$si kanaliga
+ Liitu meie %2$si kanaliga]]> Profiili nimi Kohandatud Päritud From e6c9110f761587d518262919a86e108c92af1474 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:05 +0200 Subject: [PATCH 13/16] Translated using Weblate (Lithuanian) Currently translated at 24.3% (67 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/lt/ --- manager/app/src/main/res/values-lt/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-lt/strings.xml b/manager/app/src/main/res/values-lt/strings.xml index 15a2e8d937ab..62ce228752b3 100644 --- a/manager/app/src/main/res/values-lt/strings.xml +++ b/manager/app/src/main/res/values-lt/strings.xml @@ -28,7 +28,7 @@ https://kernelsu.org/guide/what-is-kernelsu.html Sužinokite apie KernelSU Sužinokite, kaip įdiegti KernelSU ir naudoti modulius - Peržiūrėkite šaltinio kodą %1$s
Prisijunkite prie mūsų %2$s kanalo
+ Prisijunkite prie mūsų %2$s kanalo]]> Numatytas Šablonas Pasirinktinis From d8bafd73b695de5f68086c207fb68e2cc9e1a465 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:33:57 +0200 Subject: [PATCH 14/16] Translated using Weblate (Spanish) Currently translated at 36.0% (99 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/es/ --- manager/app/src/main/res/values-es/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/app/src/main/res/values-es/strings.xml b/manager/app/src/main/res/values-es/strings.xml index 048f3733b5af..0657c1d96d8a 100644 --- a/manager/app/src/main/res/values-es/strings.xml +++ b/manager/app/src/main/res/values-es/strings.xml @@ -47,8 +47,7 @@ Aprende a instalar KernelSU y a utilizar módulos Apóyanos KernelSU es, y siempre será, gratuito y de código abierto. Sin embargo, puedes demostrarnos que te importamos haciendo una donación. - Ver código fuente en %1$s
-Únete a nuestro canal %2$s
+ Únete a nuestro canal %2$s]]> Predeterminado Plantilla Personalizado From 67f634f55a046eb4292d9e469e50db632a6b2a3b Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:33:55 +0200 Subject: [PATCH 15/16] Translated using Weblate (Bosnian) Currently translated at 25.4% (70 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/bs/ --- manager/app/src/main/res/values-bs/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-bs/strings.xml b/manager/app/src/main/res/values-bs/strings.xml index 0f47c42f67f4..65741d314519 100644 --- a/manager/app/src/main/res/values-bs/strings.xml +++ b/manager/app/src/main/res/values-bs/strings.xml @@ -44,7 +44,7 @@ Podržite Nas Pošaljite Izvještaj Naučite KernelSU - Pogledajte izvornu kodu na %1$s
Pridružite nam se na %2$s kanalu
+ Pridružite nam se na %2$s kanalu]]> Domena Pravila Neuspješno ažuriranje SELinux pravila za: %s From bbc8148af86240902fe4020b682b81d6a0f32917 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 11 May 2026 11:34:11 +0200 Subject: [PATCH 16/16] Translated using Weblate (Slovenian) Currently translated at 26.9% (74 of 275 strings) Translation: KernelSU/Manager Translate-URL: https://hosted.weblate.org/projects/kernelsu/manager/sl/ --- manager/app/src/main/res/values-sl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/app/src/main/res/values-sl/strings.xml b/manager/app/src/main/res/values-sl/strings.xml index 12ed20d393be..a6b45b41965f 100644 --- a/manager/app/src/main/res/values-sl/strings.xml +++ b/manager/app/src/main/res/values-sl/strings.xml @@ -27,7 +27,7 @@ Naučite se KernelSU https://kernelsu.org/guide/what-is-kernelsu.html Naučite se, kako namestiti KernelSU in uporabiti module - Glej odprto kodo na %1$s
Pridružite se našem %2$s kanalu
+ Pridružite se našem %2$s kanalu]]> Privzeto Predloga Imenski prostor vmestitve