commit: 3378c67ceb18e8c7cd9edd4da0b3e9a930e0b82c Author: Michał Górny <mgorny <AT> gentoo <DOT> org> AuthorDate: Sun Dec 14 18:26:57 2025 +0000 Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> CommitDate: Sun Dec 14 18:26:57 2025 +0000 URL: https://gitweb.gentoo.org/proj/blas-lapack-aux-wrapper.git/commit/?id=3378c67c
Use a dedicated C tool to get symbols Thanks-to: Alexander Monakov <amonakov <AT> ispras.ru> Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> list-elf-symbols.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ make-symbol-files.py | 39 +++++++------------------ meson.build | 8 ++++++ 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/list-elf-symbols.c b/list-elf-symbols.c new file mode 100644 index 0000000..8dd1dad --- /dev/null +++ b/list-elf-symbols.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: ISC +// https://codeberg.org/amonakov/elf-stubber +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include <link.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: %s <elf>\n", argv[0]); + return 1; + } + int fd; + if ((fd = open(argv[1], O_RDONLY)) < 0) { + perror(argv[1]); + return 1; + } + struct stat st; + if (fstat(fd, &st) < 0) { + perror("stat"); + return 1; + } + char *map; + if ((map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + perror("mmap"); + return 1; + } + ElfW(Ehdr) *ehdr = (void *)map; + ElfW(Shdr) *shdr = (void *)(map + ehdr->e_shoff); + assert(ehdr->e_shentsize == sizeof *shdr); + int i; + for (i = ehdr->e_shnum; i; shdr++, i--) { + if (shdr->sh_type == SHT_DYNSYM) + break; + } + if (!i) { + fputs("section .dynsym not found", stderr); + return 1; + } + ElfW(Sym) *sym = (void *)(map + shdr->sh_offset); + assert(shdr->sh_entsize == sizeof *sym); + assert(shdr->sh_size % sizeof *sym == 0); + ElfW(Sym) *end = (void *)(map + shdr->sh_offset + shdr->sh_size); + ElfW(Shdr) *strtab = (void *)(map + ehdr->e_shoff); + strtab += shdr->sh_link; + assert(strtab->sh_type == SHT_STRTAB); + char *str = map + strtab->sh_offset; + for (sym++; sym != end; sym++) { + int type = sym->st_info & 15; + int bind = sym->st_info >> 4; + int vis = sym->st_other & 3; + assert(bind == STB_GLOBAL || bind == STB_WEAK); + assert(vis == STV_DEFAULT || vis == STV_PROTECTED); + if (!sym->st_value) continue; + switch (type) { + case STT_NOTYPE: + case STT_SECTION: + case STT_FILE: + break; + case STT_OBJECT: + case STT_TLS: + fprintf(stderr, "TODO object %s [size %zd]\n", + str + sym->st_name, (size_t)sym->st_size); + break; + case STT_FUNC: + case STT_GNU_IFUNC: + puts(str + sym->st_name); + break; + default: + fprintf(stderr, "TODO symbol type %d\n", type); + } + } + + return 0; +} diff --git a/make-symbol-files.py b/make-symbol-files.py index 203dacc..b1e3eb9 100755 --- a/make-symbol-files.py +++ b/make-symbol-files.py @@ -10,40 +10,21 @@ from pathlib import Path from typing import Generator -def get_symbols(path: Path) -> Generator[str]: - env = os.environ.copy() - env["LC_MESSAGES"] = "C" - it = iter(subprocess.run(["readelf", "-W", "--dyn-syms", str(path)], +def get_symbols(path: Path, tool: Path) -> Generator[str]: + it = iter(subprocess.run([tool, path], stdout=subprocess.PIPE, - check=True, - env=env).stdout.decode().splitlines()) - for line in it: - if line.startswith("Symbol table"): - break - else: - raise RuntimeError("Symbol table output not found in readelf output!") - - header = next(it) - _num, _value, _size, typ, bind, vis, ndx, name = header.split() - assert typ == "Type" - assert bind == "Bind" - assert vis == "Vis" - assert ndx == "Ndx" - assert name == "Name" - - for line in it: - _num, _value, _size, typ, bind, vis, ndx, *rest = line.split() - if typ != "FUNC" or ndx == "UND": - continue - assert bind in ("GLOBAL", "WEAK") - assert vis in ("DEFAULT", "PROTECTED") - name, *_ = rest + check=True).stdout.decode().splitlines()) + for name in it: assert "@" not in name yield name def main(): argp = argparse.ArgumentParser() + argp.add_argument("--list-elf-symbols", + required=True, + type=Path, + help="Path to list-elf-symbols tool") argp.add_argument("--flexiblas", required=True, type=Path, @@ -60,9 +41,9 @@ def main(): args = argp.parse_args() args.output.mkdir(exist_ok=True) - flexiblas_sym = set(get_symbols(args.flexiblas)) + flexiblas_sym = set(get_symbols(args.flexiblas, args.list_elf_symbols)) for lib in args.lib: - lib_sym = set(get_symbols(lib)) + lib_sym = set(get_symbols(lib, args.list_elf_symbols)) common_sym = lib_sym.intersection(flexiblas_sym) missing_sym = lib_sym.difference(flexiblas_sym) if missing_sym: diff --git a/meson.build b/meson.build index 2d8b4e9..7cd7887 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,12 @@ dummy_obj = configure_file( capture : true, ) +list_elf_symbols = executable( + 'list-elf-symbols', + ['list-elf-symbols.c'], + native : true, +) + foreach suffix : suffixes flexiblas_dep = dependency(f'flexiblas@suffix@', required : true) flexiblas_ver = flexiblas_dep.version().split('.') @@ -49,6 +55,8 @@ foreach suffix : suffixes script = [ py, '@CURRENT_SOURCE_DIR@' / 'make-symbol-files.py', + '--list-elf-symbols', + list_elf_symbols, '--output', '@OUTDIR@', '--flexiblas',
