Most architectures encode branch/call instructions with a PC-relativedisplacement. Some architectures use two ELF relocation types for a callinstruction:
# sparc call foo, 0 # not PIC: R_SPARC_WDISP30 call foo, 0 # gas -KPIC: R_SPARC_WPLT30
This post describes why I think this happened.
Static linking: one typesuffices
In the static linking model, all symbols are resolved at link time:every symbol is either defined in a relocatable object file or anundefined weak symbol. A branch instruction with a PC-relativedisplacement—x86 call, m68k bsr.l, s390brasl—can reuse the same PC-relative data relocation typeused for data references.
i386: R_386_PC32 for both call foo and.long foo - .
x86-64: R_X86_64_PC32 for both call fooand .long foo - .
m68k: R_68K_PC32 for bsr.l foo,move.l var,%d0, and .long foo - .
s390x: R_390_PC32DBL for brasl %r14, foo,larl %r1, var, and .long foo - .
No separate "call" relocation type is needed. The linker simplypatches the displacement to point to the symbol address.
Dynamic linking changes thepicture
With System V Release 4 style shared libraries, variable access andfunction calls diverge.
For variables and function addresses, a referencefrom one component to a symbol defined in another cannot use a plainPC-relative relocation, because the distance between the two componentsis not known at link time. The Global OffsetTable was introduced for this purpose, along with GOT-generatingrelocation types. (Additionally, copyrelocations are a workaround for external data symbols from-fno-pic relocatable files.)
For function calls, the situation is different. Acall instruction has "transfer control there by any means" semantics -the caller usually doesn't care how the callee is reached, onlythat it gets there. This allows the linker to interpose a PLT stubwhen the target is in another component, without any special codesequence at the call site.
Variable accesses do not have the same semantics - so the PC-relativedata relocation type cannot be reused on a call instruction.
This is why separate branch relocation types were introduced:R_386_PLT32, R_68K_PLT32,R_390_PLT32DBL, and so on. The relocation type carries thesemantic information: "this is a function call that can use PLTindirection."
Misleading names
The @plt notation in assembly and the PLT32relocation type names are misleading. They suggest that a PLT entry isinvolved, but that is often not the case - when the callee is defined inthe same component, the linker resolves the branch directly—no PLT entryis created.
R_386_CALL32 and R_X86_64_CALL32 would havebeen a better name.
In addition, the @plt notation itself is problematic asa relocationspecifier.
Architecture comparison
Single type (clean design). Some architecturesrecognized from the start that one call relocation type is sufficient.The linker can decide whether a PLT stub is needed based on the symbol'sbinding and visibility.
AArch64: R_AARCH64_CALL26 for both bl andb.
PowerPC64 ELFv2: R_PPC64_REL24 forbl.
These architectures never had the naming confusion—there is no "PLT"in the relocation name, and no redundant pair.
Redundant pairs (misguided). Some architecturesintroduced separate "PLT" and "non-PLT" call relocation types, creatinga distinction without a real difference.
SPARC: R_SPARC_WPLT30 alongsideR_SPARC_WDISP30. The assembler decides at assembly timebased on PIC mode and symbol preemptivity, when ideally the linkershould make these decisions.
PPC32: R_PPC_REL24 (non-PIC) andR_PPC_PLTREL24 (PIC) have genuinely different semantics(the addend of R_PPC_PLTREL24 encodes the r30 GOT pointersetup). However, R_PPC_LOCAL24PC is entirely useless—alloccurrences can be replaced with R_PPC_REL24.
RISC-V: R_RISCV_CALL_PLT alongside the now-removedR_RISCV_CALL. The community recognized that only onerelocation is needed. R_RISCV_CALL_PLT is kept (despite thename, does not mandate a PLT entry).
x86-64 started with R_X86_64_PC32 forcall foo (inherited from the static-linking mindset) andR_X86_64_PLT32 for call foo@plt (symbols notcompile-time known to be non-preemptible). In 2018, binutils https://sourceware.org/bugzilla/show_bug.cgi?id=22791switched to R_X86_64_PLT32 for call foo. LLVMintegrated assembler followed suit.
This means R_X86_64_PC32 is now effectively reserved fordata references, and R_X86_64_PLT32 marks all calls—a cleanseparation achieved by convention.
However, GNU Assembler still produces R_X86_64_PC32 whencall foo references an STB_LOCAL symbol. I'vesent a patch to fix this: [PATCHv2] x86: keep PLT32 relocation for local symbols instead of convertingto PC32.
GCC's s390 port seems to always generate @plt (even forhidden visibility functions), leading to R_390_PLT32DBLrelocations.
Range extension thunks
A dedicated call relocation type also enables rangeextension thunks: when the target is out of the branch instruction'srange, the linker can insert a thunk without the compiler or assemblerneeding to know. This works precisely because the relocation marks thesite as a branch—the linker knows it can redirect through a thunk.
On AArch64 and PowerPC64, this is well established. On x86-64, the±2GiB range of call/jmp has been sufficient sofar, but as executables grow, relocationoverflow becomes a concern. There are proposals to add rangeextension thunks to x86-64, which would rely on the linker being able toidentify call sites—another reason to consistently useR_X86_64_PLT32 rather than R_X86_64_PC32 forcalls.
Recommendation forfuture architectures
Use a single call relocation type—no "PLT" vs. "non-PLT" distinction.The assembler should emit the same relocation for every callinstruction, and the linker, which knows whether the symbol ispreemptible, decides whether a PLT stub or range extension thunk isneeded. AArch64's R_AARCH64_CALL26 and PowerPC64 ELFv2'sR_PPC64_REL24 demonstrate this approach well.
A Linux distribution (or “distro”) is an operating system built on the Linux kernel, combined with GNU tools, libraries, and software packages. Each distro includes a desktop environment, package manager, and preinstalled applications tailored to specific use cases.
With hundreds of Linux distributions available, choosing the right one can be overwhelming. This guide covers the best Linux distributions for different types of users, from complete beginners to security professionals.
Ubuntu is the most popular Linux distribution and an excellent starting point for newcomers. Developed by Canonical, it offers a polished desktop experience with the GNOME environment and extensive hardware support.
Ubuntu comes in several editions:
Ubuntu Desktop — Standard desktop with GNOME
Ubuntu Server — For server deployments
Kubuntu, Lubuntu, Xubuntu — Alternative desktop environments
Ubuntu releases new versions every six months, with Long Term Support (LTS) versions every two years receiving five years of security updates.
Linux Mint is an excellent choice for users coming from Windows. Its Cinnamon desktop environment provides a familiar layout with a taskbar, start menu, and system tray.
Developed by System76, Pop!_OS is based on Ubuntu but optimized for productivity and gaming. It ships with the COSMIC desktop environment (built in Rust by System76), featuring built-in window tiling, a launcher for quick app access, and excellent NVIDIA driver support out of the box.
Zorin OS is a beginner-focused distribution designed to make the move from Windows or macOS easier. It includes polished desktop layouts, strong hardware compatibility, and a simple settings experience for new users.
Zorin OS is a strong option when you want:
A familiar desktop layout with minimal setup
Stable Ubuntu-based package compatibility
Good out-of-the-box support for everyday desktop tasks
elementary OS is a design-focused distribution with a macOS-like interface called Pantheon. It emphasizes simplicity, consistency, and a curated app experience through its AppCenter.
Xubuntu combines Ubuntu’s reliability with the Xfce desktop environment, offering a good balance between performance and features. It is lighter than standard Ubuntu while remaining full-featured for daily desktop use.
Lubuntu uses the LXQt desktop environment, making it one of the lightest Ubuntu-based distributions available. It is designed for very old or resource-constrained hardware where even Xfce feels heavy.
Arch Linux follows a “do-it-yourself” philosophy, providing a minimal base system that users build according to their needs. It uses a rolling release model, meaning you always have the latest software without major version upgrades.
Key features:
Pacman package manager with access to vast repositories
EndeavourOS is an Arch-based distribution that keeps the Arch philosophy while simplifying installation and initial setup. It is popular among users who want a near-Arch experience without doing a fully manual install.
EndeavourOS gives you:
Rolling release updates
Access to Arch repositories and AUR packages
A cleaner onboarding path than a base Arch install
Fedora is a cutting-edge distribution sponsored by Red Hat. It showcases the latest open-source technologies while maintaining stability, making it popular among developers and system administrators.
Fedora editions include:
Fedora Workstation — Desktop with GNOME
Fedora Server — For server deployments
Fedora Silverblue — Immutable desktop OS
Fedora Spins — Alternative desktops (KDE, Xfce, etc.)
Many Red Hat technologies debut in Fedora before reaching RHEL, making it ideal for learning enterprise Linux.
openSUSE is a community-driven distribution known for its stability and powerful administration tools. It offers two main variants:
openSUSE Leap — Regular releases based on SUSE Linux Enterprise
openSUSE Tumbleweed — Rolling release with the latest packages
The YaST (Yet another Setup Tool) configuration utility makes system administration straightforward, handling everything from software installation to network configuration.
Bazzite is an immutable Fedora-based desktop optimized for gaming and handheld devices. It ships with gaming-focused defaults and integrates well with Steam, Proton, and modern GPU drivers.
Bazzite is ideal when you want:
A Steam-first gaming setup
Reliable rollback and update behavior from an immutable base
A distro tuned for gaming PCs and handheld hardware
Debian is one of the oldest and most influential Linux distributions. Known for its rock-solid stability and rigorous testing process, it serves as the foundation for Ubuntu, Linux Mint, Kali Linux, and many other distributions.
Debian offers three release channels:
Stable — Thoroughly tested, ideal for production servers
Testing — Upcoming stable release with newer packages
Unstable (Sid) — Rolling release with the latest software
With over 59,000 packages in its repositories, Debian supports more hardware architectures than any other Linux distribution.
After CentOS shifted to CentOS Stream, Rocky Linux emerged as a community-driven RHEL-compatible distribution. Founded by one of the original CentOS creators, it provides 1:1 binary compatibility with RHEL.
Rocky Linux is ideal for:
Organizations previously using CentOS
Production servers requiring stability
Anyone needing RHEL compatibility without the cost
Ubuntu Server is widely used for cloud deployments and containerized workloads. It powers a significant portion of public cloud instances on AWS, Google Cloud, and Azure.
Kali Linux is the industry-standard platform for penetration testing and security research. Maintained by Offensive Security, it includes hundreds of security tools preinstalled.
Common use cases:
Penetration testing
Security auditing
Digital forensics
Reverse engineering
Warning
Kali Linux is designed for security professionals. It should not be used as a daily driver operating system.
Tails (The Amnesic Incognito Live System) is a portable operating system designed for privacy and anonymity. It runs from a USB drive and routes all traffic through the Tor network.
Key features:
Leaves no trace on the host computer
All connections go through Tor
Built-in encryption tools
Amnesic by design (forgets everything on shutdown)
Qubes OS takes a unique approach to security by isolating different activities in separate virtual machines called “qubes.” If one qube is compromised, others remain protected.
The Xen hypervisor runs directly on hardware, providing strong isolation between:
Parrot Security is a Debian-based distribution for security testing, development, and privacy. It is lighter than Kali Linux and can serve as a daily driver.
Which Linux distro is best for beginners?
Ubuntu, Linux Mint, and Zorin OS are the best choices for beginners. Ubuntu has the largest community and most documentation, while Linux Mint and Zorin OS provide a familiar desktop experience.
Can I try a Linux distro without installing it?
Yes. Most distributions support “live booting” from a USB drive, allowing you to test the system without making any changes to your computer.
Is Linux free?
Most Linux distributions are completely free to download and use. Some enterprise distros like RHEL offer paid support subscriptions.
Can I run Windows software on Linux?
Many Windows applications run on Linux through Wine or Proton (for games via Steam). Native alternatives like LibreOffice, GIMP, and Firefox are also available.
What is a rolling release distro?
A rolling release distro (like Arch Linux or openSUSE Tumbleweed) delivers continuous updates instead of major version upgrades. You always have the latest software, but updates require more attention.
The best Linux distribution depends entirely on your needs and experience level. If you are new to Linux, start with Ubuntu, Linux Mint, or Zorin OS. If you want full control over your system, try Arch Linux, EndeavourOS, or Fedora. For gaming, Pop!_OS and Bazzite are strong options. For servers, Debian, Rocky Linux, Ubuntu Server, and RHEL are all solid choices. For security testing, Kali Linux and Parrot Security are the industry standards.
Most distributions are free to download and try. Create a bootable USB, test a few options, and find the one that fits your workflow.
If you have any questions, feel free to leave a comment below.