Page MenuHomeFreeBSD

rtld: Support DT_RELR relative relocation format
ClosedPublic

Authored by fbsd-phab_maskray.me on Oct 16 2021, 6:43 PM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Mar 25, 12:44 PM
Unknown Object (File)
Tue, Mar 19, 2:40 PM
Unknown Object (File)
Mon, Mar 18, 4:22 PM
Unknown Object (File)
Mon, Mar 18, 11:53 AM
Unknown Object (File)
Sun, Mar 17, 11:19 PM
Unknown Object (File)
Tue, Mar 5, 7:39 PM
Unknown Object (File)
Sat, Mar 2, 8:40 PM
Unknown Object (File)
Wed, Feb 28, 8:14 AM

Details

Summary

PIE and shared objects usually have many relative relocations. In
2017/2018, a compact relative relocation format RELR was proposed on
https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/GxjM0L-PBAAJ
("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
glibc).

This patch adds DT_RELR support to rtld-elf.

Author: Fangrui Song <i@maskray.me>

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 42171
Build 39059: arc lint + arc unit

Event Timeline

RELR is like a modern version of Firefox’s ELF hack https://glandium.org/blog/?p=1177#relocations


About "pre-standard": Cary Coutant took over generic-abi maintenanceship (https://groups.google.com/g/generic-abi/c/9OO5vhxb00Y "Ongoing Maintenance of the gABI") and plans to apply changes including RELR: https://sourceware.org/pipermail/libc-alpha/2021-October/131781.html

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
objdir=$HOME/freebsd/obj/default/usr/home/ray/freebsd/amd64.amd64
clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ld-elf.so.1.full -L/tmp/opt/lib -L$objdir/lib -Wl,-rpath=$objdir/lib/libc -fpic -shared b.c -o b.so -Wl,-Bsymbolic -Wl,--pack-dyn-relocs=relr
clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ld-elf.so.1.full -L/tmp/opt/lib -L$objdir/lib -Wl,-rpath=$objdir/lib/libc -fpie -pie a.c ./b.so -o a -Wl,--pack-dyn-relocs=relr
./a
// 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());
}
libexec/rtld-elf/rtld.c
3163

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

3169

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.

3177

What does this 8 mean?

sys/sys/elf32.h
155

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

sys/sys/elf_common.h
622

Is this value used somehow?

kib removed a subscriber: emaste.
fbsd-phab_maskray.me marked 5 inline comments as done.

address comments

libexec/rtld-elf/rtld.c
3163

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
3169

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.

3177

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.

sys/sys/elf32.h
155

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)

sys/sys/elf_common.h
622

I just added an assert for DT_RELRENT.

ld.lld's RELR is robust since 2019-04 (https://reviews.llvm.org/D67164) 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/libc.so 
/* $FreeBSD: releng/12.2/lib/libc/libc.ldscript 258283 2013-11-17 22:52:17Z peter $ */
GROUP ( libc/libc.so.7 libc_nonshared/libc_nonshared.a libssp_nonshared/libssp_nonshared.a )
% clang -Wl,--dynamic-linker=$objdir/libexec/rtld-elf/ld-elf.so.1.full -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.

libexec/rtld-elf/rtld.c
3168

There should be a blank line after the local declaration.

3174

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

3175

!= 0

fbsd-phab_maskray.me 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.
libexec/rtld-elf/rtld.c
3163

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

3169

Or we just switch to MK_LLVM_BINUTILS by default :)

libexec/rtld-elf/rtld.c
3169

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.

@fbsd-phab_maskray.me tell the Linux folks that they don't want to be too far behind FreeBSD :)