From 670436b9cd7a23f03c9d7248abb8eb19939c83a6 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 5 Jun 2017 22:23:18 -0700 Subject: [PATCH] scons: Try to handle problems with gcc, lto and partial linking. gcc has had a lot of problems with incremental linking and partial linking at the same time. Basically, the partial link assumes that it's the only link that's going to happen, and it converts weak external symbols into regular external symbols. Then when the real final link happens, those symbols are duplicated and the link fails. Versions of gcc 6 and greater add an option called -flinker-output which lets you tell the linker to do an incremental link. Unfortunately, other bugs make that fail, and so gcc 6 doesn't work either. Hopefully version 7 works better. A --force-lto option was added so that, when only one of lto and partial linking is available, you can switch from having partial linking to having lto. Change-Id: I5e293f5cfb07a14343dc74030d99cb161fb8bbbe Reviewed-on: https://gem5-review.googlesource.com/3680 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power --- SConstruct | 42 +++++++++++++++++++++++++++++++++++++++++- src/SConscript | 16 ++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/SConstruct b/SConstruct index bc1e1e296..146b156d1 100755 --- a/SConstruct +++ b/SConstruct @@ -183,6 +183,9 @@ AddLocalOption('--ignore-style', dest='ignore_style', action='store_true', help='Disable style checking hooks') AddLocalOption('--no-lto', dest='no_lto', action='store_true', help='Disable Link-Time Optimization for fast') +AddLocalOption('--force-lto', dest='force_lto', action='store_true', + help='Use Link-Time Optimization instead of partial linking' + + ' when the compiler doesn\'t support using them together.') AddLocalOption('--update-ref', dest='update_ref', action='store_true', help='Update test reference outputs') AddLocalOption('--verbose', dest='verbose', action='store_true', @@ -198,6 +201,10 @@ AddLocalOption('--with-ubsan', dest='with_ubsan', action='store_true', AddLocalOption('--with-asan', dest='with_asan', action='store_true', help='Build with Address Sanitizer if available') +if GetOption('no_lto') and GetOption('force_lto'): + print '--no-lto and --force-lto are mutually exclusive' + Exit(1) + termcap = get_termcap(GetOption('use_colors')) ######################################################################## @@ -719,6 +726,28 @@ if main['GCC']: main['GCC_VERSION'] = gcc_version + if compareVersions(gcc_version, '4.9') >= 0: + # Incremental linking with LTO is currently broken in gcc versions + # 4.9 and above. A version where everything works completely hasn't + # yet been identified. + # + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67548 + main['BROKEN_INCREMENTAL_LTO'] = True + if compareVersions(gcc_version, '6.0') >= 0: + # gcc versions 6.0 and greater accept an -flinker-output flag which + # selects what type of output the linker should generate. This is + # necessary for incremental lto to work, but is also broken in + # current versions of gcc. It may not be necessary in future + # versions. We add it here since it might be, and as a reminder that + # it exists. It's excluded if lto is being forced. + # + # https://gcc.gnu.org/gcc-6/changes.html + # https://gcc.gnu.org/ml/gcc-patches/2015-11/msg03161.html + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69866 + if not GetOption('force_lto'): + main.Append(PSHLINKFLAGS='-flinker-output=rel') + main.Append(PLINKFLAGS='-flinker-output=rel') + # gcc from version 4.8 and above generates "rep; ret" instructions # to avoid performance penalties on certain AMD chips. Older # assemblers detect this as an error, "Error: expecting string @@ -749,10 +778,21 @@ if main['GCC']: 'Warning: UBSan is only supported using gcc 4.9 and later.' + \ termcap.Normal + disable_lto = GetOption('no_lto') + if not disable_lto and main.get('BROKEN_INCREMENTAL_LTO', False) and \ + not GetOption('force_lto'): + print termcap.Yellow + termcap.Bold + \ + 'Warning: Your compiler doesn\'t support incremental linking' + \ + ' and lto at the same time, so lto is being disabled. To force' + \ + ' lto on anyway, use the --force-lto option. That will disable' + \ + ' partial linking.' + \ + termcap.Normal + disable_lto = True + # Add the appropriate Link-Time Optimization (LTO) flags # unless LTO is explicitly turned off. Note that these flags # are only used by the fast target. - if not GetOption('no_lto'): + if not disable_lto: # Pass the LTO flag when compiling to produce GIMPLE # output, we merely create the flags here and only append # them later diff --git a/src/SConscript b/src/SConscript index ed59bd228..519a0a986 100755 --- a/src/SConscript +++ b/src/SConscript @@ -957,7 +957,7 @@ def variantd(*path): # environment 'env' with modified object suffix and optional stripped # binary. Additional keyword arguments are appended to corresponding # build environment vars. -def makeEnv(env, label, objsfx, strip = False, **kwargs): +def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs): # SCons doesn't know to append a library suffix when there is a '.' in the # name. Use '_' instead. libname = variant('gem5_' + label) @@ -1059,6 +1059,14 @@ def makeEnv(env, label, objsfx, strip = False, **kwargs): if not srcs: continue + # If partial linking is disabled, add these sources to the build + # directly, and short circuit this loop. + if disable_partial: + for s in srcs: + static_objs.append(make_obj(s, True)) + shared_objs.append(make_obj(s, False)) + continue + # Set up the static partially linked objects. source_objs = [ make_obj(s, True) for s in srcs ] file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") @@ -1204,10 +1212,14 @@ def makeEnvirons(target, source, env): # "Fast" binary if 'fast' in needed_envs: + disable_partial = \ + env.get('BROKEN_INCREMENTAL_LTO', False) and \ + GetOption('force_lto') makeEnv(env, 'fast', '.fo', strip = True, CCFLAGS = Split(ccflags['fast']), CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], - LINKFLAGS = Split(ldflags['fast'])) + LINKFLAGS = Split(ldflags['fast']), + disable_partial=disable_partial) # Profiled binary using gprof if 'prof' in needed_envs: -- 2.30.2