2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 # IMPORTANT NOTE: If you make local mods to this file, you must run:
7 # % pnacl/build.sh driver
8 # in order for them to take effect in the scons build. This command
9 # updates the copy in the toolchain/ tree.
15 import multiprocessing
18 from driver_env import env
19 from driver_log import Log
20 from driver_temps import TempFiles
25 'PIC': '${NONSFI_NACL}',
27 # Determine if we should build nexes compatible with the IRT
30 # Allow zero-cost C++ exception handling in the pexe, which is not
31 # supported by PNaCl's stable ABI.
32 'ALLOW_ZEROCOST_CXX_EH' : '0',
34 # Use the IRT shim by default. This can be disabled with an explicit
35 # flag (--noirtshim) or via -nostdlib.
38 # To simulate the sandboxed translator better and avoid user surprises,
39 # reject LLVM bitcode (non-finalized) by default, accepting only PNaCl
40 # (finalized) bitcode. --allow-llvm-bitcode-input has to be passed
41 # explicitly to override this.
42 'ALLOW_LLVM_BITCODE_INPUT': '0',
44 # Flags for pnacl-nativeld
45 'LD_FLAGS': '-static',
48 'USE_DEFAULTLIBS': '1',
49 'FAST_TRANSLATION': '0',
56 'LD_ARGS' : '${USE_STDLIB ? ${LD_ARGS_normal} : ${LD_ARGS_nostdlib}}',
58 # Note: we always requires a shim now, but the dummy shim is not doing
60 # libpnacl_irt_shim.a is generated during the SDK packaging not
61 # during the toolchain build and there are hacks in pnacl/driver/ldtools.py
62 # and pnacl/driver/pnacl-nativeld.py that will fall back to
63 # libpnacl_irt_shim_dummy.a if libpnacl_irt_shim.a does not exist.
64 'LD_ARGS_IRT_SHIM': '-l:libpnacl_irt_shim.a',
65 'LD_ARGS_IRT_SHIM_DUMMY': '-l:libpnacl_irt_shim_dummy.a',
66 # In addition to specifying the entry point, we also specify an undefined
67 # reference to _start, which is called by the shim's entry function,
68 # __pnacl_wrapper_start. _start normally comes from libnacl and will be in
69 # the pexe, however for the IRT it comes from irt_entry.c and when linking it
70 # using native object files, this reference is required to make sure it gets
71 # pulled in from the archive.
72 'LD_ARGS_ENTRY': '--entry=__pnacl_start --undefined=_start',
74 'CRTBEGIN': '${ALLOW_ZEROCOST_CXX_EH ? -l:crtbegin_for_eh.o : -l:crtbegin.o}',
75 'CRTEND': '-l:crtend.o',
77 'LD_ARGS_nostdlib': '-nostdlib ${ld_inputs}',
79 # These are just the dependencies in the native link.
81 '${CRTBEGIN} ${ld_inputs} ' +
82 '${USE_IRT_SHIM ? ${LD_ARGS_IRT_SHIM} : ${LD_ARGS_IRT_SHIM_DUMMY}} ' +
84 '${USE_DEFAULTLIBS ? ${DEFAULTLIBS}} ' +
88 'DEFAULTLIBS': '${ALLOW_ZEROCOST_CXX_EH ? -l:libgcc_eh.a} ' +
89 '-l:libgcc.a -l:libcrt_platform.a ',
91 # BE CAREFUL: anything added here can introduce skew between
92 # the pnacl-translate commandline tool and the in-browser translator.
93 # See: llvm/tools/pnacl-llc/srpc_main.cpp and
94 # chromium/src/ppapi/native_client/src/trusted/plugin/pnacl_options.cc
95 'LLC_FLAGS_COMMON': '${PIC ? -relocation-model=pic} ' +
96 # -force-tls-non-pic makes the code generator (llc)
97 # do the work that would otherwise be done by
98 # linker rewrites which are quite messy in the nacl
99 # case and hence have not been implemented in gold
100 '${PIC ? -force-tls-non-pic} ',
102 # LLC flags which set the target and output type.
103 'LLC_FLAGS_TARGET' : '-mtriple=${TRIPLE} -filetype=${outfiletype}',
105 # Append additional non-default flags here.
106 # BE CAREFUL: anything added here can introduce skew between
107 # the pnacl-translate commandline tool and the in-browser translator.
108 # See: llvm/tools/pnacl-llc/srpc_main.cpp and
109 # chromium/src/ppapi/native_client/src/trusted/plugin/pnacl_options.cc
110 'LLC_FLAGS_EXTRA' : '${FAST_TRANSLATION ? ${LLC_FLAGS_FAST}} ' +
111 '${#OPT_LEVEL ? -O${OPT_LEVEL}} ' +
112 '${OPT_LEVEL == 0 ? -disable-fp-elim}',
114 # Opt level from command line (if any)
117 # faster translation == slower code
118 'LLC_FLAGS_FAST' : '-O0'
119 # This, surprisingly, makes a measurable difference
120 ' -tail-merge-threshold=20',
122 'LLC_FLAGS': '${LLC_FLAGS_TARGET} ${LLC_FLAGS_COMMON} ${LLC_FLAGS_ARCH} ' +
123 '${LLC_FLAGS_EXTRA}',
125 # Note: this is only used in the unsandboxed case
126 'RUN_LLC' : '${LLVM_PNACL_LLC} ${LLC_FLAGS} ${LLC_MCPU} '
127 '${input} -o ${output} ',
128 # Whether to stream the bitcode from a single FD in unsandboxed mode
129 # (otherwise it will use concurrent file reads when using multithreaded module
131 'STREAM_BITCODE' : '1',
132 # Rate in bits/sec to stream the bitcode from sel_universal over SRPC
133 # for testing. Defaults to 1Gbps (effectively unlimited).
134 'BITCODE_STREAM_RATE' : '1000000000',
135 # Default to 0, which means unset by the user. In this cases the driver will
136 # use up to 4 modules if there are enough cores. If the user overrides,
137 # use as many modules as specified (which could be only 1).
138 'SPLIT_MODULE' : '0',
142 TranslatorPatterns = [
143 ( '-o(.+)', "env.set('OUTPUT', pathtools.normalize($0))"),
144 ( ('-o', '(.+)'), "env.set('OUTPUT', pathtools.normalize($0))"),
146 ( '-S', "env.set('OUTPUT_TYPE', 's')"), # Stop at .s
147 ( '-c', "env.set('OUTPUT_TYPE', 'o')"), # Stop at .o
149 # Expose a very limited set of llc flags.
150 # BE CAREFUL: anything added here can introduce skew between
151 # the pnacl-translate commandline tool and the in-browser translator.
152 # See: llvm/tools/pnacl-llc/srpc_main.cpp and
153 # chromium/src/ppapi/native_client/src/trusted/plugin/pnacl_options.cc
154 ( '(-sfi-.+)', "env.append('LLC_FLAGS_EXTRA', $0)"),
155 ( '(-mtls-use-call)', "env.append('LLC_FLAGS_EXTRA', $0)"),
156 # These flags are usually used for linktime dead code/data
157 # removal but also help with reloc overflows on ARM
158 ( '(-fdata-sections)', "env.append('LLC_FLAGS_EXTRA', $0)"),
159 ( '(-ffunction-sections)', "env.append('LLC_FLAGS_EXTRA', $0)"),
160 ( '(--gc-sections)', "env.append('LD_FLAGS', $0)"),
161 ( '(-mattr=.*)', "env.append('LLC_FLAGS_EXTRA', $0)"),
162 ( '(-mcpu=.*)', "env.set('LLC_MCPU', '')\n"
163 "env.append('LLC_FLAGS_EXTRA', $0)"),
164 ( '(-pnaclabi-verify=.*)', "env.append('LLC_FLAGS_EXTRA', $0)"),
165 ( '(-pnaclabi-verify-fatal-errors=.*)', "env.append('LLC_FLAGS_EXTRA', $0)"),
166 ( '(-pnaclabi-allow-dev-intrinsics)', "env.append('LLC_FLAGS_EXTRA', $0)"),
167 # Allow overriding the -O level.
168 ( '-O([0-3])', "env.set('OPT_LEVEL', $0)"),
170 # This adds arch specific flags to the llc invocation aimed at
171 # improving translation speed at the expense of code quality.
172 ( '-translate-fast', "env.set('FAST_TRANSLATION', '1')"),
174 ( '-nostdlib', "env.set('USE_STDLIB', '0')"),
176 # Disables the default libraries.
177 # This flag is needed for building libgcc_s.so.
178 ( '-nodefaultlibs', "env.set('USE_DEFAULTLIBS', '0')"),
180 ( '--noirt', "env.set('USE_IRT', '0')\n"
181 "env.append('LD_FLAGS', '--noirt')"),
182 ( '--noirtshim', "env.set('USE_IRT_SHIM', '0')"),
183 ( '(--pnacl-nativeld=.+)', "env.append('LD_FLAGS', $0)"),
185 # Allowing zero-cost C++ exception handling causes a specific set of
186 # native objects to get linked into the nexe.
187 ( '--pnacl-allow-zerocost-eh', "env.set('ALLOW_ZEROCOST_CXX_EH', '1')"),
188 # TODO(mseaborn): Remove "--pnacl-allow-exceptions", replaced by
189 # "--pnacl-allow-zerocost-eh".
190 ( '--pnacl-allow-exceptions', "env.set('ALLOW_ZEROCOST_CXX_EH', '1')"),
192 ( '--allow-llvm-bitcode-input', "env.set('ALLOW_LLVM_BITCODE_INPUT', '1')"),
194 ( '-fPIC', "env.set('PIC', '1')"),
196 ( '(--build-id)', "env.append('LD_FLAGS', $0)"),
197 ( '-bitcode-stream-rate=([0-9]+)', "env.set('BITCODE_STREAM_RATE', $0)"),
198 ( '-split-module=([0-9]+)', "env.set('SPLIT_MODULE', $0)"),
199 ( '-no-stream-bitcode', "env.set('STREAM_BITCODE', '0')"),
201 # Treat general linker flags as inputs so they don't get re-ordered
202 ( '-Wl,(.*)', "env.append('INPUTS', *($0).split(','))"),
204 ( '(-.*)', driver_tools.UnrecognizedOption),
205 ( '(.*)', "env.append('INPUTS', pathtools.normalize($0))"),
210 base_arch = env.getone('BASE_ARCH')
211 env.set('TARGET_OS', 'nacl')
212 if base_arch.endswith('_LINUX'):
213 base_arch = base_arch[:-len('_LINUX')]
214 env.set('TARGET_OS', 'linux')
215 elif base_arch.endswith('_MAC'):
216 base_arch = base_arch[:-len('_MAC')]
217 env.set('TARGET_OS', 'mac')
219 if env.getbool('NONSFI_NACL'):
222 {'X8632': 'i686-linux-gnu',
223 'ARM': 'armv7a-linux-gnueabihf'}}
227 {'X8632': 'i686-none-nacl-gnu',
228 'X8664': 'x86_64-none-nacl-gnu',
229 'ARM': 'armv7a-none-nacl-gnueabihf',
230 'MIPS32': 'mipsel-none-nacl-gnu'},
231 'linux': {'X8632': 'i686-linux-gnu'},
232 'mac': {'X8632': 'i686-apple-darwin'}}
233 env.set('TRIPLE', triple_map[env.getone('TARGET_OS')][base_arch])
235 # CPU that is representative of baseline feature requirements for NaCl
236 # and/or chrome. We may want to make this more like "-mtune"
237 # by specifying both "-mcpu=X" and "-mattr=+feat1,-feat2,...".
238 # Note: this may be different from the in-browser translator, which may
239 # do auto feature detection based on CPUID, but constrained by what is
240 # accepted by NaCl validators.
245 'MIPS32': 'mips32r2'}
246 env.set('LLC_MCPU', '-mcpu=%s' % cpu_map[base_arch])
249 'ARM': ['-arm-reserve-r9', '-sfi-disable-cp', '-sfi-load', '-sfi-store',
250 '-sfi-stack', '-sfi-branch', '-sfi-data',
251 '-no-inline-jumptables', '-float-abi=hard', '-mattr=+neon'],
252 # Once PNaCl's build of compiler-rt (libgcc.a) defines __aeabi_*
253 # functions, we can drop the following ad-hoc option.
254 'ARM_NONSFI': ['-arm-enable-aeabi-functions=0'],
255 'MIPS32': ['-sfi-load', '-sfi-store', '-sfi-stack',
256 '-sfi-branch', '-sfi-data']}
257 env.set('LLC_FLAGS_ARCH', *llc_flags_map.get(env.getone('ARCH'), []))
258 # When linking against a host OS's libc (such as Linux glibc), don't
259 # use %gs:0 to read the thread pointer because that won't be
260 # compatible with the libc's use of %gs:0. Similarly, Non-SFI Mode
261 # currently offers no optimized path for reading the thread pointer.
262 if env.getone('TARGET_OS') != 'nacl' or env.getbool('NONSFI_NACL'):
263 env.append('LLC_FLAGS_ARCH', '-mtls-use-call')
267 env.update(EXTRA_ENV)
268 driver_tools.ParseArgs(argv, TranslatorPatterns)
269 driver_tools.GetArch(required = True)
272 inputs = env.get('INPUTS')
273 output = env.getone('OUTPUT')
276 Log.Fatal("No input files")
279 Log.Fatal("Please specify output file with -o")
281 # Find the bitcode file on the command line.
282 bcfiles = [f for f in inputs
283 if not ldtools.IsFlag(f) and
284 (filetype.IsPNaClBitcode(f)
285 or filetype.IsLLVMBitcode(f)
286 or filetype.FileType(f) == 'll')]
288 Log.Fatal('Expecting at most 1 bitcode file')
289 elif len(bcfiles) == 1:
294 if not env.getbool('SPLIT_MODULE'):
296 env.set('SPLIT_MODULE', str(min(4, multiprocessing.cpu_count())))
297 except NotImplementedError:
298 env.set('SPLIT_MODULE', '2')
299 elif int(env.getone('SPLIT_MODULE')) < 1:
300 Log.Fatal('Value given for -split-module must be > 0')
301 if (env.getbool('ALLOW_LLVM_BITCODE_INPUT') or
302 env.getone('TARGET_OS') != 'nacl' or
303 env.getbool('USE_EMULATOR')):
304 # When llvm input is allowed, the pexe may not be ABI-stable, so do not
305 # split it. Non-ABI-stable pexes may have symbol naming and visibility
306 # issues that the current splitting scheme doesn't account for.
308 # For now, also do not enable multi-threaded translation when TARGET_OS !=
309 # 'nacl', since in these cases we will be using the host toolchain's
312 # The x86->arm emulator is very flaky when threading is used, so don't
313 # do module splitting when using it.
314 env.set('SPLIT_MODULE', '1')
316 modules = env.getone('SPLIT_MODULE')
318 env.append('LLC_FLAGS_EXTRA', '-split-module=' + modules)
319 env.append('LD_FLAGS', '-split-module=' + modules)
320 if not env.getbool('SANDBOXED') and env.getbool('STREAM_BITCODE'):
321 # Do not set -streaming-bitcode for sandboxed mode, because it is already
322 # in the default command line.
323 env.append('LLC_FLAGS_EXTRA', '-streaming-bitcode')
325 # If there's a bitcode file, translate it now.
326 tng = driver_tools.TempNameGen(inputs + bcfiles, output)
327 output_type = env.getone('OUTPUT_TYPE')
330 if output_type == 's':
334 if output_type == 'o':
336 elif output_type != 's':
337 ofile = tng.TempNameForInput(bcfile, 'o')
340 RunLLC(bcfile, sfile, outfiletype='asm')
344 RunLLC(bcfile, ofile, outfiletype='obj')
348 # If we've been told to stop after translation, stop now.
349 if output_type in ('o','s'):
352 # Replace the bitcode file with __BITCODE__ in the input list
354 inputs = ListReplace(inputs, bcfile, '__BITCODE__')
355 env.set('INPUTS', *inputs)
356 if int(env.getone('SPLIT_MODULE')) > 1:
357 modules = int(env.getone('SPLIT_MODULE'))
358 for i in range(1, modules):
359 filename = ofile + '.module%d' % i
360 TempFiles.add(filename)
361 env.append('INPUTS', filename)
363 if env.getone('TARGET_OS') != 'nacl':
364 RunHostLD(ofile, output)
369 def RunAS(infile, outfile):
370 driver_tools.RunDriver('as', [infile, '-o', outfile])
372 def ListReplace(items, old, new):
381 def RunLD(infile, outfile):
382 inputs = env.get('INPUTS')
384 # Put llc-translated-file at the beginning of the inputs so that it will
385 # pull in all needed symbols from any native archives that may also be
386 # in the input list. This is in case there are any mixed groups of bitcode
387 # and native archives in the link (as is the case with irt_browser_lib)
388 inputs.remove('__BITCODE__')
389 inputs = ['--llc-translated-file=' + infile] + inputs
390 env.set('ld_inputs', *inputs)
391 args = env.get('LD_ARGS') + ['-o', outfile]
392 if env.getbool('USE_STDLIB'):
393 args += env.get('LD_ARGS_ENTRY')
394 args += env.get('LD_FLAGS')
395 driver_tools.RunDriver('nativeld', args)
397 def RunHostLD(infile, outfile):
398 if env.getone('TARGET_OS') == 'linux':
399 driver_tools.Run(['objcopy', '--redefine-sym', '_start=_user_start',
401 lib_dir = (env.getone('BASE_LIB_NATIVE')
402 + 'x86-32-%s' % env.getone('TARGET_OS'))
403 args = ['gcc', '-m32', infile, '-o', outfile,
404 os.path.join(lib_dir, 'unsandboxed_irt.o'), '-lpthread']
405 if env.getone('TARGET_OS') == 'linux':
406 args.append('-lrt') # For clock_gettime()
407 driver_tools.Run(args)
409 def RunLLC(infile, outfile, outfiletype):
411 env.setmany(input=infile, output=outfile, outfiletype=outfiletype)
412 if env.getbool('SANDBOXED'):
416 args = ["${RUN_LLC}"]
417 if filetype.IsPNaClBitcode(infile):
418 args.append("-bitcode-format=pnacl")
419 elif filetype.IsLLVMBitcode(infile):
420 if not env.getbool('ALLOW_LLVM_BITCODE_INPUT'):
421 Log.Fatal('Translator expects finalized PNaCl bitcode. '
422 'Pass --allow-llvm-bitcode-input to override.')
423 driver_tools.Run(' '.join(args))
427 def RunLLCSandboxed():
428 driver_tools.CheckTranslatorPrerequisites()
429 infile = env.getone('input')
430 outfile = env.getone('output')
431 is_pnacl = filetype.IsPNaClBitcode(infile)
432 if not is_pnacl and not env.getbool('ALLOW_LLVM_BITCODE_INPUT'):
433 Log.Fatal('Translator expects finalized PNaCl bitcode. '
434 'Pass --allow-llvm-bitcode-input to override.')
435 script = MakeSelUniversalScriptForLLC(infile, outfile, is_pnacl)
436 command = ('${SEL_UNIVERSAL_PREFIX} ${SEL_UNIVERSAL} ${SEL_UNIVERSAL_FLAGS} '
438 driver_tools.Run(command,
439 stdin_contents=script,
440 # stdout/stderr will be automatically dumped
442 redirect_stderr=subprocess.PIPE,
443 redirect_stdout=subprocess.PIPE)
445 def BuildOverrideLLCCommandLine(is_pnacl):
446 extra_flags = env.get('LLC_FLAGS_EXTRA')
447 # The mcpu is not part of the default flags, so append that too.
448 mcpu = env.getone('LLC_MCPU')
450 extra_flags.append(mcpu)
452 extra_flags.append('-bitcode-format=llvm')
453 # command_line is a NUL (\x00) terminated sequence.
455 command_line = kTerminator.join(extra_flags) + kTerminator
456 command_line_escaped = command_line.replace(kTerminator, '\\x00')
457 return len(command_line), command_line_escaped
459 def MakeSelUniversalScriptForLLC(infile, outfile, is_pnacl):
461 script.append('readwrite_file objfile %s' % outfile)
462 modules = int(env.getone('SPLIT_MODULE'))
464 script.extend(['readwrite_file objfile%d %s.module%d' % (m, outfile, m)
465 for m in range(1, modules)])
466 stream_rate = int(env.getraw('BITCODE_STREAM_RATE'))
467 assert stream_rate != 0
468 cmdline_len, cmdline_escaped = BuildOverrideLLCCommandLine(is_pnacl)
469 assert modules in range(1, 17)
470 script.append('rpc StreamInitWithSplit i(%d) h(objfile) ' % modules +
471 ' '.join(['h(objfile%d)' % m for m in range(1, modules)] +
472 ['h(invalid)' for x in range(modules, 16)]) +
473 ' C(%d,%s) * s()' % (cmdline_len, cmdline_escaped))
474 # specify filename, chunk size and rate in bits/s
475 script.append('stream_file %s %s %s' % (infile, 64 * 1024, stream_rate))
476 script.append('rpc StreamEnd * i() s() s() s()')
477 script.append('echo "pnacl-llc complete"')
479 return '\n'.join(script)
483 PNaCl bitcode to native code translator.
485 Usage: pnacl-translate [options] -arch <arch> <input> -o <output>
487 <input> Input file (bitcode).
488 -arch <arch> Translate to <arch> (i686, x86-64, armv7).
489 Note: <arch> is a generic arch specifier. This
490 generates code assuming certain baseline CPU features,
491 required by NaCl or Chrome. For finer control of
492 tuning and features, see -mattr, and -mcpu.
493 -o <output> Output file.
495 The default output file type is .nexe, which assumes that the input file
496 type is .pexe. Native object files and assembly can also be generated
497 with the -S and -c commandline flags.
500 -mattr=<+feat1,-feat2> Toggle specific cpu features on and off.
501 -mcpu=<cpu-name> Target a specific cpu type. Tunes code as well as
502 turns cpu features on and off.
503 -S Generate native assembly only.
504 -c Generate native object file only.
505 --pnacl-sb Use the translator which runs inside the NaCl sandbox.
506 -O[0-3] Change translation-time optimization level.