Page MenuHomeFreeBSD

rtld: Support DT_RELR relative relocation format

Authored by on Oct 16 2021, 6:43 PM.



PIE and shared objects usually have many relative relocations. In
2017/2018, a compact relative relocation format RELR was proposed on
("Proposal for a new section type SHT_RELR") and is a pre-standard.
RELR usually takes 3% or smaller space than R_*_RELATIVE relocations.
The virtual memory size of a mostly statically linked PIE is typically 5~10% smaller.

ld.lld --pack-dyn-relocs=relr emits RELR relocations. DT_RELR has been
adopted by Android bionic, Linux kernel's arm64 port, Chrome OS (patched

This patch adds DT_RELR support to rtld-elf.

Author: Fangrui Song <>

Diff Detail

R10 FreeBSD src repository
Automatic diff as part of commit; lint not applicable.
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

RELR is like a modern version of Firefox’s ELF hack

About "pre-standard": Cary Coutant took over generic-abi maintenanceship ( "Ongoing Maintenance of the gABI") and plans to apply changes including RELR:

My testing on amd64:

# To build just libexec/rtld-elf
MAKEOBJDIRPREFIX=$PWD/obj/default make -j 12 buildenv
export CPUTYPE=  # zsh hack
make -C libexec/rtld-elf

cd /tmp/c
clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ -L/tmp/opt/lib -L$objdir/lib -Wl,-rpath=$objdir/lib/libc -fpic -shared b.c -o -Wl,-Bsymbolic -Wl,--pack-dyn-relocs=relr
clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ -L/tmp/opt/lib -L$objdir/lib -Wl,-rpath=$objdir/lib/libc -fpie -pie a.c ./ -o a -Wl,--pack-dyn-relocs=relr
// b.c
#include <stdio.h>

int vb;
int fb() {
  return vb++;
// a.c
#include <stdio.h>

int fb();
int main() {
  printf("%d\n", fb());
  printf("%d\n", fb());
  printf("%d\n", fb());
  printf("%d\n", fb());

Please use normal style(9) conventions for the new code. Most important, use tab for indent, not 4 spaces.


You are checking the lowest bit there, right? I believe & 1 is much more common way to do this.

Initially I was quite confused by the code, but apparently they changed encoding against the initial proposal. Also they made all entries 64bit, right?

IMO the documentation in the tangled thread on some list/google groups is not enough argument to start supporting this stuff. The last activity occured in 2018.


What does this 8 mean?

155 ↗(On Diff #96962)

If they changed relocation entry to be 64bit always, why this?

622 ↗(On Diff #96962)

Is this value used somehow?

kib removed a subscriber: emaste. marked 5 inline comments as done.

address comments


OK. I'll use this neovim script for my FreeBSD code:

:so ~/Dev/freebsd/tools/tools/editing/freebsd.vim
:call FreeBSD_Style()
:set ts=8 sw=4 sts=0 noet

Yes, the format changed. Ali Bahrami's comment (scroll to the bottom) is the format used by ld.lld, llvm-readelf -r, Android bionic, Linux kernel, and Chrome OS.

Someone may need to implement readelf -r for FreeBSD's readelf.


CHAR_BIT = 8. I just switched to CHAR_BIT for clarity.

A bitmap entry describes 63 locations on a 64-bit machine. where skips 63 locations.

155 ↗(On Diff #96962)

They use typedef Elf32_Word Elf32_Relr; for ELFCLASS32. ld.lld --pack-dyn-relocs=relr and llvm-readelf -r use 32-bit on ELFCLASS32 as well (llvm-project llvm/include/llvm/BinaryFormat/ELF.h)

622 ↗(On Diff #96962)

I just added an assert for DT_RELRENT.

ld.lld's RELR is robust since 2019-04 ( when I fixed an oscillation bug.

Better test:

% cat relr.c
static int o, x;

#define ELEMS O O O O O O O O X X X X X X X O O X O O X X X E X E E O X O E
#define E 0,

#define O &o,
#define X &x,
void *arr[] = { ELEMS };
#undef O
#undef X

#define O 1,
#define X 2,
static char val[] = { ELEMS };

int main()
  for (int i = 0; i < sizeof (arr) / sizeof (arr[0]); i++)
    if (!((arr[i] == 0 && val[i] == 0) ||
          (arr[i] == &o && val[i] == 1) ||
          (arr[i] == &x && val[i] == 2)))
      return 1;
  return 0;

% cat /tmp/opt/lib/ 
/* $FreeBSD: releng/12.2/lib/libc/libc.ldscript 258283 2013-11-17 22:52:17Z peter $ */
GROUP ( libc/ libc_nonshared/libc_nonshared.a libssp_nonshared/libssp_nonshared.a )
% clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ -L/tmp/opt/lib -L$objdir/lib -Wl,-rpath=$objdir/lib/libc -fpie -pie relr.c -o relr -Wl,--pack-dyn-relocs=relr
% ./relr  # good

# Without DT_RELR support, segfault:
% clang -fpie -pie relr.c -o relr -Wl,--pack-dyn-relocs=relr
% ./relr
[1]    45961 segmentation fault (core dumped)  ./relr

Please split the patch into two: one for sys/ adding the needed definitions, and one for rtld. Then send me complete git patches with all metadata and tags filled.


There should be a blank line after the local declaration.


If you use local inside block, why not move its declaration into for loop init clause?


!= 0 marked 2 inline comments as done.

address style issues

rebase on D32526

This revision was not accepted when it landed; it landed in state Needs Review.Oct 16 2021, 11:39 PM
This revision was automatically updated to reflect the committed changes.
arichardson added inline comments.

For most code git-clang-format should be almost correct. However rtld still uses different indentation for some functions...


Or we just switch to MK_LLVM_BINUTILS by default :)


Or both - even when MK_LLVM_BINUTILS lands we presumably will not MFC it, but people may well run readelf from older FreeBSD branches to inspect objects built with RELR. tell the Linux folks that they don't want to be too far behind FreeBSD :)