{"id":16333116,"url":"https://github.com/fzakaria/old","last_synced_at":"2025-10-06T02:57:52.530Z","repository":{"id":40574098,"uuid":"475561142","full_name":"fzakaria/old","owner":"fzakaria","description":"The Other Link Editor","archived":false,"fork":false,"pushed_at":"2023-08-26T22:38:42.000Z","size":92,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-16T07:51:37.885Z","etag":null,"topics":["dynamic-linking","glibc","rtld"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fzakaria.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-29T18:01:43.000Z","updated_at":"2024-05-17T18:38:55.000Z","dependencies_parsed_at":"2025-02-11T02:31:24.050Z","dependency_job_id":"397e8dc8-a9b2-4a29-a56d-9c0c8df0482b","html_url":"https://github.com/fzakaria/old","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fzakaria/old","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fzakaria","download_url":"https://codeload.github.com/fzakaria/old/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278551482,"owners_count":26005389,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dynamic-linking","glibc","rtld"],"created_at":"2024-10-10T23:34:23.247Z","updated_at":"2025-10-06T02:57:52.498Z","avatar_url":"https://github.com/fzakaria.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# old\n\n![main branch](https://github.com/fzakaria/old/actions/workflows/actions.yml/badge.svg)\n\n[![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)\n\n\n\u003e The Other Link Editor\n\nThe algorithm with which dependencies are found and selected have not changed since it's introduction in [Multics](https://en.wikipedia.org/wiki/Multics) and codifies in [SystemV ABI](http://www.sco.com/developers/devspecs/gabi41.pdf),\n\nThe current knobs offered by dynamic linkers are quite coarse by only allowing single lists that affect the resolution for any dependency such as _LD_LIBRARY_PATH_ or _RUN_PATH_.\n\nThis project is an exploration into _alternative_ resolution strategies for dynamic linking by leveraging [glibc runtime linking audit API](https://man7.org/linux/man-pages/man7/rtld-audit.7.html).\n\nLet's take a look a minimal example of doing a _key-value_ resolution strategy for the needed dependencies.\n\nWe create our _TOML_ file with the necessary information.\n```toml\nstrategy = \"key_value\"\n\n[key_value]\n# if strict mode is enabled, then all libraries must be included\nstrict = true\n# these need to be quoted since they have periods\n\"libruby-3.0.so.3.0\" = \"/lib/x86_64-linux-gnu/libruby-3.0.so.3.0\"\n\"libc.so.6\" = \"/lib/x86_64-linux-gnu/libc.so.6\"\n\"libpthread.so.0\" = \"/lib/x86_64-linux-gnu/libpthread.so.0\"\n\"librt.so.1\" = \"/lib/x86_64-linux-gnu/librt.so.1\"\n\"libgmp.so.10\" = \"/lib/x86_64-linux-gnu/libgmp.so.10\"\n\"libdl.so.2\" = \"/lib/x86_64-linux-gnu/libdl.so.2\"\n\"libcrypt.so.1\" = \"/lib/x86_64-linux-gnu/libcrypt.so.1\"\n\"libm.so.6\" = \"/lib/x86_64-linux-gnu/libm.so.6\"\n\"libz.so.1\" = \"/lib/x86_64-linux-gnu/libz.so.1\"\n```\n\nWe can now invoke any binary that has glibc dynamic linker in the interpreter section of the binary and specify _LD_AUDIT_ environment variable.\n\n\u003e You can easily get started and try the example by using [Nix](https://nixos.org).\n\u003e\n\u003e `LD_AUDIT=$(nix build github:fzakaria/old --no-link --json | jq -r \".[].outputs.out\")/bin/libold.so ruby -e \"puts 'hi'\"\n`\n\n```console\n$ OLDAUDIT_CONFIG=./example.toml LD_AUDIT=./bazel-bin/src/main/libold.so ruby --help | head\n\nI20220506 01:30:34.472784 1547568 main.cpp:56] Taking control of the linking search....\nI20220506 01:30:34.473285 1547568 key_value.cpp:17] replacing [libruby-3.0.so.3.0] with ['/lib/x86_64-linux-gnu/libruby-3.0.so.3.0']\nI20220506 01:30:34.473435 1547568 key_value.cpp:17] replacing [libc.so.6] with ['/lib/x86_64-linux-gnu/libc.so.6']\nI20220506 01:30:34.473569 1547568 key_value.cpp:17] replacing [libz.so.1] with ['/lib/x86_64-linux-gnu/libz.so.1']\nI20220506 01:30:34.473695 1547568 key_value.cpp:17] replacing [libpthread.so.0] with ['/lib/x86_64-linux-gnu/libpthread.so.0']\nI20220506 01:30:34.473809 1547568 key_value.cpp:17] replacing [librt.so.1] with ['/lib/x86_64-linux-gnu/librt.so.1']\nI20220506 01:30:34.473938 1547568 key_value.cpp:17] replacing [libgmp.so.10] with ['/lib/x86_64-linux-gnu/libgmp.so.10']\nI20220506 01:30:34.474058 1547568 key_value.cpp:17] replacing [libdl.so.2] with ['/lib/x86_64-linux-gnu/libdl.so.2']\nI20220506 01:30:34.474195 1547568 key_value.cpp:17] replacing [libcrypt.so.1] with ['/lib/x86_64-linux-gnu/libcrypt.so.1']\nI20220506 01:30:34.474318 1547568 key_value.cpp:17] replacing [libm.so.6] with ['/lib/x86_64-linux-gnu/libm.so.6']\nUsage: ruby [switches] [--] [programfile] [arguments]\n  -0[octal]       specify record separator (\\0, if no argument)\n  -a              autosplit mode with -n or -p (splits $_ into $F)\n  -c              check syntax only\n  -Cdirectory     cd to directory before executing your script\n  -d, --debug     set debugging flags (set $DEBUG to true)\n  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]\n  -Eex[:in], --encoding=ex[:in]\n                  specify the default external and internal character encodings\n  -Fpattern       split() pattern for autosplit (-a)\n```\n\n\u003e Right now the log messages are emitted to _stderr_ always.\n\nIf you want to explore other strategies take a look at [example.toml](example.toml).\n\n## Auditing\n\nOftentimes, binaries require more libraries than what is specifically required in the _DT_NEEDED_ section.\nLet's use `ruby` as an example.\n\nHere we can see what is required by the binary itself; there are 11 libraries.\n```console\n$ ldd $(which ruby)\n\tlinux-vdso.so.1 (0x00007ffc5eb93000)\n\t/lib/x86_64-linux-gnu/libnss_cache.so.2 (0x00007f8b68788000)\n\tlibruby-3.0.so.3.0 =\u003e /lib/x86_64-linux-gnu/libruby-3.0.so.3.0 (0x00007f8b683f3000)\n\tlibc.so.6 =\u003e /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b6821a000)\n\tlibz.so.1 =\u003e /lib/x86_64-linux-gnu/libz.so.1 (0x00007f8b681fd000)\n\tlibpthread.so.0 =\u003e /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8b681dc000)\n\tlibrt.so.1 =\u003e /lib/x86_64-linux-gnu/librt.so.1 (0x00007f8b681d0000)\n\tlibgmp.so.10 =\u003e /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f8b6814f000)\n\tlibdl.so.2 =\u003e /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8b68149000)\n\tlibcrypt.so.1 =\u003e /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f8b6810e000)\n\tlibm.so.6 =\u003e /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8b67fca000)\n\t/lib64/ld-linux-x86-64.so.2 (0x00007f8b68796000)\n```\n\nWe can run `ruby` using this _LD_AUDIT_ tool to capture all other dynamically needed libaries so that we can also\ninclude them in our key-value map, therefore, speeding up builds.\n\n```console\n❯ LD_AUDIT=./bazel-bin/src/main/libold.so ruby -e \"puts 'hi'\"\n.. prune for brevity ...\nhi\nI20220701 21:54:58.348860 1715429 main.cpp:18] Profiled the following libraries which were loaded\nstrategy = 'key_value'\n\n[key_value]\n'encdb.so' = '/usr/lib/x86_64-linux-gnu/ruby/3.0.0/enc/encdb.so'\n'ld-linux-x86-64.so.2' = '/lib64/ld-linux-x86-64.so.2'\n'libc.so.6' = '/lib/x86_64-linux-gnu/libc.so.6'\n'libcrypt.so.1' = '/lib/x86_64-linux-gnu/libcrypt.so.1'\n'libdl.so.2' = '/lib/x86_64-linux-gnu/libdl.so.2'\n'libgmp.so.10' = '/lib/x86_64-linux-gnu/libgmp.so.10'\n'libm.so.6' = '/lib/x86_64-linux-gnu/libm.so.6'\n'libnss_cache.so.2' = '/lib/x86_64-linux-gnu/libnss_cache.so.2'\n'libpthread.so.0' = '/lib/x86_64-linux-gnu/libpthread.so.0'\n'librt.so.1' = '/lib/x86_64-linux-gnu/librt.so.1'\n'libruby-3.0.so.3.0' = '/lib/x86_64-linux-gnu/libruby-3.0.so.3.0'\n'libz.so.1' = '/lib/x86_64-linux-gnu/libz.so.1'\n'monitor.so' = '/usr/lib/x86_64-linux-gnu/ruby/3.0.0/monitor.so'\nstrict = false\n'transdb.so' = '/usr/lib/x86_64-linux-gnu/ruby/3.0.0/enc/trans/transdb.so'\n```\n\nWe now have a much more exhaustive list of libraries that were needed by the application which we can include.\nThe tool generously provides the required TOML file necessary for the configuration to use on subsequent runs.\n\n## Development\n\nThis repository uses [bazel](https://docs.bazel.build/) as the build system; some familiarity is required.\n\nOnce you have bazel installed, building the shared object is done as follows.\n```console\n$ bazel build src/main:libold.so\n```\n\nYou can then run the built binary with the example TOML file provided by setting the necessary environment variables.\n\n```console\n$ OLDAUDIT_CONFIG=./example.toml LD_AUDIT=./bazel-bin/src/main/libold.so ruby --help | head\n```\n\n### Nix\n\nYou can get all the needed dependencies via [Nix](https://nixos.org).\nYou can quickly just build the binary with Nix\n```console\n$ nix build .#old\n$ ls result/bin\nlibold.so\n```\n\nYou can also start up a Nix development shell and have all the dependencies provided.\n```console\n$ nix develop\nnix develop\nwarning: Git tree '/usr/local/google/home/fmzakari/code/github.com/fzakaria/old' is dirty\n$ which bazel\n/nix/store/hzmmgvs3hknwwaxansd984c8gjkwyjgv-bazel-3.7.2/bin/bazel\n$ which clang\n/nix/store/8jl4ks1m051dafvl7lcdmwjsl63k5xck-clang-wrapper-7.1.0/bin/clang\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzakaria%2Fold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffzakaria%2Fold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzakaria%2Fold/lists"}