{"id":29550113,"url":"https://github.com/graphitemaster/detour","last_synced_at":"2026-01-18T21:02:44.057Z","repository":{"id":304511732,"uuid":"1019001326","full_name":"graphitemaster/detour","owner":"graphitemaster","description":"A detour through the Linux dynamic linker","archived":false,"fork":false,"pushed_at":"2025-07-13T14:24:52.000Z","size":13,"stargazers_count":217,"open_issues_count":1,"forks_count":7,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-10-10T13:46:57.636Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/graphitemaster.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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,"zenodo":null}},"created_at":"2025-07-13T14:22:28.000Z","updated_at":"2025-10-08T02:41:34.000Z","dependencies_parsed_at":"2025-07-13T16:23:03.590Z","dependency_job_id":"de2a37f1-b37a-4c64-9077-ffc3009ce3ec","html_url":"https://github.com/graphitemaster/detour","commit_stats":null,"previous_names":["graphitemaster/detour"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/graphitemaster/detour","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2Fdetour","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2Fdetour/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2Fdetour/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2Fdetour/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphitemaster","download_url":"https://codeload.github.com/graphitemaster/detour/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2Fdetour/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28550497,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T20:59:07.572Z","status":"ssl_error","status_checked_at":"2026-01-18T20:59:02.799Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2025-07-18T01:02:23.998Z","updated_at":"2026-01-18T21:02:44.051Z","avatar_url":"https://github.com/graphitemaster.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# Detour\n\nOn Linux, the traditional divide between statically and dynamically linked executables can feel like a hard wall. Either you bundle *everything* into your binary, or you accept full dependency on the system's libc and dynamic linker. But Detour, a tiny static library, blows a hole clean through that wall.\n\nDetour lets you build statically linked executables, with no dependency on glibc\nor musl while still giving you access to dynamic linking at runtime. You can\n`dlopen` libraries, resolve symbols, and even mix multiple C runtimes in the\nsame process, all without ever linking against libc directly.\n\n## What Is Detour?\n\nAt its core, Detour is a minimal bootstrap layer that gives your application access to the system dynamic linker `ld-linux.so` without requiring libc at all. It allows:\n\n- Dynamically loading libraries without linking libc\n- Capturing `libdl` functionality (e.g., `dlopen`, `dlsym`) inside a fully static executable\n- Mixing different libcs in one process\n- Creating freestanding, zero-libc ELF executables\n\nAll while remaining entirely under your control, with no extra dependencies or runtime overhead.\n\n\u003e **Note:** Detour is not limited to freestanding or static use. You can also use it in dynamically linked applications that use an alternative libc such as musl. Detour works in both static and dynamic contexts.\n\n\u003e **Note:** Detour only works with **x86_64** Linux currently. Other architectures can be supported but will require writing assembly for system calls, setjmp/longjmp, and the indirect jump into the ELF entry point. See [loader.c](loader.c).\n\n## Why Static Linking Alone Is Not Enough\n\nWhile fully static linking may sound appealing, it comes with major tradeoffs. When you bundle everything into your binary, you lose access to essential system components that rely on dynamic linking. This includes things like:\n\n- GPU drivers (e.g., OpenGL, Vulkan ICDs)\n- Window systems (X11, Wayland)\n- Audio subsystems\n- Input libraries\n- PAM modules and NSS services\n- Almost any plugin-based runtime\n\nThese components expect a working dynamic linker environment. If you statically link a libc, you cannot also have a dynamic linker in the same process. That means `dlopen` and `dlsym` will not work, and neither will anything that depends on them.\n\nDetour solves this by letting you statically link your core application while still setting up a dynamic linker for runtime use.\n\n## How It Works\n\nTo understand Detour, it helps to understand how dynamic executables work under the hood on Linux.\n\nWhen you run a dynamically linked [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) binary, the kernel does not actually execute your binary. Instead, it reads the [ELF Program Header Table](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#Program_header) to find a segment of type `PT_INTERP`. This segment specifies the program interpreter to use, typically `/lib64/ld-linux-x86-64.so.2`. The kernel then executes *that* interpreter, passing it:\n\n1. The full path to your executable\n2. All command-line arguments\n3. Environment variables\n4. Auxiliary vectors\n\nFrom there, the dynamic linker takes over. It maps your executable into memory,\nresolves shared library dependencies, performs relocations, sets up [TLS](https://en.wikipedia.org/wiki/Thread-local_storage), runs\nconstructors, and finally jumps to libc's initialization which then jumps to\nyour binary's `main` function. In effect, the dynamic\nlinker is the real program, and your application is just a payload it sets up\nand transfers control to after initializing everything.\n\n**Detour leverages this system by pretending to be the OS.**\n\nIt works like this:\n\n1. We provide a tiny stub ELF executable that *is* dynamically linked against the system dynamic linker.\n2. Your actual program (which Detour bootstraps) loads this stub ELF using a minimal ELF loader.\n3. Detour reads the stub executable's `PT_INTERP` segment and loads the specified dynamic linker, just like the kernel would.\n4. Before jumping into the dynamic linker, Detour calls [`setjmp`](https://en.wikipedia.org/wiki/Setjmp.h) to capture its current state.\n5. It then jumps into the dynamic linker, forwarding the stub ELF and original arguments as if it were the kernel.\n6. The dynamic linker maps in and initializes the stub ELF, then calls its `main` function. That `main` receives a string argument containing a function pointer encoded as a hex string. It decodes the address, casts it to a function pointer, and calls it.\n7. This function captures symbols like `dlopen`, `dlsym`, `dlclose`, `dlerror`, and then calls `longjmp` to return to the original application.\n8. Now, back at your main program's entry point, you have full access to the dynamic linker without ever linking against libc.\n\nIt is a trampoline: a short, carefully orchestrated detour through the dynamic linker, giving you just enough of its guts to carry on without ever depending on it directly.\n\n## About the Tiny Stub\n\nThe helper ELF stub used in the first step is extremely small. It's about 35\nlines of C. It is dynamically linked, but uses `__asm__(\".symver\")` to\nexplicitly pin any symbols it calls to the earliest possible version of glibc\nthat introduced the dynamic linker (around 2002). This ensures maximum forward\ncompatibility with any glibc-based Linux system in the wild today. Don't believe\nme? [Look at the code](linker.c)\n\nYou can ship this stub alongside your application, compile it at runtime on the\nuser's system, or even embed it directly into your binary and extract it to a\ntemporary file at startup. Its only job is to get the dynamic linker to call a\nknown function pointer. Nothing more.\n\n## Included Demo\n\nIncluded is a demo that uses Detour to render a flashing colored window using SDL2 and OpenGL. The demo is a fully freestanding static executable that dynamically loads the system's `libc`, `libm`, `libSDL2`, and `libGL` at runtime.\n\nIt is compiled with:\n\n```sh\n-static -nostartfiles -nodefaultlibs -nostdlib -e detour_start\n```\n\n\u003e **Note:** When using Detour in a freestanding way (such as this demo), the ELF entry point must be `detour_start`.\n\nDespite being entirely statically linked, the executable dynamically loads\neverything it needs at runtime. This includes: graphics drivers, windowing system libraries,\nand more without ever linking against glibc or any dynamic libraries at build\ntime. Provided the system has a `libSDL2.so` this will work on any Linux install\nfrom 2002 onwards!\n\n## Why Use It?\n\n- Create libc-free executables that still load plugins or shared libraries\n- Avoid [dependency hell](https://en.wikipedia.org/wiki/Dependency_hell) when shipping portable tools across Linux distributions\n- Experiment with new runtimes that bootstrap their own environment\n- Mix musl and glibc in the same process for advanced compatibility or sandboxing\n- Access graphics drivers, window systems, and hardware-accelerated APIs without linking glibc\n- Maintain compatibility with system components that require a functioning `PT_INTERP` chain\n\n## Final Thoughts\n\nDetour does not hide how Linux works, it uses how Linux works. By repurposing the exact same mechanism the OS uses to launch dynamic binaries, it gives static executables a back door into the dynamic linker.\n\nWhether you are building minimal tooling, crafting portable binaries, or writing\nyour own runtime, Detour gives you surgical control over how and when the\ndynamic linker shows up.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphitemaster%2Fdetour","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphitemaster%2Fdetour","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphitemaster%2Fdetour/lists"}