[llvm-branch-commits] [lld] ELF: CFI jump table relaxation. (PR #147424)

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat May 2 18:01:29 PDT 2026


MaskRay wrote:

Script that demonstrates the end-to-end behavior difference
```sh
cat > cfi.cc <<'eof'
// CFI icall example -- function pointer indirect calls trigger jump tables.
extern "C" {
// Tiny: ret-only body, fits in 8 bytes.
int tiny1(int) { return 1; }
int tiny2(int) { return 2; }

// Big: too large to inline into a single 8-byte slot.
int big(int x) {
  int s = 0;
  for (int i = 0; i < 7; ++i) s += i * x;
  return s;
}

// Force the address of each function to be taken so a jump table is built.
typedef int (*FP)(int);
__attribute__((noinline))
int call(FP fp, int x) { return fp(x); }
}

int main() {
  FP v[3] = { &tiny1, &tiny2, &big };
  int s = 0;
  for (auto fp : v) s += call(fp, 3);
  return s;
}
eof

T=/tmp/Rel/bin
CLANG=$T/clang

"$CLANG" -O2 -flto -fvisibility=hidden -fsanitize=cfi-icall \
         -fuse-ld=lld -B"$T" cfi.cc -o cfi -Wl,--lto-emit-asm,--save-temps
sed -i '/\.prefalign/d' cfi.lto.s

cp cfi.lto.s cfi.progbits.s
sed 's|\.text\.\.L\.cfi\.jumptable,"ax", at progbits|.text..L.cfi.jumptable,"ax", at llvm_cfi_jump_table,8|' \
    cfi.lto.s > cfi.relax.s

for v in progbits relax; do
    "$T"/llvm-mc -filetype=obj -triple=x86_64 cfi.$v.s -o cfi.$v.o
    "$CLANG" -fuse-ld=lld -B"$T" cfi.$v.o -o cfi.$v
done

set +e
./cfi.progbits; echo "cfi.progbits exit=$?"
./cfi.relax;    echo "cfi.relax    exit=$?"
set -e

SYMS=tiny1.cfi,tiny2.cfi,big.cfi,tiny1,tiny2,big
for v in progbits relax; do
    printf '\n===== cfi.%s =====\n' "$v"
    "$T"/llvm-objdump -d --show-all-symbols --no-show-raw-insn \
        --disassemble-symbols=$SYMS cfi.$v
done

printf '\n===== .text size =====\n'
"$T"/llvm-readelf -SW cfi.progbits cfi.relax | \
    awk '/^File:/{f=$2} /\.text +PROGBITS/{print f, $6}'
```

https://github.com/llvm/llvm-project/pull/147424


More information about the llvm-branch-commits mailing list