[PATCH] gold, libLTO: Add new flags to support bit set lowering.

Peter Collingbourne peter at pcc.me.uk
Wed Mar 18 13:17:12 PDT 2015

On Wed, Mar 18, 2015 at 12:46:48PM -0700, Duncan P. N. Exon Smith wrote:
> > On 2015-Mar-18, at 12:08, Peter Collingbourne <peter at pcc.me.uk> wrote:
> > 
> > On Wed, Mar 18, 2015 at 09:16:54AM -0400, Rafael EspĂ­ndola wrote:
> >>> I don't think this should be a problem; there is no user-visible behaviour
> >>> change when using the supported way of enabling control flow integrity.
> >>> 
> >>> The only supported way to enable CFI for the user to supply -fsanitize=cfi*
> >>> at link time as well as at compile time. (Admittedly this should be
> >>> documented better.) The LowerBitSets pass only has an effect on the module
> >>> if -fsanitize=cfi* was passed as compile time. And the related change
> >>> http://reviews.llvm.org/D8402 modifies the Clang driver to supply the
> >>> lowerbitsets flag if -fsanitize=cfi* is supplied at link time.
> >> 
> >> If the pass does nothing if a given flag is not present, why not
> >> always run the pass and avoid the option?
> > 
> > I would like a way to run only a couple of passes at link time if CFI is
> > enabled and optimizations are enabled but LTO is not specifically enabled. In
> > particular, I've found that running only simplifycfg and globaldce makes a
> > significant difference in binary size (with the full LTO pipeline, a Chrome
> > binary is 179424536 bytes, and with simplifycfg+globaldce it is 160340400
> > bytes). So we need some way to communicate an optimization level to the
> > linker so that it knows what level to use.
> > 
> > Duncan and I discussed this on IRC last night, and we agreed that module
> > flags inserted at compile time would be the best way to communicate this
> > information. I thought further about how this could work and I came up with
> > something relatively simple.
> > 
> > The solution I have in mind is that a module flag named "LTO Opt Level"
> > will control the opt level. An opt level of 0 runs no optimization passes, a
> > level of 1 runs only simplifycfg and globaldce and 2 runs the entire LTO pass
> > pipeline. -flto causes us to set the flag to 2, otherwise -O >= 1 causes us
> > to set it to 1, otherwise it is 0. When modules have conflicting opt levels,
> > we pick the maximum.
> > 
> > I have patches that implement this and I'll upload them later today.
> I'm still not sure about the high-level approach.  I didn't put together
> that you'd need to send an "LTO Opt Level" through module flags (I just
> understood the -lowerbitsets part).
> I think there may be a minefield of semantic issues with using the LTO
> pipeline when the user hasn't specifically enabled LTO.  Can you point
> me at the discussion on the list about this so I can catch up?  (I'm
> sorry I missed it.)

What discussion there has been was in the proposal thread:

> For example, what semantics do you expect in the following case?
>     $ clang -O3 -flto a.c
>     $ clang -O1 -fsanitize=cfi b.c
>     $ clang a.o b.o
> Here, a.c is supposed to be compiled with LTO but b.c isn't.  I'm not
> sure how you would merge the LTO Opt Level in this case (among other
> problems).

In this case we compile both with LTO and use the maximum opt level, which
is 2 (2 from a.o and 1 from b.o). This is an approximation of what ought to
happen, but I reckon it isn't too bad to handle these types of cases poorly,
since in most cases one would be controlling the build flags for an entire
project compiled with CFI, so they would normally be consistent.

> IMO, the following flow makes more sense (but maybe this was already
> discussed?):
>   - If -fno-lto, run -lowerbitsets near the end of the -cc1 opt
>     pipeline.  *Do not* enable -flto.

This won't work (unless perhaps if the whole program was in that translation
unit). The lowerbitsets pass needs whole-program visibility.


More information about the llvm-commits mailing list