<div dir="ltr"><br><br><div class="gmail_quote">On Wed, Mar 18, 2015 at 2:26 PM Duncan P. N. Exon Smith <<a href="mailto:dexonsmith@apple.com">dexonsmith@apple.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
> On 2015-Mar-18, at 13:17, Peter Collingbourne <<a href="mailto:peter@pcc.me.uk" target="_blank">peter@pcc.me.uk</a>> wrote:<br>
><br>
> On Wed, Mar 18, 2015 at 12:46:48PM -0700, Duncan P. N. Exon Smith wrote:<br>
>><br>
>>> On 2015-Mar-18, at 12:08, Peter Collingbourne <<a href="mailto:peter@pcc.me.uk" target="_blank">peter@pcc.me.uk</a>> wrote:<br>
>>><br>
>>> On Wed, Mar 18, 2015 at 09:16:54AM -0400, Rafael Espíndola wrote:<br>
>>>>> I don't think this should be a problem; there is no user-visible behaviour<br>
>>>>> change when using the supported way of enabling control flow integrity.<br>
>>>>><br>
>>>>> The only supported way to enable CFI for the user to supply -fsanitize=cfi*<br>
>>>>> at link time as well as at compile time. (Admittedly this should be<br>
>>>>> documented better.) The LowerBitSets pass only has an effect on the module<br>
>>>>> if -fsanitize=cfi* was passed as compile time. And the related change<br>
>>>>> <a href="http://reviews.llvm.org/D8402" target="_blank">http://reviews.llvm.org/D8402</a> modifies the Clang driver to supply the<br>
>>>>> lowerbitsets flag if -fsanitize=cfi* is supplied at link time.<br>
>>>><br>
>>>> If the pass does nothing if a given flag is not present, why not<br>
>>>> always run the pass and avoid the option?<br>
>>><br>
>>> I would like a way to run only a couple of passes at link time if CFI is<br>
>>> enabled and optimizations are enabled but LTO is not specifically enabled. In<br>
>>> particular, I've found that running only simplifycfg and globaldce makes a<br>
>>> significant difference in binary size (with the full LTO pipeline, a Chrome<br>
>>> binary is 179424536 bytes, and with simplifycfg+globaldce it is 160340400<br>
>>> bytes). So we need some way to communicate an optimization level to the<br>
>>> linker so that it knows what level to use.<br>
>>><br>
>>> Duncan and I discussed this on IRC last night, and we agreed that module<br>
>>> flags inserted at compile time would be the best way to communicate this<br>
>>> information. I thought further about how this could work and I came up with<br>
>>> something relatively simple.<br>
>>><br>
>>> The solution I have in mind is that a module flag named "LTO Opt Level"<br>
>>> will control the opt level. An opt level of 0 runs no optimization passes, a<br>
>>> level of 1 runs only simplifycfg and globaldce and 2 runs the entire LTO pass<br>
>>> pipeline. -flto causes us to set the flag to 2, otherwise -O >= 1 causes us<br>
>>> to set it to 1, otherwise it is 0. When modules have conflicting opt levels,<br>
>>> we pick the maximum.<br>
>>><br>
>>> I have patches that implement this and I'll upload them later today.<br>
>><br>
>> I'm still not sure about the high-level approach.  I didn't put together<br>
>> that you'd need to send an "LTO Opt Level" through module flags (I just<br>
>> understood the -lowerbitsets part).<br>
>><br>
>> I think there may be a minefield of semantic issues with using the LTO<br>
>> pipeline when the user hasn't specifically enabled LTO.  Can you point<br>
>> me at the discussion on the list about this so I can catch up?  (I'm<br>
>> sorry I missed it.)<br>
><br>
> What discussion there has been was in the proposal thread:<br>
> <a href="https://groups.google.com/d/msg/llvm-dev/YzJSG2VGydI/76zJXpv4OuQJ" target="_blank">https://groups.google.com/d/<u></u>msg/llvm-dev/YzJSG2VGydI/<u></u>76zJXpv4OuQJ</a><br>
<br>
Thanks for this.  Sorry for chasing you in circles.<br>
<br>
><br>
>> For example, what semantics do you expect in the following case?<br>
>><br>
>>    $ clang -O3 -flto a.c<br>
>>    $ clang -O1 -fsanitize=cfi b.c<br>
>>    $ clang a.o b.o<br>
>><br>
>> Here, a.c is supposed to be compiled with LTO but b.c isn't.  I'm not<br>
>> sure how you would merge the LTO Opt Level in this case (among other<br>
>> problems).<br>
><br>
> In this case we compile both with LTO and use the maximum opt level, which<br>
> is 2 (2 from a.o and 1 from b.o). This is an approximation of what ought to<br>
> happen, but I reckon it isn't too bad to handle these types of cases poorly,<br>
> since in most cases one would be controlling the build flags for an entire<br>
> project compiled with CFI, so they would normally be consistent.<br>
><br>
>> IMO, the following flow makes more sense (but maybe this was already<br>
>> discussed?):<br>
>><br>
>>  - If -fno-lto, run -lowerbitsets near the end of the -cc1 opt<br>
>>    pipeline.  *Do not* enable -flto.<br>
><br>
> This won't work (unless perhaps if the whole program was in that translation<br>
> unit). The lowerbitsets pass needs whole-program visibility.<br>
<br>
Yes, I understand now, after reading the original thread.<br>
<br>
IMO, we should continue to always run the -lowerbitsets pass.  It's free<br>
if there's no work to do.  There's no reason to encode this in the<br>
module or pass any info from `clang` related to this pass.<br>
<br>
But I guess your real goal here is to stop running the rest of the<br>
optimizations, and that's the contentious part.  Currently clang doesn't<br>
control the LTO pass pipeline, and how/whether to do that isn't clear.<br>
<br>
Starting to do that, whether it's via -disable-opt, "LTO Opt Level", or<br>
some other mechanism, isn't really related to lowering bitsets, and<br>
probably needs its own discussion.</blockquote><div><br></div><div>Agreed with everything here.</div><div><br></div><div>-eric </div></div></div>