Detect trailing unmarked code after CFI-bounded predecessors (__BOLT_FDE_FUNC* or symbols whose FDE address range equals their size) and promote it into separate BinaryFunction objects named __BOLT_UNMARKED_TAILat<addr>. A predecessor is only considered when: - the target is AArch64 - it is not a pseudo or fragment function - it has slack beyond its recorded size (MaxSize > Size) - it is CFI-bounded - no function is already registered at the tail start address The trailing region is measured conservatively and we bail out (leaving the slack attached to the predecessor) when: - the tail range is not fully contained in the predecessor's origin section - a data marker ($d) or a constant island overlaps the region (data-in-code) - disassembly fails or yields a zero-length instruction - after trimming trailing padding, the tail is empty (i.e. it contained only padding) or does not end in a return - any bytes past the decoded code are non-zero, i.e. not pure zero padding. The bug was introduced in commit [cd27741](cd27741c11)
111 lines
3 KiB
ArmAsm
111 lines
3 KiB
ArmAsm
## Promote unmarked code after a CFI-bounded predecessor into __BOLT_UNMARKED_TAIL.
|
|
## Covers:
|
|
## 1) FDE-only region (no symtab entry; BOLT names it __BOLT_FDE_FUNC* or .text/N)
|
|
## 2) Named function (FDE range == symbol size) -> named_sub + tail
|
|
## Caller is in a separate section; -Wl,-q keeps PC-relative relocs on the bl.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
|
|
# RUN: %clang %cflags %t.o -pie -Wl,-q -o %t.exe
|
|
# RUN: llvm-bolt %t.exe -o %t.bolt --print-disasm -v=1 2>&1 | FileCheck %s
|
|
|
|
# CHECK-COUNT-3: BOLT-WARNING: detected executable code after CFI-bounded function
|
|
# CHECK-SAME: creating synthetic function __BOLT_UNMARKED_TAILat
|
|
# CHECK-SAME: Consider adding a symbol or FDE for this code.
|
|
|
|
## Scenario 1a: FDE-only predecessor at the section start (named after .text).
|
|
## The tail has trailing filler nops after its ret: they are trimmed from the
|
|
## callable Size but remain part of MaxSize slack.
|
|
# CHECK: Binary Function ".text/{{[0-9]+}}" after disassembly
|
|
# CHECK: Size : 0x14
|
|
# CHECK: MaxSize : 0x14
|
|
# CHECK: Binary Function "{{.*}}__BOLT_UNMARKED_TAIL{{.*}}" after disassembly
|
|
# CHECK: Size : 0x8
|
|
# CHECK: MaxSize : 0x10
|
|
|
|
## Scenario 1b: FDE-only predecessor discovered from the FDE alone.
|
|
# CHECK: Binary Function "__BOLT_FDE_FUNC{{.*}}" after disassembly
|
|
# CHECK: Size : 0x14
|
|
# CHECK: MaxSize : 0x14
|
|
# CHECK: Binary Function "{{.*}}__BOLT_UNMARKED_TAIL{{.*}}" after disassembly
|
|
# CHECK: Size : 0x8
|
|
# CHECK: MaxSize : 0x8
|
|
|
|
## Scenario 2: named predecessor (FDE address range matches .size).
|
|
# CHECK: Binary Function "named_sub" after disassembly
|
|
# CHECK: Size : 0x14
|
|
# CHECK: MaxSize : 0x14
|
|
# CHECK: Binary Function "{{.*}}__BOLT_UNMARKED_TAIL{{.*}}" after disassembly
|
|
# CHECK: Size : 0x10
|
|
# CHECK: MaxSize : 0x10
|
|
|
|
# CHECK-COUNT-3: bl __BOLT_UNMARKED_TAILat{{.*}}
|
|
|
|
.section .text.fdeonly,"ax",@progbits
|
|
|
|
## Scenario 1a: FDE-only predecessor at the section start (no symbol table entry).
|
|
.Lfde_sub:
|
|
.cfi_startproc
|
|
stp x29, x30, [sp, #-16]!
|
|
mov x29, sp
|
|
mov w0, #42
|
|
ldp x29, x30, [sp], #16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
.Ltail_after_fde:
|
|
nop
|
|
ret
|
|
nop
|
|
nop
|
|
|
|
## Scenario 1b: identical FDE-only region, not at the section start.
|
|
.Lfde_sub2:
|
|
.cfi_startproc
|
|
stp x29, x30, [sp, #-16]!
|
|
mov x29, sp
|
|
mov w0, #42
|
|
ldp x29, x30, [sp], #16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
.Ltail_after_fde2:
|
|
nop
|
|
ret
|
|
|
|
.section .text.named,"ax",@progbits
|
|
|
|
## Scenario 2: named predecessor (FDE address range matches .size).
|
|
.globl named_sub
|
|
.type named_sub, %function
|
|
named_sub:
|
|
.cfi_startproc
|
|
stp x29, x30, [sp, #-16]!
|
|
mov x29, sp
|
|
mov w0, #7
|
|
ldp x29, x30, [sp], #16
|
|
ret
|
|
.cfi_endproc
|
|
.size named_sub, .-named_sub
|
|
|
|
.Ltail_after_named:
|
|
mov x0, x0
|
|
mov w1, #7
|
|
add w0, w0, w1
|
|
ret
|
|
|
|
.section .text.entry,"ax",@progbits
|
|
|
|
.globl _start
|
|
.type _start, %function
|
|
_start:
|
|
.cfi_startproc
|
|
stp x29, x30, [sp, #-16]!
|
|
mov x29, sp
|
|
bl .Ltail_after_fde
|
|
bl .Ltail_after_fde2
|
|
bl .Ltail_after_named
|
|
ldp x29, x30, [sp], #16
|
|
mov w0, #0
|
|
ret
|
|
.cfi_endproc
|
|
.size _start, .-_start
|