"API" and "ABI" sound alike, but they break in different ways. An API change stops your code from compiling; an ABI change lets it compile and then crashes it, or stops a program you downloaded from starting at all. This guide explains both in the Linux context, shows how to inspect them on a real binary, and explains the error messages you will meet when an ABI does not match.
An API (application programming interface) is the source-code contract: the functions, types and headers you write code against. An ABI (application binary interface) is the machine-level contract that compiled code relies on: calling conventions, data sizes, the ELF file format, system call numbers and versioned library symbols. Keep the API stable and your users can recompile; keep the ABI stable and they don't need to. On Linux the kernel keeps its user-space ABI stable, glibc stays backward compatible through symbol versioning, and most "GLIBC not found" or "cannot open shared object file" errors are ABI mismatches.
1. What an API is
An API is the set of functions, data types and constants that one piece of software offers another, described at the source level. In C on Linux, it is what the header files declare:
- the C standard library and POSIX functions, such as
printf,open,readandfork; - library APIs, such as OpenSSL's or libcurl's functions;
- the system call interface, which user programs normally reach through glibc wrappers rather than directly.
An API tells a programmer what to call and what arguments to pass. It says nothing about which CPU register an argument travels in.
2. What an ABI is
An ABI is the contract between pieces of compiled code. Two binaries share an ABI when they agree on:
3. API and ABI side by side
| Question | API | ABI |
|---|---|---|
| Level | Source code | Compiled machine code |
| Defined by | Headers and documentation | Architecture, compiler, C library and linker conventions |
| A breaking change means | Code no longer compiles | Old binaries crash or refuse to load |
| Fix for the user | Change the code, recompile | Recompile, or install the matching library version |
| Example change | A function gains a parameter | A struct gains a field, changing its size |
An API change can keep the ABI intact (adding a new function), and an ABI change can keep the API intact (adding a field to a struct that callers allocate themselves). That second case is the dangerous one: the code still compiles, so nobody notices until an old binary misreads memory.
4. A worked example
Take the classic program:
#include <stdio.h>
int main(void) {
printf("Hello, Linux!\n");
return 0;
}printf and stdio.h are the API. Compile it and inspect the ABI facts the compiler recorded:
gcc hello.c -o hello
file hello # ELF 64-bit LSB pie executable, x86-64, dynamically linked
readelf -d hello | grep NEEDED # Shared library: [libc.so.6]
objdump -T hello | grep GLIBC # e.g. puts with version GLIBC_2.2.5
ldd hello # where each needed library is found on this systemTwo things stand out. The compiler replaced printf with puts, because the string has no format specifiers: the API you wrote is not always the symbol that ends up in the binary. And the symbol carries a version tag. The binary will run on any system whose glibc provides at least that version of every symbol it uses. Build it on a system with glibc 2.34 or newer and you will also see __libc_start_main tagged GLIBC_2.34, so even this hello-world will not start on an older system.
5. How Linux keeps ABIs stable
- The kernel's user-space ABI is stable. System call numbers and behaviour are not changed in ways that break existing programs, which is why a binary built years ago can still run on a current kernel.
- The kernel's internal API and ABI are not stable. Kernel modules must be rebuilt for each kernel version; tools such as DKMS automate this for drivers.
- glibc is backward compatible through symbol versioning. When a function's behaviour changes, glibc keeps the old version alongside the new one. Programs built against an older glibc run on newer systems, but not the other way round.
- Shared libraries signal ABI breaks with the soname.
libssl.so.3andlibssl.so.1.1are different ABIs; a program built for one cannot load the other. - C++ adds its own ABI questions: name mangling, the layout of standard library types, and exceptions. GCC's libstdc++ has used a newer ABI for
std::stringandstd::listsince GCC 5, while keeping the old one available.
6. ABI errors you will actually see
| Error | What it means | Usual fix |
|---|---|---|
| version GLIBC_2.xx not found | The binary was built on a newer system than the one running it | Build on the oldest system you support, or run a newer OS |
| error while loading shared libraries: libX.so.N | A library at that soname is not installed | Install the matching library version, or rebuild |
| Exec format error | The binary is for a different CPU architecture, such as arm64 on x86-64 | Download or build for the right architecture |
| Crash only after a library upgrade | The library changed its ABI without changing its soname | Rebuild against the new version; report it upstream |
| Module compiled against a different Node.js version | A native add-on was built for another Node.js ABI | Reinstall dependencies, or use add-ons built on Node-API |
Distributions built on musl libc, such as Alpine Linux, have a different C library ABI from glibc systems, so a glibc binary will not run there unchanged. Language ecosystems handle this with tagged builds: Python wheels are labelled manylinux (glibc) or musllinux, and Node.js native add-ons built on Node-API keep working across Node.js versions.
7. Good practice for developers
- Version your API with semantic versioning.A backward-incompatible change means a new major version.
- Bump the soname when the ABI breaks.Users of the old library keep working, because both can be installed side by side.
- Hide struct layouts behind opaque pointersin public C APIs, so you can add fields without an ABI break.
- Build release binaries on the oldest system you support, usually inside a container, so they don't depend on newer glibc symbols.
- Check ABI changes automatically.Tools such as libabigail's
abidiffcompare two builds of a library and report incompatible changes before release.
Linking everything statically avoids missing-library errors, but you then ship your own copy of every library, including their security bugs, and some glibc features still expect a matching system library. Containers are usually the cleaner way to control the whole user-space ABI.
8. Running this on Domain India
- Shared hosting (cPanel, DirectAdmin, Webuzo): jailed SSH access is available on every shared hosting plan. It is off by default; ask support to enable it for your account, and log in with an SSH key. You cannot install system libraries, and tools available inside the jailed shell vary; ask support. The cPanel and DirectAdmin servers run CloudLinux 8 (measured September 2026), so a binary built on a much newer distribution may fail with a GLIBC error; run
ldd --versionover SSH to see the glibc version before you upload one. PHP's process functions are disabled on cPanel, so PHP cannot launch uploaded programs; see PHP disabled functions on shared hosting. Enabling and accessing jailed SSH covers access. - App Platform: you control the whole user-space ABI through your Dockerfile's base image; Node.js apps are detected automatically and other languages deploy with a Dockerfile. See App Platform: getting started.
- VPS: a self-managed server with root access and no cPanel, where you choose the distribution, install libraries and build software yourself.
- 512 MB RAM per app
- 1 vCPU
- 5 GB NVMe SSD
- PostgreSQL Database
Frequently asked questions
What is the difference between an API and an ABI?
An API is the source-code contract: the functions, types and headers you write code against. An ABI is the binary contract: calling conventions, data sizes, the executable format and versioned symbols that compiled code depends on. An API break stops code compiling; an ABI break makes existing binaries fail.
What does "version GLIBC_2.xx not found" mean?
The program was compiled on a system with a newer glibc and uses a symbol version the running system does not have. Rebuild it on an older system or in a container that matches the target, or run it on a newer operating system.
Is the Linux kernel ABI stable?
The interface between the kernel and user programs, mainly system calls, is kept stable so old binaries keep running. The kernel's internal interfaces for modules are not stable, so modules must be rebuilt for each kernel version.
Can a binary built on Ubuntu run on another Linux distribution?
Often, if both use the same CPU architecture, the target's glibc is at least as new as the one it was built against, and the same shared library versions are installed. It will not run unchanged on musl-based distributions such as Alpine.
What is a soname?
The name a shared library advertises for its ABI, such as libssl.so.3. Programs record the soname they need, and a library changes its soname when it breaks its ABI, so old and new versions can be installed side by side.
Does static linking solve ABI problems?
It avoids missing shared libraries, but it bundles copies of every library, including their security bugs, and does not remove every dependency on the system. Building in a container that matches your target is usually a better fix.
Can I run my own compiled programs on Domain India shared hosting?
Jailed SSH is available on request on every shared plan, with key login, but you cannot install system libraries and the tools inside the jail vary, so ask support first. For full control of libraries, use the App Platform with a Dockerfile or a self-managed VPS.
Ready to run your own builds? Deploy with a Dockerfile on the App Platform, take full control on a VPS, or open a support ticket to ask about jailed SSH on your shared hosting.
Deploy from a Dockerfile and choose your own base image, without managing a server.
See the App Platform