[llvm-dev] [RFC] CFI for indirect calls with ThinLTO

Evgenii Stepanov via llvm-dev llvm-dev at lists.llvm.org
Mon May 15 17:17:01 PDT 2017


Hi,

this is a proposal for the implementation of CFI-icall [1] with ThinLTO.

Jumptables are generated in the merged module. To generate a
jumptable, we need a list of functions with !type annotations,
including (in non-cross-dso mode) external functions. Unfortunately,
LLVM IR does not preserve unused function declarations, and we don’t
want to copy the actual function bodies to the merged module.

Indirect call targets can be represented in the following way using
named metadata:

void foo() {}
int bar() { return 0; }

# Merged module
!cfi.functions = !{!1, !3}
!1 = !{!"bar", i8 0, !2}
!2 = !{i64 0, !"_ZTSFiE"}
!3 = !{!"foo", i8 0, !4}
!4 = !{i64 0, !"_ZTSFvE"}

Each function is described by a tuple of
* Promoted name as a string
* Linkage (see below)
* Type(s)


A function can have multiple types. In the Cross-DSO mode each
function has a second “external” numeric type, and we might want to
allow “relaxed” type checking in the future where a function could
conform to multiple types. In that case the metadata would look like
this:

!4 = !{!"bar", i8 0, !5, !6}
!5 = !{i64 0, !"_ZTSFiE"}
!6 = !{i64 0, i64 751454132325070187}

“Linkage” is one of: definition, external declaration, external weak
declaration.

In the merged “merged” module, !cfi.functions may contain multiple
entries for each function. We pick one with the strongest linkage
(i.e. the definition, if it is available) in LowerTypeTests.

The LTO step emits, for a defined function named “f”:
declare void f.cfi()
.jumptable:
    …
    call f.cfi
    ...
f.cfi-jt = alias .jumptable + offset
f = alias f.cfi-jt

The same for an external (either weak or strong) declaration of a
function named “f”:
.jumptable:
    …
    call f
    ...
f.cfi-jt = alias .jumptable + offset

Weak external linkage is used in the lowering of uses of @f. This is
done both in the merged module and in ThinLTO backends. Uses of strong
definitions and declarations are replaced with f.cfi-jt. Uses of weak
external declarations a replaced with (f ? f.cfi-jt : 0) instead.

ThinLTO backends need to know which functions have jumptable entries
created for them (they will need to be RAUWed with f.cfi-jt). In the
Cross-DSO mode, external functions don’t get jumptable entries. This
information is passed back from the LTO step through combined summary.
The current idea is to add a new record, FunctionTypeResolution, which
would contain a set of function names in the jumptable.

== Alternatives

Function type information can be passed in the summary, as a list of
records (name, linkage, type(, type)*).
* Type can be either a string or a number. This complicates the encoding.
* The code in LowerTypeTests works with !type metadata in the same
format as described above. It would need to either recreate the
metadata from the summary, or deal with different input formats.
I don’t see any advantages to this encoding. Could it be more compact
than the metadata approach?

[1] https://clang.llvm.org/docs/ControlFlowIntegrity.html#indirect-function-call-checking


More information about the llvm-dev mailing list