1#!/usr/bin/env python2 2 3import argparse 4import os 5import shutil 6import tempfile 7 8import targets 9from utils import FindBaseNaCl, GetObjcopyCmd, shellcmd 10 11 12def Translate(ll_files, extra_args, obj, verbose, target): 13 """Translate a set of input bitcode files into a single object file. 14 15 Use pnacl-llc to translate textual bitcode input ll_files into object file 16 obj, using extra_args as the architectural flags. 17 """ 18 externalize = ['-externalize'] 19 shellcmd(['cat'] + ll_files + ['|', 20 'pnacl-llc', 21 '-function-sections', 22 '-O2', 23 '-filetype=obj', 24 '-bitcode-format=llvm', 25 '-o', obj 26 ] + extra_args + externalize, echo=verbose) 27 localize_syms = ['nacl_tp_tdb_offset', 'nacl_tp_tls_offset'] 28 29 shellcmd([GetObjcopyCmd(target), obj] + 30 [('--localize-symbol=' + sym) for sym in localize_syms]) 31 32 33def PartialLink(obj_files, extra_args, lib, verbose): 34 """Partially links a set of obj files into a final obj library.""" 35 shellcmd(['le32-nacl-ld', 36 '-o', lib, 37 '-r', 38 ] + extra_args + obj_files, echo=verbose) 39 40 41def MakeRuntimesForTarget(target_info, ll_files, 42 srcdir, tempdir, rtdir, verbose, excluded_targets): 43 """Builds native, sandboxed, and nonsfi runtimes for the given target.""" 44 if target_info.target in excluded_targets: 45 return 46 # File-mangling helper functions. 47 def TmpFile(template): 48 return template.format(dir=tempdir, target=target_info.target) 49 def OutFile(template): 50 return template.format(rtdir=rtdir, target=target_info.target) 51 # Helper function for building the native unsandboxed runtime. 52 def MakeNativeRuntime(): 53 """Builds just the native runtime.""" 54 # Translate tempdir/szrt.ll and tempdir/szrt_ll.ll to 55 # szrt_native_{target}.tmp.o. 56 Translate(ll_files, 57 ['-mtriple=' + target_info.triple] + target_info.llc_flags, 58 TmpFile('{dir}/szrt_native_{target}.tmp.o'), 59 verbose, target_info.target) 60 # Compile srcdir/szrt_profiler.c to 61 # tempdir/szrt_profiler_native_{target}.o. 62 shellcmd(['clang', 63 '-O2', 64 '-target=' + target_info.triple, 65 '-c', 66 '{srcdir}/szrt_profiler.c'.format(srcdir=srcdir), 67 '-o', TmpFile('{dir}/szrt_native_profiler_{target}.o') 68 ], echo=verbose) 69 # Assemble srcdir/szrt_asm_{target}.s to tempdir/szrt_asm_{target}.o. 70 shellcmd(['llvm-mc', 71 '-triple=' + target_info.triple, '--defsym NATIVE=1', 72 '-filetype=obj', 73 '-o', TmpFile('{dir}/szrt_native_asm_{target}.o'), 74 '{srcdir}/szrt_asm_{target}.s'.format( 75 srcdir=srcdir, target=target_info.target) 76 ], echo=verbose) 77 # Write full szrt_native_{target}.o. 78 PartialLink([TmpFile('{dir}/szrt_native_{target}.tmp.o'), 79 TmpFile('{dir}/szrt_native_asm_{target}.o'), 80 TmpFile('{dir}/szrt_native_profiler_{target}.o')], 81 ['-m {ld_emu}'.format(ld_emu=target_info.ld_emu)], 82 OutFile('{rtdir}/szrt_native_{target}.o'), 83 verbose) 84 shellcmd([GetObjcopyCmd(target_info.target), 85 '--strip-symbol=NATIVE', 86 OutFile('{rtdir}/szrt_native_{target}.o')]) 87 # Compile srcdir/szrt_asan.c to szrt_asan_{target}.o 88 shellcmd(['clang', 89 '-O2', 90 '-target=' + target_info.triple, 91 '-c', 92 '{srcdir}/szrt_asan.c'.format(srcdir=srcdir), 93 '-o', OutFile('{rtdir}/szrt_asan_{target}.o') 94 ], echo=verbose) 95 96 # Helper function for building the sandboxed runtime. 97 def MakeSandboxedRuntime(): 98 """Builds just the sandboxed runtime.""" 99 # Translate tempdir/szrt.ll and tempdir/szrt_ll.ll to szrt_sb_{target}.o. 100 # The sandboxed library does not get the profiler helper function as the 101 # binaries are linked with -nostdlib. 102 Translate(ll_files, 103 ['-mtriple=' + targets.ConvertTripleToNaCl(target_info.triple)] + 104 target_info.llc_flags, 105 TmpFile('{dir}/szrt_sb_{target}.tmp.o'), 106 verbose,target_info.target) 107 # Assemble srcdir/szrt_asm_{target}.s to tempdir/szrt_asm_{target}.o. 108 shellcmd(['llvm-mc', 109 '-triple=' + targets.ConvertTripleToNaCl(target_info.triple), 110 '--defsym NACL=1', 111 '-filetype=obj', 112 '-o', TmpFile('{dir}/szrt_sb_asm_{target}.o'), 113 '{srcdir}/szrt_asm_{target}.s'.format( 114 srcdir=srcdir, target=target_info.target) 115 ], echo=verbose) 116 PartialLink([TmpFile('{dir}/szrt_sb_{target}.tmp.o'), 117 TmpFile('{dir}/szrt_sb_asm_{target}.o')], 118 ['-m {ld_emu}'.format(ld_emu=target_info.sb_emu)], 119 OutFile('{rtdir}/szrt_sb_{target}.o'), 120 verbose) 121 shellcmd([GetObjcopyCmd(target_info.target), 122 '--strip-symbol=NACL', 123 OutFile('{rtdir}/szrt_sb_{target}.o')]) 124 125 # Helper function for building the Non-SFI runtime. 126 def MakeNonsfiRuntime(): 127 """Builds just the nonsfi runtime.""" 128 # Translate tempdir/szrt.ll and tempdir/szrt_ll.ll to 129 # szrt_nonsfi_{target}.tmp.o. 130 Translate(ll_files, 131 ['-mtriple=' + target_info.triple] + target_info.llc_flags + 132 ['-relocation-model=pic', '-force-tls-non-pic', '-malign-double'], 133 TmpFile('{dir}/szrt_nonsfi_{target}.tmp.o'), 134 verbose, target_info.target) 135 # Assemble srcdir/szrt_asm_{target}.s to tempdir/szrt_asm_{target}.o. 136 shellcmd(['llvm-mc', 137 '-triple=' + target_info.triple, '--defsym NONSFI=1', 138 '-filetype=obj', 139 '-o', TmpFile('{dir}/szrt_nonsfi_asm_{target}.o'), 140 '{srcdir}/szrt_asm_{target}.s'.format( 141 srcdir=srcdir, target=target_info.target) 142 ], echo=verbose) 143 # Write full szrt_nonsfi_{target}.o. 144 PartialLink([TmpFile('{dir}/szrt_nonsfi_{target}.tmp.o'), 145 TmpFile('{dir}/szrt_nonsfi_asm_{target}.o')], 146 ['-m {ld_emu}'.format(ld_emu=target_info.ld_emu)], 147 OutFile('{rtdir}/szrt_nonsfi_{target}.o'), 148 verbose) 149 shellcmd([GetObjcopyCmd(target_info.target), 150 '--strip-symbol=NONSFI', 151 OutFile('{rtdir}/szrt_nonsfi_{target}.o')]) 152 153 154 # Run the helper functions. 155 MakeNativeRuntime() 156 MakeSandboxedRuntime() 157 MakeNonsfiRuntime() 158 159 160def main(): 161 """Build the Subzero runtime support library for all architectures. 162 """ 163 nacl_root = FindBaseNaCl() 164 argparser = argparse.ArgumentParser( 165 description=' ' + main.__doc__, 166 formatter_class=argparse.RawTextHelpFormatter) 167 argparser.add_argument('--verbose', '-v', dest='verbose', 168 action='store_true', 169 help='Display some extra debugging output') 170 argparser.add_argument('--pnacl-root', dest='pnacl_root', 171 default=( 172 '{root}/toolchain/linux_x86/pnacl_newlib_raw' 173 ).format(root=nacl_root), 174 help='Path to PNaCl toolchain binaries.') 175 argparser.add_argument('--exclude-target', dest='excluded_targets', 176 default=[], action='append', 177 help='Target whose runtime should not be built') 178 args = argparser.parse_args() 179 os.environ['PATH'] = ('{root}/bin{sep}{path}' 180 ).format(root=args.pnacl_root, sep=os.pathsep, path=os.environ['PATH']) 181 srcdir = ( 182 '{root}/toolchain_build/src/subzero/runtime' 183 ).format(root=nacl_root) 184 rtdir = ( 185 '{root}/toolchain_build/src/subzero/build/runtime' 186 ).format(root=nacl_root) 187 try: 188 tempdir = tempfile.mkdtemp() 189 if os.path.exists(rtdir) and not os.path.isdir(rtdir): 190 os.remove(rtdir) 191 if not os.path.exists(rtdir): 192 os.makedirs(rtdir) 193 # Compile srcdir/szrt.c to tempdir/szrt.ll 194 shellcmd(['pnacl-clang', 195 '-O2', 196 '-c', 197 '{srcdir}/szrt.c'.format(srcdir=srcdir), 198 '-o', '{dir}/szrt.tmp.bc'.format(dir=tempdir) 199 ], echo=args.verbose) 200 shellcmd(['pnacl-opt', 201 '-pnacl-abi-simplify-preopt', 202 '-pnacl-abi-simplify-postopt', 203 '-pnaclabi-allow-debug-metadata', 204 '{dir}/szrt.tmp.bc'.format(dir=tempdir), 205 '-S', 206 '-o', '{dir}/szrt.ll'.format(dir=tempdir) 207 ], echo=args.verbose) 208 ll_files = ['{dir}/szrt.ll'.format(dir=tempdir), 209 '{srcdir}/szrt_ll.ll'.format(srcdir=srcdir)] 210 211 MakeRuntimesForTarget(targets.X8632Target, ll_files, 212 srcdir, tempdir, rtdir, args.verbose, 213 args.excluded_targets) 214 MakeRuntimesForTarget(targets.X8664Target, ll_files, 215 srcdir, tempdir, rtdir, args.verbose, 216 args.excluded_targets) 217 MakeRuntimesForTarget(targets.ARM32Target, ll_files, 218 srcdir, tempdir, rtdir, args.verbose, 219 args.excluded_targets) 220 MakeRuntimesForTarget(targets.MIPS32Target, ll_files, 221 srcdir, tempdir, rtdir, args.verbose, 222 args.excluded_targets) 223 224 finally: 225 try: 226 shutil.rmtree(tempdir) 227 except OSError as exc: 228 if exc.errno != errno.ENOENT: # ENOENT - no such file or directory 229 raise # re-raise exception 230 231if __name__ == '__main__': 232 main() 233