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',

Reply via email to