# Copyright (c) 2012 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-#
-# IMPORTANT NOTE: If you make local mods to this file, you must run:
-# % pnacl/build.sh driver
-# in order for them to take effect in the scons build. This command
-# updates the copy in the toolchain/ tree.
-#
-
-from driver_tools import *
+
+from driver_tools import ArchMerge, DriverChain, GetArch, \
+ ParseArgs, ParseTriple, RunDriver, RunWithEnv, SetArch, \
+ SetExecutableMode, TempNameGen, UnrecognizedOption
from driver_env import env
-from driver_log import Log, DriverOpen, TempFiles
+from driver_log import Log
import filetype
-import platform
+import ldtools
+import pathtools
EXTRA_ENV = {
'ALLOW_NATIVE': '0', # Allow LD args which will change the behavior
'INPUTS' : '',
'OUTPUT' : '',
- 'SHARED' : '0',
'STATIC' : '0',
'PIC' : '0',
'USE_STDLIB': '1',
# requested or not, since we don't want to propagate
# the value to TRANSLATE_FLAGS if it wasn't explicitly set.
'OPT_LTO_FLAGS': '-std-link-opts -disable-internalize',
- 'OPT_FLAGS': '${#OPT_LEVEL && !OPT_LEVEL == 0 ? ${OPT_LTO_FLAGS}} ${OPT_STRIP_%STRIP_MODE%} ' +
+ 'OPT_FLAGS': '${#OPT_LEVEL && !OPT_LEVEL == 0 ? ${OPT_LTO_FLAGS}} ' +
'-inline-threshold=${OPT_INLINE_THRESHOLD} ',
- 'OPT_STRIP_none': '',
- 'OPT_STRIP_all': '-disable-opt --strip',
- 'OPT_STRIP_debug': '-disable-opt --strip-debug',
'TRANSLATE_FLAGS': '${PIC ? -fPIC} ${!USE_STDLIB ? -nostdlib} ' +
- '${STATIC ? -static} ' +
- '${SHARED ? -shared} ' +
'${#SONAME ? -Wl,--soname=${SONAME}} ' +
'${#OPT_LEVEL ? -O${OPT_LEVEL}} ' +
'--allow-llvm-bitcode-input ' +
+ '${CXX_EH_MODE==zerocost ? --pnacl-allow-zerocost-eh} ' +
'${TRANSLATE_FLAGS_USER}',
# Extra pnacl-translate flags specified by the user using -Wt
'-plugin-opt=emit-llvm',
'LD_FLAGS' : '-nostdlib ${@AddPrefix:-L:SEARCH_DIRS} ' +
- '${SHARED ? -shared} ${STATIC ? -static} ' +
+ '${STATIC ? -static} ' +
'${RELOCATABLE ? -relocatable} ' +
'${#SONAME ? --soname=${SONAME}}',
# Standard Library Directories
'SEARCH_DIRS_BUILTIN': '${USE_STDLIB ? ' +
+ ' ${BASE_USR}/usr/lib/ ' +
' ${BASE_USR}/lib/ ' +
' ${BASE_SDK}/lib/ ' +
' ${BASE_LIB}/ ' +
'}',
- 'BCLD_OFORMAT' : '${BCLD_OFORMAT_%ARCH%}',
- 'BCLD_OFORMAT_ARM' : 'elf32-littlearm',
- 'BCLD_OFORMAT_X8632' : 'elf32-i386-nacl',
- 'BCLD_OFORMAT_X8664' : 'elf64-x86-64-nacl',
- 'BCLD_OFORMAT_MIPS32' : 'elf32-tradlittlemips',
+ 'BCLD_OFORMAT' : '${BCLD_OFORMAT_%ARCH%}',
+ 'BCLD_OFORMAT_ARM' : 'elf32-littlearm',
+ 'BCLD_OFORMAT_X8632' : 'elf32-i386-nacl',
+ 'BCLD_OFORMAT_X8664' : 'elf64-x86-64-nacl',
+ 'BCLD_OFORMAT_MIPS32' : 'elf32-tradlittlemips-nacl',
+ 'BCLD_OFORMAT_ARM_NONSFI' : 'elf32-littlearm',
+ 'BCLD_OFORMAT_X8632_NONSFI' : 'elf32-i386-nacl',
'BCLD_ALLOW_UNRESOLVED' :
# The following functions are implemented in the native support library.
'--allow-unresolved=memmove '
'--allow-unresolved=setjmp '
'--allow-unresolved=longjmp '
+ # These TLS layout functions are either defined by the ExpandTls
+ # pass or (for non-ABI-stable code only) by PNaCl's native support
+ # code.
+ '--allow-unresolved=__nacl_tp_tls_offset '
+ '--allow-unresolved=__nacl_tp_tdb_offset '
+ # __nacl_get_arch() is for non-ABI-stable code only.
+ '--allow-unresolved=__nacl_get_arch '
+ '${CXX_EH_MODE==sjlj ? '
+ # These symbols are defined by libsupc++ and the PNaClSjLjEH
+ # pass generates references to them.
+ '--undefined=__pnacl_eh_stack '
+ '--undefined=__pnacl_eh_resume '
+ # These symbols are defined by the PNaClSjLjEH pass and
+ # libsupc++ refers to them.
+ '--allow-unresolved=__pnacl_eh_type_table '
+ '--allow-unresolved=__pnacl_eh_action_table '
+ '--allow-unresolved=__pnacl_eh_filter_table} '
# For exception-handling enabled tests.
- '${ALLOW_CXX_EXCEPTIONS ? '
+ '${CXX_EH_MODE==zerocost ? '
'--allow-unresolved=_Unwind_Backtrace '
'--allow-unresolved=_Unwind_DeleteException '
'--allow-unresolved=_Unwind_GetCFA '
'--allow-unresolved=_Unwind_SetIP}',
'BCLD_FLAGS':
- '--oformat ${BCLD_OFORMAT} -Ttext=0x20000 ' +
- '${!SHARED && !RELOCATABLE ? --undef-sym-check ${BCLD_ALLOW_UNRESOLVED}} ' +
+ '--oformat ${BCLD_OFORMAT} ' +
+ '${!RELOCATABLE ? --undef-sym-check ${BCLD_ALLOW_UNRESOLVED}} ' +
'${GOLD_PLUGIN_ARGS} ${LD_FLAGS}',
'RUN_BCLD': ('${LD} ${BCLD_FLAGS} ${inputs} -o ${output}'),
- 'ALLOW_CXX_EXCEPTIONS': '0',
+ 'CXX_EH_MODE': 'none',
'ALLOW_NEXE_BUILD_ID': '0',
'DISABLE_ABI_CHECK': '0',
'LLVM_PASSES_TO_DISABLE': '',
- # Skip dev intrinsic checks in ABI verifier. Used for pnacl-llc.pexe and
- # gold.pexe, which currently use llvm.nacl.target.arch.
- # TODO(jvoung): find way to stop using llvm.nacl.target.arch.
- 'ALLOW_DEV_INTRINSICS': '0',
+ 'RUN_PASSES_SEPARATELY': '0',
}
def AddToBCLinkFlags(*args):
env.append('LD_FLAGS', *args)
env.append('LD_FLAGS_NATIVE', *args)
-def AddAllowCXXExceptions(*args):
- env.set('ALLOW_CXX_EXCEPTIONS', '1')
- env.append('TRANSLATE_FLAGS', *args)
-
def SetLibTarget(*args):
arch = ParseTriple(args[0])
if arch != 'le32':
LDPatterns = [
( '--pnacl-allow-native', "env.set('ALLOW_NATIVE', '1')"),
( '--noirt', "env.set('USE_IRT', '0')"),
- ( '(--pnacl-allow-exceptions)', AddAllowCXXExceptions),
+ ( '--pnacl-exceptions=(none|sjlj|zerocost)', "env.set('CXX_EH_MODE', $0)"),
+ # TODO(mseaborn): Remove "--pnacl-allow-exceptions", which is
+ # superseded by "--pnacl-exceptions".
+ ( '--pnacl-allow-exceptions', "env.set('CXX_EH_MODE', 'zerocost')"),
( '(--pnacl-allow-nexe-build-id)', "env.set('ALLOW_NEXE_BUILD_ID', '1')"),
( '--pnacl-disable-abi-check', "env.set('DISABLE_ABI_CHECK', '1')"),
# "--pnacl-disable-pass" allows an ABI simplification pass to be
# required for ABI-stable pexes but can be omitted when the PNaCl
# toolchain is used for producing native nexes.
( '--pnacl-disable-pass=(.+)', "env.append('LLVM_PASSES_TO_DISABLE', $0)"),
- ( '--pnacl-allow-dev-intrinsics', "env.set('ALLOW_DEV_INTRINSICS', '1')"),
+ ( '--pnacl-run-passes-separately', "env.set('RUN_PASSES_SEPARATELY', '1')"),
( ('-target', '(.+)'), SetLibTarget),
( ('--target=(.+)'), SetLibTarget),
( '-o(.+)', "env.set('OUTPUT', pathtools.normalize($0))"),
( ('-o', '(.+)'), "env.set('OUTPUT', pathtools.normalize($0))"),
+ ( ('--output', '(.+)'), "env.set('OUTPUT', pathtools.normalize($0))"),
- ( '-shared', "env.set('SHARED', '1')"),
( '-static', "env.set('STATIC', '1')"),
( '-nostdlib', "env.set('USE_STDLIB', '0')"),
+
( '-r', "env.set('RELOCATABLE', '1')"),
( '-relocatable', "env.set('RELOCATABLE', '1')"),
+ ( '-i', "env.set('RELOCATABLE', '1')"),
( ('-L', '(.+)'),
"env.append('SEARCH_DIRS_USER', pathtools.normalize($0))\n"),
( ('--library-path', '(.+)'),
"env.append('SEARCH_DIRS_USER', pathtools.normalize($0))\n"),
- # We just ignore undefined symbols in shared objects, so
- # -rpath-link should not be necessary.
- #
- # However, libsrpc.so still needs to be linked in directly (in non-IRT mode)
- # or it malfunctions. This is the only way that -rpath-link is still used.
- # There's a corresponding hack in pnacl-translate to recognize libsrpc.so
- # and link it in directly.
- # TODO(pdox): Investigate this situation.
+ # -rpath and -rpath-link are only relevant to dynamic linking.
+ # Ignore them for compatibility with build scripts that expect to be
+ # able to pass them.
( ('(-rpath)','(.*)'), ""),
( ('(-rpath)=(.*)'), ""),
- ( ('(-rpath-link)','(.*)'),
- "env.append('TRANSLATE_FLAGS', $0+'='+pathtools.normalize($1))"),
- ( ('(-rpath-link)=(.*)'),
- "env.append('TRANSLATE_FLAGS', $0+'='+pathtools.normalize($1))"),
+ ( ('(-rpath-link)','(.*)'), ""),
+ ( ('(-rpath-link)=(.*)'), ""),
# This overrides the builtin linker script.
( ('(-T)', '(.*)'), AddToNativeFlags),
( ('-?-soname', '(.*)'), "env.set('SONAME', $0)"),
( '(-M)', AddToBCLinkFlags),
+ ( '(--print-map)', AddToBCLinkFlags),
( '(-t)', AddToBCLinkFlags),
+ ( '(--trace)', AddToBCLinkFlags),
( ('(-y)','(.*)'), AddToBCLinkFlags),
( ('(-defsym)','(.*)'), AddToBCLinkFlags),
( '-mmipselelf_nacl', "env.set('ARCH', 'MIPS32')"),
( ('-m','mipselelf_nacl'), "env.set('ARCH', 'MIPS32')"),
+ ( ('(-?-wrap)', '(.+)'), AddToBCLinkFlags),
+ ( ('(-?-wrap=.+)'), AddToBCLinkFlags),
+
# NOTE: For scons tests, the code generation fPIC flag is used with pnacl-ld.
( '-fPIC', "env.set('PIC', '1')"),
# Inputs and options that need to be kept in order
( '(-l.*)', "env.append('INPUTS', $0)"),
( ('(-l)','(.*)'), "env.append('INPUTS', $0+$1)"),
+ ( ('--library', '(.*)'), "env.append('INPUTS', '-l'+$0)"),
+
( '(--no-as-needed)', "env.append('INPUTS', $0)"),
( '(--as-needed)', "env.append('INPUTS', $0)"),
( '(--start-group)', "env.append('INPUTS', $0)"),
( '(-Bdynamic)', "env.append('INPUTS', $0)"),
( '(--(no-)?whole-archive)', "env.append('INPUTS', $0)"),
( '(--undefined=.*)', "env.append('INPUTS', $0)"),
+ ( ('(-u)','(.*)'), "env.append('INPUTS', $0+$1)"),
+ ( '(-u.*)', "env.append('INPUTS', $0)"),
( '(-.*)', UnrecognizedOption),
( '(.*)', "env.append('INPUTS', pathtools.normalize($0))"),
]
env.set('BASE_LIB', "${BASE_LIB_ARCH}")
if env.getbool('RELOCATABLE'):
- if env.getbool('SHARED'):
- Log.Fatal("-r and -shared may not be used together")
env.set('STATIC', '0')
inputs = env.get('INPUTS')
SetArch('X8632')
assert(GetArch() is not None)
+ inputs = FixPrivateLibs(inputs)
+
# Expand all parameters
# This resolves -lfoo into actual filenames,
# and expands linker scripts into command-line arguments.
regular_inputs, native_objects = SplitLinkLine(inputs)
- if not env.getbool('USE_IRT'):
- inputs = UsePrivateLibraries(inputs)
-
- inputs = ReorderPrivateLibs(inputs)
-
- if env.getbool('SHARED'):
- bitcode_type = 'pso'
- native_type = 'so'
- elif env.getbool('RELOCATABLE'):
+ if env.getbool('RELOCATABLE'):
bitcode_type = 'po'
native_type = 'o'
else:
# not needed.
abi_simplify = (env.getbool('STATIC') and
len(native_objects) == 0 and
- not env.getbool('ALLOW_CXX_EXCEPTIONS') and
+ env.getone('CXX_EH_MODE') != 'zerocost' and
not env.getbool('ALLOW_NEXE_BUILD_ID') and
IsPortable())
still_need_expand_byval = IsPortable()
- preopt_passes = []
+ # A list of groups of args. Each group should contain a pass to run
+ # along with relevant flags that go with that pass.
+ opt_args = []
if abi_simplify:
- preopt_passes += ['-pnacl-abi-simplify-preopt']
- elif not env.getbool('ALLOW_CXX_EXCEPTIONS'):
+ pre_simplify = ['-pnacl-abi-simplify-preopt']
+ if env.getone('CXX_EH_MODE') == 'sjlj':
+ pre_simplify += ['-enable-pnacl-sjlj-eh']
+ else:
+ assert env.getone('CXX_EH_MODE') == 'none'
+ opt_args.append(pre_simplify)
+ elif env.getone('CXX_EH_MODE') != 'zerocost':
# '-lowerinvoke' prevents use of C++ exception handling, which
# is not yet supported in the PNaCl ABI. '-simplifycfg' removes
# landingpad blocks made unreachable by '-lowerinvoke'.
# We run this in order to remove 'resume' instructions,
# otherwise these are translated to calls to _Unwind_Resume(),
# which will not be available at native link time.
- preopt_passes += ['-lowerinvoke', '-simplifycfg']
- if len(preopt_passes) != 0:
- chain.add(DoLLVMPasses(preopt_passes), 'simplify_preopt.' + bitcode_type)
+ opt_args.append(['-lowerinvoke', '-simplifycfg'])
if env.getone('OPT_LEVEL') != '' and env.getone('OPT_LEVEL') != '0':
- chain.add(DoLTO, 'opt.' + bitcode_type)
- elif env.getone('STRIP_MODE') != 'none':
- chain.add(DoStrip, 'stripped.' + bitcode_type)
+ opt_args.append(env.get('OPT_FLAGS'))
+ if env.getone('STRIP_MODE') != 'none':
+ opt_args.append(env.get('STRIP_FLAGS'))
- postopt_passes = []
if abi_simplify:
- postopt_passes = ['-pnacl-abi-simplify-postopt']
+ post_simplify = ['-pnacl-abi-simplify-postopt']
if not env.getbool('DISABLE_ABI_CHECK'):
- postopt_passes += [
+ post_simplify += [
'-verify-pnaclabi-module',
'-verify-pnaclabi-functions',
# A flag for the above -verify-pnaclabi-* passes.
'-pnaclabi-allow-debug-metadata']
- if env.getbool('ALLOW_DEV_INTRINSICS'):
- # A flag for the above -verify-pnaclabi-* passes.
- postopt_passes += ['-pnaclabi-allow-dev-intrinsics']
+ opt_args.append(post_simplify)
elif still_need_expand_byval:
# We may still need -expand-byval to match the PPAPI shim
# calling convention.
- postopt_passes = ['-expand-byval']
- if len(postopt_passes) != 0:
- chain.add(DoLLVMPasses(postopt_passes),
- 'simplify_postopt.' + bitcode_type)
+ opt_args.append(['-expand-byval'])
+ if len(opt_args) != 0:
+ if env.getbool('RUN_PASSES_SEPARATELY'):
+ for i, group in enumerate(opt_args):
+ chain.add(DoLLVMPasses(group),
+ 'simplify_%d.%s' % (i, bitcode_type))
+ else:
+ flattened_opt_args = [flag for group in opt_args for flag in group]
+ chain.add(DoLLVMPasses(flattened_opt_args),
+ 'simplify_and_opt.' + bitcode_type)
else:
chain = DriverChain('', output, tng)
SetExecutableMode(output)
return 0
-def UsePrivateLibraries(libs):
- """ Place libnacl_sys_private.a before libnacl.a
- Replace libpthread.a with libpthread_private.a
- Replace libnacl_dyncode.a with libnacl_dyncode_private.a
- This assumes that the private libs can be found at the same directory
- as the public libs.
- """
- result_libs = []
- for l in libs:
- base = pathtools.basename(l)
- dname = pathtools.dirname(l)
- if base == 'libnacl.a':
- Log.Info('Not using IRT -- injecting libnacl_sys_private.a to link line')
- result_libs.append(pathtools.join(dname, 'libnacl_sys_private.a'))
- result_libs.append(l)
- elif base == 'libpthread.a':
- Log.Info('Not using IRT -- swapping private lib for libpthread')
- result_libs.append(pathtools.join(dname, 'libpthread_private.a'))
- elif base == 'libnacl_dyncode.a':
- Log.Info('Not using IRT -- swapping private lib for libnacl_dyncode')
- result_libs.append(pathtools.join(dname, 'libnacl_dyncode_private.a'))
- else:
- result_libs.append(l)
- return result_libs
+def FixPrivateLibs(user_libs):
+ """If not using the IRT or if private libraries are used:
+ - Place private libraries that can coexist before their public
+ equivalent (keep both);
+ - Replace public libraries that can't coexist with their private
+ equivalent.
-def ReorderPrivateLibs(libs):
- """ Place private libraries just before their non-private equivalent
- if there is one.
+ This occurs before path resolution (important because public/private
+ libraries aren't always colocated) and assumes that -l:libfoo.a syntax
+ isn't used by the driver for relevant libraries.
"""
- result_libs = list(libs)
- bases = {}
- for l in libs:
- bases[pathtools.basename(l)] = l
- lib_map = {
- 'libnacl_sys_private.a': 'libnacl.a',
- 'libpthread_private.a': 'libpthread.a',
- 'libnacl_dyncode_private.a': 'libnacl_dyncode.a'
+ special_libs = {
+ # Public library name: (private library name, can coexist?)
+ '-lnacl': ('-lnacl_sys_private', True),
+ '-lpthread': ('-lpthread_private', False),
}
- for l in libs:
- base = pathtools.basename(l)
- if base in lib_map and lib_map[base] in bases:
- result_libs.remove(l)
- result_libs.insert(result_libs.index(bases[lib_map[base]]), l)
+ private_libs = [v[0] for v in special_libs.values()]
+ public_libs = special_libs.keys()
+ private_lib_for = lambda user_lib: special_libs[user_lib][0]
+ can_coexist = lambda user_lib: special_libs[user_lib][1]
+
+ no_irt = not env.getbool('USE_IRT')
+ uses_private_libs = set(user_libs) & set(private_libs)
+
+ if not (no_irt or uses_private_libs):
+ return user_libs
+
+ result_libs = []
+ for user_lib in user_libs:
+ if user_lib in public_libs:
+ result_libs.append(private_lib_for(user_lib))
+ if can_coexist(user_lib):
+ result_libs.append(user_lib)
+ else:
+ result_libs.append(user_lib)
return result_libs
def SplitLinkLine(inputs):
ArchMerge(f, True)
else:
Log.Fatal("%s: Unexpected type of file for linking (%s)",
- pathtools.touser(f), FileType(f))
+ pathtools.touser(f), filetype.FileType(f))
count += 1
if count == 0:
def Func(infile, outfile):
filtered_list = [pass_option for pass_option in pass_list
if pass_option not in env.get('LLVM_PASSES_TO_DISABLE')]
- RunDriver('opt', filtered_list + [infile, '-o', outfile])
+ RunDriver('pnacl-opt', filtered_list + [infile, '-o', outfile])
return Func
-def DoLTO(infile, outfile):
- opt_flags = env.get('OPT_FLAGS')
- RunDriver('opt', opt_flags + [ infile, '-o', outfile ])
-
-def DoStrip(infile, outfile):
- strip_flags = env.get('STRIP_FLAGS')
- RunDriver('strip', strip_flags + [ infile, '-o', outfile ])
-
def DoTranslate(infile, outfile):
args = env.get('TRANSLATE_FLAGS')
args += ['-Wl,'+s for s in env.get('LD_FLAGS_NATIVE')]
args += ['-Wl,'+s if ldtools.IsFlag(s) else s
for s in env.get('NATIVE_OBJECTS')]
args += ['-o', outfile]
- RunDriver('translate', args)
+ RunDriver('pnacl-translate', args)
def LinkBC(inputs, output):
'''Input: a bunch of bc/o/lib input files
Bitcode linker for PNaCl. Similar to the binutils "ld" tool,
but links bitcode instead of native code. Supports many of the
-"ld" flags.
+"ld" flags. Below are a subset of them.
OPTIONS:
-L DIRECTORY, --library-path DIRECTORY
Add DIRECTORY to library search path
- -r, --relocatable Generate relocatable output
+ -r, -relocatable Generate relocatable output
-O<opt-level> Optimize output file
-M, --print-map Print map file on standard output
--no-whole-archive Turn off --whole-archive
-s, --strip-all Strip all symbols
-S, --strip-debug Strip debugging symbols
- --undefined SYMBOL Start with undefined reference to SYMBOL
+ -u SYM, --undefined=SYM Start with undefined reference to SYM
-help | -h Output this help.
"""