def main(argv): env.update(EXTRA_ENV) ParseArgs(argv, LDPatterns) GetArch(required=True) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if output == '': output = pathtools.normalize('a.out') # Expand all parameters # This resolves -lfoo into actual filenames, # and expands linker scripts into command-line arguments. inputs = ldtools.ExpandInputs(inputs, env.get('SEARCH_DIRS'), env.getbool('STATIC'), ldtools.LibraryTypes.NATIVE) env.push() env.set('inputs', *inputs) env.set('output', output) if env.getbool('SANDBOXED'): RunLDSandboxed() else: Run('${RUN_LD}') env.pop() # only reached in case of no errors return 0
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, PrepPatterns) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) != 1: Log.Fatal('Can only have one input') f_input = inputs[0] # Allow in-place file changes if output isn't specified.. if output != '': f_output = output else: f_output = f_input if env.getbool('DISABLE_FINALIZE') or filetype.IsPNaClBitcode(f_input): # Just copy the input file to the output file. if f_input != f_output: shutil.copyfile(f_input, f_output) return 0 opt_flags = [ '-disable-opt', '-strip', '-strip-metadata', '--bitcode-format=pnacl', f_input, '-o', f_output ] # Transform the file, and convert it to a PNaCl bitcode file. driver_tools.RunDriver('opt', opt_flags) # Compress the result if requested. if env.getbool('COMPRESS'): driver_tools.RunDriver('compress', [f_output]) return 0
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, PrepPatterns) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) != 1: Log.Fatal('Can only have one input') f_input = inputs[0] # Allow in-place file changes if output isn't specified.. if output != '': f_output = output else: f_output = f_input if env.getbool('DISABLE_FINALIZE') or filetype.IsPNaClBitcode(f_input): # Just copy the input file to the output file. if f_input != f_output: shutil.copyfile(f_input, f_output) return 0 opt_flags = ['-disable-opt', '-strip', '-strip-metadata', '--bitcode-format=pnacl', f_input, '-o', f_output] # Transform the file, and convert it to a PNaCl bitcode file. driver_tools.RunDriver('opt', opt_flags) # Compress the result if requested. if env.getbool('COMPRESS'): driver_tools.RunDriver('compress', [f_output]) return 0
def RunTranslate(infile, output, mode): if not env.getbool('ALLOW_TRANSLATE'): Log.Fatal('%s: Trying to convert bitcode to an object file before ' 'bitcode linking. This is supposed to wait until ' 'translation. Use --pnacl-allow-translate to override.', pathtools.touser(infile)) args = env.get('TRANSLATE_FLAGS') + [mode, infile, '-o', output] if env.getbool('PIC'): args += ['-fPIC'] RunDriver('translate', args)
def SetUpArch(): base_arch = env.getone('BASE_ARCH') env.set('TARGET_OS', 'nacl') if base_arch.endswith('_LINUX'): base_arch = base_arch[:-len('_LINUX')] env.set('TARGET_OS', 'linux') elif base_arch.endswith('_MAC'): base_arch = base_arch[:-len('_MAC')] env.set('TARGET_OS', 'mac') if env.getbool('NONSFI_NACL'): triple_map = { 'nacl': {'X8632': 'i686-linux-gnu', 'ARM': 'armv7a-linux-gnueabihf'}} else: triple_map = { 'nacl': {'X8632': 'i686-none-nacl-gnu', 'X8664': 'x86_64-none-nacl-gnu', 'ARM': 'armv7a-none-nacl-gnueabihf', 'MIPS32': 'mipsel-none-nacl-gnu'}, 'linux': {'X8632': 'i686-linux-gnu'}, 'mac': {'X8632': 'i686-apple-darwin'}} env.set('TRIPLE', triple_map[env.getone('TARGET_OS')][base_arch]) # CPU that is representative of baseline feature requirements for NaCl # and/or chrome. We may want to make this more like "-mtune" # by specifying both "-mcpu=X" and "-mattr=+feat1,-feat2,...". # Note: this may be different from the in-browser translator, which may # do auto feature detection based on CPUID, but constrained by what is # accepted by NaCl validators. cpu_map = { 'X8632': 'pentium4', 'X8664': 'core2', 'ARM': 'cortex-a9', 'MIPS32': 'mips32r2'} env.set('LLC_MCPU', '-mcpu=%s' % cpu_map[base_arch]) llc_flags_map = { 'ARM': ['-arm-reserve-r9', '-sfi-disable-cp', '-sfi-load', '-sfi-store', '-sfi-stack', '-sfi-branch', '-sfi-data', '-no-inline-jumptables', '-float-abi=hard', '-mattr=+neon'], # Once PNaCl's build of compiler-rt (libgcc.a) defines __aeabi_* # functions, we can drop the following ad-hoc option. 'ARM_NONSFI': ['-arm-enable-aeabi-functions=0'], 'MIPS32': ['-sfi-load', '-sfi-store', '-sfi-stack', '-sfi-branch', '-sfi-data']} env.set('LLC_FLAGS_ARCH', *llc_flags_map.get(env.getone('ARCH'), [])) # When linking against a host OS's libc (such as Linux glibc), don't # use %gs:0 to read the thread pointer because that won't be # compatible with the libc's use of %gs:0. Similarly, Non-SFI Mode # currently offers no optimized path for reading the thread pointer. if env.getone('TARGET_OS') != 'nacl' or env.getbool('NONSFI_NACL'): env.append('LLC_FLAGS_ARCH', '-mtls-use-call')
def main(argv): env.update(EXTRA_ENV) ParseArgs(argv, LDPatterns) GetArch(required=True) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if output == '': output = pathtools.normalize('a.out') # As we will modify the output file in-place for non-SFI, we output # the file to a temporary file first and then rename it. Otherwise, # build systems such as make assume the output file is ready even # if the last build failed during the in-place update. tmp_output = output + '.tmp' # Expand all parameters # This resolves -lfoo into actual filenames, # and expands linker scripts into command-line arguments. inputs = ldtools.ExpandInputs(inputs, env.get('SEARCH_DIRS'), True, ldtools.LibraryTypes.NATIVE) env.push() env.set('inputs', *inputs) env.set('output', tmp_output) if env.getbool('SANDBOXED'): RunLDSandboxed() else: Run('${RUN_LD}') if env.getbool('NONSFI_NACL'): # Remove PT_INTERP in non-SFI binaries as we never use host's # dynamic linker/loader. # # This is necessary otherwise we get a statically linked # executable that is not directly runnable by Linux, because Linux # tries to load the non-existent file that PT_INTERP points to. # # This is fairly hacky. It would be better if the linker provided # an option for omitting PT_INTERP (e.g. "--dynamic-linker ''"). RemoveInterpProgramHeader(tmp_output) if driver_tools.IsWindowsPython() and os.path.exists(output): # On Windows (but not on Unix), the os.rename() call would fail if the # output file already exists. os.remove(output) os.rename(tmp_output, output) env.pop() # only reached in case of no errors return 0
def RunTranslate(infile, output, mode): if not env.getbool("ALLOW_TRANSLATE"): Log.Fatal( "%s: Trying to convert bitcode to an object file before " "bitcode linking. This is supposed to wait until " "translation. Use --pnacl-allow-translate to override.", pathtools.touser(infile), ) args = env.get("TRANSLATE_FLAGS") + [mode, infile, "-o", output] if env.getbool("PIC"): args += ["-fPIC"] RunDriver("translate", args)
def RunLD(infile, outfile): inputs = env.get('INPUTS') if infile: inputs = ListReplace(inputs, '__BITCODE__', '--llc-translated-file=' + infile) ToggleDefaultCommandlineLD(inputs, infile) env.set('ld_inputs', *inputs) args = env.get('LD_ARGS') + ['-o', outfile] if not env.getbool('SHARED') and env.getbool('STDLIB'): args += env.get('LD_ARGS_ENTRY') args += env.get('LD_FLAGS') driver_tools.RunDriver('nativeld', args)
def RunLD(infile, outfile): inputs = env.get("INPUTS") if infile: inputs = ListReplace(inputs, "__BITCODE__", "--llc-translated-file=" + infile) ToggleDefaultCommandlineLD(inputs, infile) env.set("ld_inputs", *inputs) args = env.get("LD_ARGS") + ["-o", outfile] if not env.getbool("SHARED") and env.getbool("STDLIB"): args += env.get("LD_ARGS_ENTRY") args += env.get("LD_FLAGS") # If there is bitcode, there is also a metadata file. if infile and env.getbool("USE_META"): args += ["--metadata", "%s.meta" % infile] driver_tools.RunDriver("nativeld", args)
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, PATTERNS) # Binary output may go to stdout (when -o was not specified) driver_tools.Run('"${LLVM_OPT}" ${ARGS} ${HAVE_OUTPUT ? -o ${OUTPUT}}') if env.getbool('DO_WRAP'): if not env.getbool('HAVE_OUTPUT'): Log.Error("unable to wrap pexe on stdout, use: --do-no-wrap flag") else: driver_tools.WrapBitcode(env.getone('OUTPUT')) # only reached in case of no errors return 0
def RunLLC(infile, outfile, filetype): env.push() env.setmany(input=infile, output=outfile, filetype=filetype) if env.getbool('SANDBOXED'): is_shared, soname, needed = RunLLCSandboxed() env.pop() # soname and dt_needed libs are returned from LLC and passed to LD driver_tools.SetBitcodeMetadata(infile, is_shared, soname, needed) else: driver_tools.Run("${RUN_LLC}") # As a side effect, this creates a temporary file if not env.getbool('SAVE_TEMPS'): TempFiles.add(outfile + '.meta') env.pop() return 0
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, PrepPatterns) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) != 1: Log.Fatal('Can only have one input') f_input = inputs[0] # Allow in-place file changes if output isn't specified.. if output != '': f_output = output else: f_output = f_input if env.getbool('DISABLE_FINALIZE'): # Just copy the input file to the output file. if f_input != f_output: shutil.copyfile(f_input, f_output) return 0 # Transform the file, and convert it to a PNaCl bitcode file. driver_tools.RunWithEnv(' '.join(['${RUN_OPT}', '--bitcode-format=pnacl']), input=inputs[0], output=f_output) return 0
def RunCompiler(infile, outfile, outfiletype, use_sz): env.push() env.setmany(input=infile, output=outfile, outfiletype=outfiletype) if env.getbool('SANDBOXED'): RunSandboxedCompiler(use_sz) else: args = ["${RUN_SZ}" if use_sz else "${RUN_LLC}"] if filetype.IsPNaClBitcode(infile): args.append("-bitcode-format=pnacl") elif filetype.IsLLVMBitcode(infile): if not env.getbool('ALLOW_LLVM_BITCODE_INPUT'): Log.Fatal('Translator expects finalized PNaCl bitcode. ' 'Pass --allow-llvm-bitcode-input to override.') driver_tools.Run(' '.join(args)) env.pop() return 0
def RunSandboxedCompiler(use_sz): driver_tools.CheckTranslatorPrerequisites() infile = env.getone('input') is_pnacl = filetype.IsPNaClBitcode(infile) if not is_pnacl and not env.getbool('ALLOW_LLVM_BITCODE_INPUT'): Log.Fatal('Translator expects finalized PNaCl bitcode. ' 'Pass --allow-llvm-bitcode-input to override.') threads = int(env.getone('SPLIT_MODULE')) command = [driver_tools.SelLdrCommand(), '-a', # Allow file access '-E NACL_IRT_PNACL_TRANSLATOR_COMPILE_INPUT=%s' % infile] driver_tools.AddListToEnv(command, 'NACL_IRT_PNACL_TRANSLATOR_COMPILE_OUTPUT', GetObjectFiles(use_sz)) driver_tools.AddListToEnv(command, 'NACL_IRT_PNACL_TRANSLATOR_COMPILE_ARG', BuildOverrideCompilerCommandLine(is_pnacl, use_sz)) command.extend(['-E NACL_IRT_PNACL_TRANSLATOR_COMPILE_THREADS=%d' % threads, '--']) if use_sz: command.append('${PNACL_SZ_SB}') else: command.append('${LLC_SB}') driver_tools.Run(' '.join(command), # stdout/stderr will be automatically dumped # upon failure redirect_stderr=subprocess.PIPE, redirect_stdout=subprocess.PIPE)
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, StripPatterns) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) > 1 and output != '': Log.Fatal('Cannot have -o with multiple inputs') if '--info' in env.get('STRIP_FLAGS'): code, _, _ = driver_tools.Run('${STRIP} ${STRIP_FLAGS}') return code for f in inputs: if output != '': f_output = output else: f_output = f if driver_tools.IsBitcode(f): driver_tools.RunWithEnv('${RUN_OPT}', input=f, output=f_output) if env.getbool('DO_WRAP'): driver_tools.WrapBitcode(f_output) elif driver_tools.IsELF(f) or driver_tools.IsNativeArchive(f): driver_tools.RunWithEnv('${RUN_STRIP}', input=f, output=f_output) elif driver_tools.IsBitcodeArchive(f): # The strip tool supports native archives, but it does not support the # LLVM gold plugin so cannot handle bitcode. There is also no bitcode # tool like opt that support archives. Log.Fatal('%s: strip does not support bitcode archives', pathtools.touser(f)) else: Log.Fatal('%s: File is neither ELF, nor bitcode', pathtools.touser(f)) return 0
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, StripPatterns) inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) > 1 and output != '': Log.Fatal('Cannot have -o with multiple inputs') if '--info' in env.get('STRIP_FLAGS'): code, _, _ = driver_tools.Run('${STRIP} ${STRIP_FLAGS}') return code for f in inputs: if output != '': f_output = output else: f_output = f if driver_tools.IsBitcode(f): driver_tools.RunWithEnv('${RUN_OPT}', input=f, output=f_output) if env.getbool('DO_WRAP'): driver_tools.WrapBitcode(f_output) elif driver_tools.IsELF(f): driver_tools.RunWithEnv('${RUN_STRIP}', input=f, output=f_output) else: Log.Fatal('%s: File is neither ELF nor bitcode', pathtools.touser(f)) return 0
def RunLD(infile, outfile): inputs = env.get('INPUTS') if infile: # Put llc-translated-file at the beginning of the inputs so that it will # pull in all needed symbols from any native archives that may also be # in the input list. This is in case there are any mixed groups of bitcode # and native archives in the link (as is the case with irt_browser_lib) inputs.remove('__BITCODE__') inputs = ['--llc-translated-file=' + infile] + inputs ToggleDefaultCommandlineLD(inputs, infile) env.set('ld_inputs', *inputs) args = env.get('LD_ARGS') + ['-o', outfile] if not env.getbool('SHARED') and env.getbool('USE_STDLIB'): args += env.get('LD_ARGS_ENTRY') args += env.get('LD_FLAGS') driver_tools.RunDriver('nativeld', args)
def RunLD(infile, outfile): inputs = env.get('INPUTS') if infile: inputs = ListReplace(inputs, '__BITCODE__', '--llc-translated-file=' + infile) ToggleDefaultCommandlineLD(inputs, infile) env.set('ld_inputs', *inputs) args = env.get('LD_ARGS') + ['-o', outfile] if not env.getbool('SHARED') and env.getbool('STDLIB'): args += env.get('LD_ARGS_ENTRY') args += env.get('LD_FLAGS') # If there is bitcode, there is also a metadata file. if infile and env.getbool('USE_META'): args += ['--metadata', '%s.meta' % infile] driver_tools.RunDriver('nativeld', args)
def AddUrlForAllArches(json_dict, shortname): KNOWN_NMF_ARCHES = ['x86-32', 'x86-64', 'arm'] for arch in KNOWN_NMF_ARCHES: json_dict[arch] = {} if env.getbool('FLAT_URL_SCHEME'): json_dict[arch]['url'] = '%s' % shortname else: json_dict[arch]['url'] = 'lib-%s/%s' % (arch, shortname)
def MakeSelUniversalScriptForLD(ld_flags, main_input, files, outfile): """ Return sel_universal script text for invoking LD.nexe with the given ld_flags, main_input (which is treated specially), and other input files. The output will be written to outfile. """ script = [] # Open the output file. script.append('readwrite_file nexefile %s' % outfile) # Need to include the linker script file as a linker resource for glibc. files_to_map = list(files) use_default = env.getbool('USE_DEFAULT_CMD_LINE') # Create a mapping for each input file and add it to the command line. for f in files_to_map: basename = pathtools.basename(f) # If we are using the dummy shim, map it with the filename of the real # shim, so the baked-in commandline will work if basename == 'libpnacl_irt_shim_dummy.a' and use_default: basename = 'libpnacl_irt_shim.a' script.append('reverse_service_add_manifest_mapping files/%s %s' % (basename, f)) if use_default: # Assume static linking for now. soname = '' needed = '' is_shared_library = 0 script.append('readonly_file objfile %s' % main_input) script.append(('rpc RunWithDefaultCommandLine ' + 'h(objfile) h(nexefile) i(%d) s("%s") s("%s") *' % (is_shared_library, soname, needed))) else: # Join all the arguments. # Based on the format of RUN_LD, the order of arguments is: # ld_flags, then input files (which are more sensitive to order). # For the sandboxed build, we don't want "real" filesystem paths, # because we use the reverse-service to do a lookup -- make sure # everything is a basename first. ld_flags = [ pathtools.basename(flag) for flag in ld_flags ] kTerminator = '\0' command_line = kTerminator.join(['ld'] + ld_flags) + kTerminator for f in files: basename = pathtools.basename(f) command_line = command_line + basename + kTerminator command_line_escaped = command_line.replace(kTerminator, '\\x00') # Assume that the commandline captures all necessary metadata for now. script.append('rpc Run h(nexefile) C(%d,%s) *' % (len(command_line), command_line_escaped)) script.append('echo "ld complete"') script.append('') return '\n'.join(script)
def main(argv): env.update(EXTRA_ENV) driver_tools.ParseArgs(argv, PrepPatterns) inputs = env.get("INPUTS") output = env.getone("OUTPUT") for path in inputs + [output]: driver_tools.CheckPathLength(path) if len(inputs) != 1: Log.Fatal("Can only have one input") f_input = inputs[0] # Allow in-place file changes if output isn't specified.. if output != "": f_output = output else: f_output = f_input if env.getbool("DISABLE_FINALIZE") or filetype.IsPNaClBitcode(f_input): # Just copy the input file to the output file. if f_input != f_output: shutil.copyfile(f_input, f_output) return 0 opt_flags = [ "-disable-opt", "-strip-metadata", "-strip-module-flags", "--bitcode-format=pnacl", f_input, "-o", f_output, ] if env.getbool("DISABLE_STRIP_SYMS"): opt_flags += ["-strip-debug"] else: opt_flags += ["-strip"] # Transform the file, and convert it to a PNaCl bitcode file. driver_tools.RunDriver("pnacl-opt", opt_flags) # Compress the result if requested. if env.getbool("COMPRESS"): driver_tools.RunDriver("pnacl-compress", [f_output]) return 0
def UseDefaultCommandlineLLC(): if not env.getbool('USE_DEFAULT_CMD_LINE'): return False else: reason, non_standard = RequiresNonStandardLLCCommandline() if non_standard: Log.Info(reason + ' -- not using default SRPC commandline for LLC!') return False return True
def RequiresNonStandardLDCommandline(inputs, infile): """ Determine when we must force USE_DEFAULT_CMD_LINE off for running the sandboxed LD (if link line is completely non-standard). """ if len(inputs) > 1: # There must have been some native objects on the link line. # In that case, if we are using the sandboxed translator, we cannot # currently allow that with the default commandline (only one input). return ("Native link with more than one native object: %s" % str(inputs), True) if not infile: return ("No bitcode input: %s" % str(infile), True) if not env.getbool("STDLIB"): return ("NOSTDLIB", True) if not env.getbool("USE_IRT"): return ("USE_IRT false when normally true", True) if not env.getbool("SHARED") and not env.getbool("USE_IRT_SHIM"): return ("USE_IRT_SHIM false when normally true", True) return (None, False)
def RequiresNonStandardLLCCommandline(): if env.getbool('FAST_TRANSLATION'): return ('FAST_TRANSLATION', True) extra_flags = env.get('LLC_FLAGS_EXTRA') if extra_flags != []: reason = 'Has additional llc flags: %s' % extra_flags return (reason, True) return (None, False)
def RunLLC(infile, outfile, outfiletype): env.push() env.setmany(input=infile, output=outfile, outfiletype=outfiletype) if env.getbool('SANDBOXED'): is_shared, soname, needed = RunLLCSandboxed() # Ignore is_shared, soname, and needed for now, since we aren't # dealing with bitcode shared libraries. env.pop() else: args = ["${RUN_LLC}"] if filetype.IsPNaClBitcode(infile): args.append("-bitcode-format=pnacl") elif filetype.IsLLVMBitcode(infile): if not env.getbool('ALLOW_LLVM_BITCODE_INPUT'): Log.Fatal('Translator expects finalized PNaCl bitcode. ' 'Pass --allow-llvm-bitcode-input to override.') driver_tools.Run(' '.join(args)) env.pop() return 0
def RemoveNativeStdLibs(objs): # For newlib, all standard libraries are already bitcode. if env.getbool('LIBMODE_NEWLIB'): return objs # GLibC standard libraries defaultlibs = ['libc_nonshared.a', 'libpthread_nonshared.a', 'libc.a', 'libstdc++.a', 'libgcc.a', 'libgcc_eh.a', 'libm.a'] return [f for f in objs if pathtools.split(f)[1] not in defaultlibs]
def RequiresNonStandardLLCCommandline(): if env.getbool("FAST_TRANSLATION"): return ("FAST_TRANSLATION", True) extra_flags = env.get("LLC_FLAGS_EXTRA") if extra_flags != []: reason = "Has additional llc flags: %s" % extra_flags return (reason, True) return (None, False)
def Run(args, errexit=True, redirect_stdout=None, redirect_stderr=None): """ Run: Run a command. Returns: return_code, stdout, stderr Run() is used to invoke "other" tools, e.g. those NOT prefixed with "pnacl-" stdout and stderr only contain meaningful data if redirect_{stdout,stderr} == subprocess.PIPE Run will terminate the program upon failure unless errexit == False TODO(robertm): errexit == True has not been tested and needs more work redirect_stdout and redirect_stderr are passed straight to subprocess.Popen """ result_stdout = None result_stderr = None if isinstance(args, str): args = shell.split(env.eval(args)) args = [pathtools.tosys(args[0])] + args[1:] Log.Info('Running: ' + StringifyCommand(args)) if env.getbool('DRY_RUN'): if redirect_stderr or redirect_stdout: # TODO(pdox): Prevent this from happening, so that # dry-run is more useful. Log.Fatal("Unhandled dry-run case.") return 0, None, None try: # If we have too long of a cmdline on windows, running it would fail. # Attempt to use a file with the command line options instead in that case. if ArgsTooLongForWindows(args): actual_args = ConvertArgsToFile(args) Log.Info('Wrote long commandline to file for Windows: ' + StringifyCommand(actual_args)) else: actual_args = args p = subprocess.Popen(actual_args, stdout=redirect_stdout, stderr=redirect_stderr) result_stdout, result_stderr = p.communicate() except Exception, e: msg = '%s\nCommand was: %s' % (str(e), StringifyCommand(args)) print(msg) DriverExit(1)
def Run(args, errexit=True, redirect_stdout=None, redirect_stderr=None): """ Run: Run a command. Returns: return_code, stdout, stderr Run() is used to invoke "other" tools, e.g. those NOT prefixed with "pnacl-" stdout and stderr only contain meaningful data if redirect_{stdout,stderr} == subprocess.PIPE Run will terminate the program upon failure unless errexit == False TODO(robertm): errexit == True has not been tested and needs more work redirect_stdout and redirect_stderr are passed straight to subprocess.Popen """ result_stdout = None result_stderr = None if isinstance(args, str): args = shell.split(env.eval(args)) args = [pathtools.tosys(args[0])] + args[1:] Log.Info('Running: ' + StringifyCommand(args)) if env.getbool('DRY_RUN'): if redirect_stderr or redirect_stdout: # TODO(pdox): Prevent this from happening, so that # dry-run is more useful. Log.Fatal("Unhandled dry-run case.") return 0, None, None try: # If we have too long of a cmdline on windows, running it would fail. # Attempt to use a file with the command line options instead in that case. if ArgsTooLongForWindows(args): actual_args = ConvertArgsToFile(args) Log.Info('Wrote long commandline to file for Windows: ' + StringifyCommand(actual_args)) else: actual_args = args p = subprocess.Popen(actual_args, stdout=redirect_stdout, stderr=redirect_stderr) result_stdout, result_stderr = p.communicate() except Exception, e: msg = '%s\nCommand was: %s' % (str(e), StringifyCommand(args)) print msg DriverExit(1)
def SetUpLinkOptions(): if env.getbool('TRANSLATE_PSO'): # Using "-pie" rather than "-shared" has the effect of suppressing the # creation of a PLT and R_*_JUMP_SLOT relocations, which come from the # external symbol references that multi-threaded translation produces. env.append('LD_FLAGS', '-pie') return if env.getbool('NONSFI_NACL'): # "_begin" allows a PIE to find its load address in order to apply # dynamic relocations. env.append('LD_FLAGS', '-defsym=_begin=0') env.append('LD_FLAGS', '-pie') else: env.append('LD_FLAGS', '-static') # Give non-IRT builds 12MB of text before starting rodata instead of # the larger default gap. The gap cannot be too small (e.g., 0) because # sel_ldr requires space for adding a halt sled. if not env.getbool('USE_IRT'): env.append('LD_FLAGS', '--rosegment-gap=0xc00000')
def TempNameForInput(self, input, imtype): fullpath = pathtools.abspath(input) # If input is already a temporary name, just change the extension if fullpath.startswith(self.TempBase): temp = self.TempBase + '.' + imtype else: # Source file temp = self.TempMap[fullpath] + '.' + imtype if not env.getbool('SAVE_TEMPS'): TempFiles.add(temp) return temp
def RequiresNonStandardLDCommandline(inputs, infile): ''' Determine when we must force USE_DEFAULT_CMD_LINE off for running the sandboxed LD (if link line is completely non-standard). ''' if len(inputs) > 1: # There must have been some native objects on the link line. # In that case, if we are using the sandboxed translator, we cannot # currently allow that with the default commandline (only one input). return ('Native link with more than one native object: %s' % str(inputs), True) if not infile: return ('No bitcode input: %s' % str(infile), True) if not env.getbool('USE_STDLIB'): return ('NOSTDLIB', True) if env.getbool('ALLOW_ZEROCOST_CXX_EH'): return ('ALLOW_ZEROCOST_CXX_EH', True) if not env.getbool('USE_IRT'): return ('USE_IRT false when normally true', True) if not env.getbool('USE_IRT_SHIM'): return ('USE_IRT_SHIM false when normally true', True) return (None, False)
def RequiresNonStandardLDCommandline(inputs, infile): ''' Determine when we must force USE_DEFAULT_CMD_LINE off for running the sandboxed LD (if link line is completely non-standard). ''' if len(inputs) > 1: # There must have been some native objects on the link line. # In that case, if we are using the sandboxed translator, we cannot # currently allow that with the default commandline (only one input). return ('Native link with more than one native object: %s' % str(inputs), True) if not infile: return ('No bitcode input: %s' % str(infile), True) if not env.getbool('USE_STDLIB'): return ('NOSTDLIB', True) if env.getbool('ALLOW_CXX_EXCEPTIONS'): return ('ALLOW_CXX_EXCEPTIONS', True) if not env.getbool('USE_IRT'): return ('USE_IRT false when normally true', True) if not env.getbool('USE_IRT_SHIM'): return ('USE_IRT_SHIM false when normally true', True) return (None, False)
def CheckTranslatorPrerequisites(): """ Assert that the scons artifacts for running the sandboxed translator exist: sel_ldr, and the IRT blob. """ if env.getbool('DRY_RUN'): return reqs = ['SEL_LDR', 'IRT_BLOB'] # Linux also requires the nacl bootstrap helper. if GetBuildOS() == 'linux': reqs.append('BOOTSTRAP_LDR') for var in reqs: needed_file = env.getone(var) if not pathtools.exists(needed_file): Log.Fatal('Could not find %s [%s]', var, needed_file)
def CheckTranslatorPrerequisites(): """ Assert that the scons artifacts for running the sandboxed translator exist: sel_universal, and sel_ldr. """ if env.getbool('DRY_RUN'): return reqs = ['SEL_UNIVERSAL', 'SEL_LDR'] # Linux also requires the nacl bootstrap helper. if GetBuildOS() == 'linux': reqs.append('BOOTSTRAP_LDR') for var in reqs: needed_file = env.getone(var) if not pathtools.exists(needed_file): Log.Fatal('Could not find %s [%s]', var, needed_file)
def SetUpLinkOptions(): if env.getbool('NONSFI_NACL'): # "_begin" allows a PIE to find its load address in order to apply # dynamic relocations. env.append('LD_FLAGS', '-defsym=_begin=0') if env.getbool('USE_IRT'): env.append('LD_FLAGS', '-pie') else: # Note that we really want to use "-pie" for this case, but it # currently adds a PT_INTERP header to the executable that we don't # want because it stops the executable from being loadable by Linux. # TODO(mseaborn): Add a linker option to omit PT_INTERP. env.append('LD_FLAGS', '-static') # Set _DYNAMIC to a dummy value. TODO(mseaborn): Remove this when we # use "-pie" instead of "-static" for this case. env.append('LD_FLAGS', '-defsym=_DYNAMIC=1') else: env.append('LD_FLAGS', '-static') # Give non-IRT builds 12MB of text before starting rodata instead of # the larger default gap. The gap cannot be too small (e.g., 0) because # sel_ldr requires space for adding a halt sled. if not env.getbool('USE_IRT'): env.append('LD_FLAGS', '--rosegment-gap=0xc00000')
def RunLLC(infile, outfile, filetype): env.push() env.setmany(input=infile, output=outfile, filetype=filetype) if env.getbool('SANDBOXED'): is_shared, soname, needed = RunLLCSandboxed() env.pop() # soname and dt_needed libs are returned from LLC and passed to LD driver_tools.SetBitcodeMetadata(infile, is_shared, soname, needed) else: args = ["${RUN_LLC}"] if driver_tools.IsPNaClBitcode(infile): args.append("-bitcode-format=pnacl") driver_tools.Run(' '.join(args)) env.pop() return 0
def SetStdLib(*args): """Set the C++ Standard Library.""" lib = args[0] assert lib == 'libc++' or lib == 'libstdc++', ( 'Invalid C++ standard library: -stdlib=%s' % lib) env.set('STDLIB', lib) env.set('STDLIB_TRUNC', lib[3:]) if lib == 'libc++': env.set('STDLIB_IDIR', 'v1') if env.getbool('IS_CXX'): # libc++ depends on pthread for C++11 features as well as some # exception handling (which may get removed later by the PNaCl ABI # simplification) and initialize-once. env.set('PTHREAD', '1') elif lib == 'libstdc++': env.set('STDLIB_IDIR', '4.6.2')
def DriverOutputTypes(driver_flag, compiling_to_native): if env.getbool('SHARED'): bclink_output = 'pso' link_output = 'so' else: bclink_output = 'pexe' link_output = 'nexe' output_type_map = { ('-E', False) : 'pp', ('-E', True) : 'pp', ('-c', False) : 'po', ('-c', True) : 'o', ('-S', False) : 'll', ('-S', True) : 's', ('', False) : bclink_output, ('', True) : link_output } return output_type_map[(driver_flag, compiling_to_native)]
def ApplyBitcodeConfig(metadata, bctype): # Read the bitcode metadata to extract library # dependencies and SOName. # For now, we use LD_FLAGS to convey the information. # However, if the metadata becomes richer we will need another mechanism. # TODO(jvoung): at least grep out the SRPC output from LLC and transmit # that directly to LD to avoid issues with mismatching delimiters. for needed in metadata['NeedsLibrary']: env.append('LD_FLAGS', '--add-extra-dt-needed=' + needed) if bctype == 'pso': soname = metadata['SOName'] if soname: env.append('LD_FLAGS', '-soname=' + soname) # For the current LD final linker, native libraries still need to be # linked directly, since --add-extra-dt-needed isn't enough. # BUG= http://code.google.com/p/nativeclient/issues/detail?id=2451 # For the under-construction gold final linker, it expects to have # the needed libraries on the commandline as "-llib1 -llib2", which actually # refer to the stub metadata file. for needed in metadata['NeedsLibrary']: # Specify the ld-nacl-${arch}.so as the --dynamic-linker to set PT_INTERP. # Also, the original libc.so linker script had it listed as --as-needed, # so let's do that. if needed.startswith('ld-nacl-'): env.append('NEEDED_LIBRARIES', '--dynamic-linker=' + needed) env.append( 'NEEDED_LIBRARIES', '--as-needed', # We normally would have a symlink between # ld-2.9 <-> ld-nacl-${arch}.so, but our native lib directory # has no symlinks (to make windows + cygwin happy). # Link to ld-2.9.so instead for now. '-l:ld-2.9.so', '--no-as-needed') else: env.append('NEEDED_LIBRARIES', '-l:' + needed) # libc and libpthread may need the nonshared components too. # Normally these are enclosed in --start-group and --end-group... if not env.getbool('NEWLIB_SHARED_EXPERIMENT'): if needed.startswith('libc.so'): env.append('NEEDED_LIBRARIES', '-l:libc_nonshared.a') elif needed.startswith('libpthread.so'): env.append('NEEDED_LIBRARIES', '-l:libpthread_nonshared.a')
def RunLLCSandboxed(): driver_tools.CheckTranslatorPrerequisites() infile = env.getone('input') outfile = env.getone('output') is_pnacl = filetype.IsPNaClBitcode(infile) if not is_pnacl and not env.getbool('ALLOW_LLVM_BITCODE_INPUT'): Log.Fatal('Translator expects finalized PNaCl bitcode. ' 'Pass --allow-llvm-bitcode-input to override.') script = MakeSelUniversalScriptForLLC(infile, outfile, is_pnacl) command = ( '${SEL_UNIVERSAL_PREFIX} ${SEL_UNIVERSAL} ${SEL_UNIVERSAL_FLAGS} ' '-- ${LLC_SB}') driver_tools.Run( command, stdin_contents=script, # stdout/stderr will be automatically dumped # upon failure redirect_stderr=subprocess.PIPE, redirect_stdout=subprocess.PIPE)
def BuildSharedLib(): # Shared libs must be built PIC Env.set('GENERATE_PIC', '1') inputs = Env.get('INPUTS') if len(inputs) == 0: Log.Fatal('No input specified.') if not Env.getbool('GENERATE_PIC'): Log.Fatal('Shared libs must be build in pic mode. Use -fPIC') if Env.getone('SONAME_FLAG') == '': Log.Fatal('Shared libs must be given a soname.') pso_command = ProcessBuildCommand(BUILD_COMMAND_PSO_FROM_BC) DumpCommand("@bc->pso", pso_command) # suppress_arch is needed to prevent clang to inherit the # -arch argument driver_tools.RunDriver('clang', pso_command, suppress_arch=True) so_command = ProcessBuildCommand(BUILD_COMMAND_SO_FROM_PSO) DumpCommand("@pso->so", so_command) driver_tools.RunDriver('translate', so_command)
def RunLDSandboxed(): if not env.getbool('USE_STDLIB'): Log.Fatal('-nostdlib is not supported by the sandboxed translator') CheckTranslatorPrerequisites() # The "main" input file is the application's combined object file. all_inputs = env.get('inputs') main_input = env.getone('LLC_TRANSLATED_FILE') if not main_input: Log.Fatal("Sandboxed LD requires one shm input file") outfile = env.getone('output') modules = int(env.getone('SPLIT_MODULE')) assert modules >= 1 first_mainfile = all_inputs.index(main_input) first_extra = all_inputs.index(main_input) + modules # Have a list of just the split module files. llc_outputs = all_inputs[first_mainfile:first_extra] # Have a list of everything else. other_inputs = all_inputs[:first_mainfile] + all_inputs[first_extra:] native_libs_dirname = pathtools.tosys(GetNativeLibsDirname(other_inputs)) command = [driver_tools.SelLdrCommand(), '-a'] # Allow file access driver_tools.AddListToEnv(command, 'NACL_IRT_PNACL_TRANSLATOR_LINK_INPUT', llc_outputs) command.extend([ '-E', 'NACL_IRT_PNACL_TRANSLATOR_LINK_OUTPUT=%s ' % outfile, '-E', 'NACL_IRT_OPEN_RESOURCE_BASE=%s' % native_libs_dirname, '-E', 'NACL_IRT_OPEN_RESOURCE_REMAP=%s' % 'libpnacl_irt_shim.a:libpnacl_irt_shim_dummy.a', '--', '${LD_SB}' ]) Run( ' '.join(command), # stdout/stderr will be automatically dumped # upon failure redirect_stderr=subprocess.PIPE, redirect_stdout=subprocess.PIPE)
def RunLDSandboxed(): if not env.getbool('USE_STDLIB'): Log.Fatal('-nostdlib is not supported by the sandboxed translator') CheckTranslatorPrerequisites() # The "main" input file is the application's combined object file. all_inputs = env.get('inputs') main_input = env.getone('LLC_TRANSLATED_FILE') if not main_input: Log.Fatal("Sandboxed LD requires one shm input file") outfile = env.getone('output') modules = int(env.getone('SPLIT_MODULE')) if modules > 1: first_mainfile = all_inputs.index(main_input) first_extra = all_inputs.index(main_input) + modules # Just the split module files llc_outputs = all_inputs[first_mainfile:first_extra] # everything else all_inputs = all_inputs[:first_mainfile] + all_inputs[first_extra:] else: llc_outputs = [main_input] files = LinkerFiles(all_inputs) ld_flags = env.get('LD_FLAGS') script = MakeSelUniversalScriptForLD(ld_flags, llc_outputs, files, outfile) Run( '${SEL_UNIVERSAL_PREFIX} ${SEL_UNIVERSAL} ' + '${SEL_UNIVERSAL_FLAGS} -- ${LD_SB}', stdin_contents=script, # stdout/stderr will be automatically dumped # upon failure redirect_stderr=subprocess.PIPE, redirect_stdout=subprocess.PIPE)
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. 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. """ special_libs = { # Public library name: (private library name, can coexist?) '-lnacl': ('-lnacl_sys_private', True), '-lpthread': ('-lpthread_private', False), } 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 SetupChain(chain, input_type, output_type): assert (output_type in ('pp', 'll', 'po', 's', 'o')) cur_type = input_type # source file -> pp if filetype.IsSourceType(cur_type) and output_type == 'pp': chain.add(RunCC, 'cpp', mode='-E') cur_type = 'pp' if cur_type == output_type: return # source file -> ll if (filetype.IsSourceType(cur_type) and (env.getbool('FORCE_INTERMEDIATE_LL') or output_type == 'll')): chain.add(RunCC, 'll', mode='-S') cur_type = 'll' if cur_type == output_type: return # ll -> po if cur_type == 'll': chain.add(RunLLVMAS, 'po') cur_type = 'po' if cur_type == output_type: return # source file -> po (we also force native output to go through this phase if filetype.IsSourceType(cur_type) and output_type in ('po', 'o', 's'): chain.add(RunCC, 'po', mode='-c') cur_type = 'po' if cur_type == output_type: return # po -> o if (cur_type == 'po' and output_type == 'o'): # If we aren't using biased bitcode, then at least -expand-byval # must be run to work with the PPAPI shim calling convention. if IsPortable(): chain.add(RunOpt, 'expand.po', pass_list=['-expand-byval']) chain.add(RunTranslate, 'o', mode='-c') cur_type = 'o' if cur_type == output_type: return # po -> s if cur_type == 'po': # If we aren't using biased bitcode, then at least -expand-byval # must be run to work with the PPAPI shim calling convention. if IsPortable(): chain.add(RunOpt, 'expand.po', pass_list=['-expand-byval']) chain.add(RunTranslate, 's', mode='-S') cur_type = 's' if cur_type == output_type: return # S -> s if cur_type == 'S': chain.add(RunCC, 's', mode='-E') cur_type = 's' if output_type == 'pp': return if cur_type == output_type: return # s -> o if cur_type == 's' and output_type == 'o': chain.add(RunNativeAS, 'o') cur_type = 'o' if cur_type == output_type: return Log.Fatal("Unable to compile .%s to .%s", input_type, output_type)
def main(argv): env.update(EXTRA_ENV) CheckSetup() ParseArgs(argv, CustomPatterns + GCCPatterns) # "configure", especially when run as part of a toolchain bootstrap # process, will invoke gcc with various diagnostic options and # parse the output. In these cases we do not alter the incoming # commandline. It is also important to not emit spurious messages. if env.getbool('DIAGNOSTIC'): if env.getbool('SHOW_VERSION'): code, stdout, stderr = Run(env.get('CC') + env.get('CC_FLAGS'), redirect_stdout=subprocess.PIPE) out = stdout.split('\n') nacl_version = ReadDriverRevision() out[0] += ' nacl-version=%s' % nacl_version stdout = '\n'.join(out) print stdout, else: Run(env.get('CC') + env.get('CC_FLAGS')) return 0 unmatched = env.get('UNMATCHED') if len(unmatched) > 0: UnrecognizedOption(*unmatched) # If -arch was given, we are compiling directly to native code compiling_to_native = GetArch() is not None if env.getbool('ALLOW_NATIVE') and not compiling_to_native: Log.Fatal("--pnacl-allow-native without -arch is not meaningful.") if not env.get('STDLIB'): # Default C++ Standard Library. SetStdLib('libc++') inputs = env.get('INPUTS') output = env.getone('OUTPUT') if len(inputs) == 0: if env.getbool('VERBOSE'): # -v can be invoked without any inputs. Runs the original # command without modifying the commandline for this case. Run(env.get('CC') + env.get('CC_FLAGS')) return 0 else: Log.Fatal('No input files') gcc_mode = env.getone('GCC_MODE') output_type = DriverOutputTypes(gcc_mode, compiling_to_native) needs_linking = (gcc_mode == '') if env.getbool('NEED_DASH_E') and gcc_mode != '-E': Log.Fatal("-E or -x required when input is from stdin") # There are multiple input files and no linking is being done. # There will be multiple outputs. Handle this case separately. if not needs_linking: # Filter out flags inputs = [f for f in inputs if not IsFlag(f)] if output != '' and len(inputs) > 1: Log.Fatal( 'Cannot have -o with -c, -S, or -E and multiple inputs: %s', repr(inputs)) for f in inputs: if IsFlag(f): continue intype = filetype.FileType(f) if not filetype.IsSourceType(intype): if ((output_type == 'pp' and intype != 'S') or (output_type == 'll') or (output_type == 'po' and intype != 'll') or (output_type == 's' and intype not in ('ll', 'po', 'S')) or (output_type == 'o' and intype not in ('ll', 'po', 'S', 's'))): Log.Fatal("%s: Unexpected type of file for '%s'", pathtools.touser(f), gcc_mode) if output == '': f_output = DefaultOutputName(f, output_type) else: f_output = output namegen = TempNameGen([f], f_output) CompileOne(f, output_type, namegen, f_output) return 0 # Linking case assert (needs_linking) assert (output_type in ('pso', 'so', 'pexe', 'nexe')) if output == '': output = pathtools.normalize('a.out') namegen = TempNameGen(inputs, output) # Compile all source files (c/c++/ll) to .po for i in xrange(0, len(inputs)): if IsFlag(inputs[i]): continue intype = filetype.FileType(inputs[i]) if filetype.IsSourceType(intype) or intype == 'll': inputs[i] = CompileOne(inputs[i], 'po', namegen) # Compile all .s/.S to .o if env.getbool('ALLOW_NATIVE'): for i in xrange(0, len(inputs)): if IsFlag(inputs[i]): continue intype = filetype.FileType(inputs[i]) if intype in ('s', 'S'): inputs[i] = CompileOne(inputs[i], 'o', namegen) # We should only be left with .po and .o and libraries for f in inputs: if IsFlag(f): continue intype = filetype.FileType(f) if intype in ('o', 's', 'S') or filetype.IsNativeArchive(f): if not env.getbool('ALLOW_NATIVE'): Log.Fatal( '%s: Native object files not allowed in link. ' 'Use --pnacl-allow-native to override.', pathtools.touser(f)) assert (intype in ('po', 'o', 'so', 'ldscript') or filetype.IsArchive(f)) # Fix the user-specified linker arguments ld_inputs = [] for f in inputs: if f.startswith('-Xlinker='): ld_inputs.append(f[len('-Xlinker='):]) elif f.startswith('-Wl,'): ld_inputs += f[len('-Wl,'):].split(',') else: ld_inputs.append(f) if env.getbool('ALLOW_NATIVE'): ld_inputs.append('--pnacl-allow-native') # Invoke the linker env.set('ld_inputs', *ld_inputs) ld_args = env.get('LD_ARGS') ld_flags = env.get('LD_FLAGS') RunDriver('ld', ld_flags + ld_args + ['-o', output]) return 0