<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Thanks for sending this out. A few comments below.</div><div class="gmail_quote"><br></div><div class="gmail_quote">On Mon, May 15, 2017 at 5:17 PM, Evgenii Stepanov via llvm-dev <span dir="ltr"><<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi,<br>
<br>
this is a proposal for the implementation of CFI-icall [1] with ThinLTO.<br>
<br>
Jumptables are generated in the merged module. To generate a<br>
jumptable, we need a list of functions with !type annotations,<br>
including (in non-cross-dso mode) external functions. Unfortunately,<br>
LLVM IR does not preserve unused function declarations, and we don’t<br>
want to copy the actual function bodies to the merged module.<br>
<br>
Indirect call targets can be represented in the following way using<br>
named metadata:<br>
<br>
void foo() {}<br>
int bar() { return 0; }<br>
<br>
# Merged module<br>
!cfi.functions = !{!1, !3}<br>
!1 = !{!"bar", i8 0, !2}<br>
!2 = !{i64 0, !"_ZTSFiE"}<br>
!3 = !{!"foo", i8 0, !4}<br>
!4 = !{i64 0, !"_ZTSFvE"}<br></blockquote><div><br></div><div>Presumably there would be no entries in !cfi.functions for functions defined in the merged module, as the type metadata would come from the module itself.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Each function is described by a tuple of<br>
* Promoted name as a string<br></blockquote><div><br></div><div>I imagine that we would only promote a function if it is address-taken. Otherwise we could be inhibiting optimization significantly.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
* Linkage (see below)<br>
* Type(s)<br>
<br>
<br>
A function can have multiple types. In the Cross-DSO mode each<br>
function has a second “external” numeric type, and we might want to<br>
allow “relaxed” type checking in the future where a function could<br>
conform to multiple types. In that case the metadata would look like<br>
this:<br>
<br>
!4 = !{!"bar", i8 0, !5, !6}<br>
!5 = !{i64 0, !"_ZTSFiE"}<br>
!6 = !{i64 0, i64 751454132325070187}<br>
<br>
“Linkage” is one of: definition, external declaration, external weak<br>
declaration.<br>
<br>
In the merged “merged” module, !cfi.functions may contain multiple<br>
entries for each function. We pick one with the strongest linkage<br>
(i.e. the definition, if it is available) in LowerTypeTests.<br></blockquote><div><br></div><div>It's unfortunate that this design effectively requires that the LowerTypeTests pass recompute the linkage for each symbol, as the linker already knows this information (and could, in principle, provide it to the pass). But I'm not sure if there's a better way to do it.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
The LTO step emits, for a defined function named “f”:<br>
declare void f.cfi()<br>
.jumptable:<br>
…<br>
call f.cfi<br>
...<br>
f.cfi-jt = alias .jumptable + offset<br>
f = alias f.cfi-jt<br>
<br>
The same for an external (either weak or strong) declaration of a<br>
function named “f”:<br>
.jumptable:<br>
…<br>
call f<br>
...<br>
f.cfi-jt = alias .jumptable + offset<br>
<br></blockquote><div><br></div><div>One thing to be careful about is summary-based dead stripping: the pass needs to be able to query whether any specific function is still live in order to avoid introducing undefined symbol references. I think we can do that by adding a Live flag to GlobalValueSummaryInfo (which I think should also let us fix a number of FIXMEs elsewhere, e.g. <a href="http://llvm-cs.pcc.me.uk/lib/Transforms/IPO/LowerTypeTests.cpp#1447" target="_blank">http://llvm-cs.pcc.me.uk/<wbr>lib/Transforms/IPO/LowerTypeTe<wbr>sts.cpp#1447</a> <a href="http://llvm-cs.pcc.me.uk/lib/Transforms/IPO/WholeProgramDevirt.cpp#1329" target="_blank">http://llvm-cs.pc<wbr>c.me.uk/lib/Transforms/IPO/Who<wbr>leProgramDevirt.cpp#1329</a>), and have the pass check the flag for each function.</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Weak external linkage is used in the lowering of uses of @f. This is<br>done both in the merged module and in ThinLTO backends. Uses of strong<br>definitions and declarations are replaced with f.cfi-jt. Uses of weak<br>external declarations a replaced with (f ? f.cfi-jt : 0) instead.</blockquote></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
ThinLTO backends need to know which functions have jumptable entries<br>
created for them (they will need to be RAUWed with f.cfi-jt). In the<br>
Cross-DSO mode, external functions don’t get jumptable entries. This<br>
information is passed back from the LTO step through combined summary.<br>
The current idea is to add a new record, FunctionTypeResolution, which<br>
would contain a set of function names in the jumptable.<br></blockquote><div><br></div><div>It occurred to me that this design could prevent inlining of indirect calls via constant propagation. For example, suppose that we have a module that looks like this:</div><div><br></div><div>define void @f() {</div><div> ret void</div><div>}</div><div><br></div><div>define void @g() {</div><div> %fp = call i8* @identity(i8* @f)</div><div> call void %fp()</div><div>}</div><div><br></div><div>and a second module:</div><div><br></div><div>define i8* @identity(i8* %ptr) {</div><div> return %ptr</div><div>}</div><div><br></div><div>and @identity is imported into the first module. Now I think the first module would look like this after optimization:</div><div><br></div><div>define void @f.cfi() {</div><div> ret void</div><div>}</div><div><br></div><div>declare void @f.cfi-jt()</div><div><br></div><div>define void @g.cfi() {</div><div> call void @f.cfi-jt()</div><div>}</div><div><br></div><div>So we cannot inline f.cfi into g.cfi, as the optimizer does not know that f.cfi-jt can be replaced with f.cfi. I'm not sure how likely this would be in practice, but something to keep in mind.</div><div><br></div><div>Peter</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
== Alternatives<br>
<br>
Function type information can be passed in the summary, as a list of<br>
records (name, linkage, type(, type)*).<br>
* Type can be either a string or a number. This complicates the encoding.<br>
* The code in LowerTypeTests works with !type metadata in the same<br>
format as described above. It would need to either recreate the<br>
metadata from the summary, or deal with different input formats.<br>
I don’t see any advantages to this encoding. Could it be more compact<br>
than the metadata approach?<br>
<br>
[1] <a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html#indirect-function-call-checking" rel="noreferrer" target="_blank">https://clang.llvm.org/docs/Co<wbr>ntrolFlowIntegrity.html#indire<wbr>ct-function-call-checking</a><br>
______________________________<wbr>_________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-dev</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="m_1463562608666097783m_-2077039780819457319gmail-m_-8207080408143575871gmail-m_178903005185447285gmail-m_4653642213528994379m_5176653323062868542m_7227464676392875144gmail_signature"><div dir="ltr">-- <div>Peter</div></div></div>
</div></div>