• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python2
2
3import argparse
4import itertools
5import os
6import re
7import subprocess
8import sys
9import tempfile
10
11from utils import FindBaseNaCl, GetObjdumpCmd, shellcmd
12
13
14def TargetAssemblerFlags(target, sandboxed):
15  # TODO(reed kotler). Need to find out exactly we need to
16  # add here for Mips32.
17  flags = { 'x8632': ['-triple=%s' % ('i686-nacl' if sandboxed else 'i686')],
18            'x8664': ['-triple=%s' % (
19                          'x86_64-nacl' if sandboxed else 'x86_64')],
20            'arm32': ['-triple=%s' % (
21                          'armv7a-nacl' if sandboxed else 'armv7a'),
22                      '-mcpu=cortex-a9', '-mattr=+neon'],
23            'mips32': ['-triple=%s' % (
24                          'mipsel-nacl' if sandboxed else 'mipsel'),
25                       '-mcpu=mips32'] }
26  return flags[target]
27
28
29def TargetDisassemblerFlags(target):
30  flags = { 'x8632': ['-Mintel'],
31            'x8664': ['-Mintel'],
32            'arm32': [],
33            'mips32':[] }
34  return flags[target]
35
36def main():
37    """Run the pnacl-sz compiler on an llvm file.
38
39    Takes an llvm input file, freezes it into a pexe file, converts
40    it to a Subzero program, and finally compiles it.
41    """
42    argparser = argparse.ArgumentParser(
43        description='    ' + main.__doc__,
44        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
45    argparser.add_argument('--input', '-i', required=True,
46                           help='LLVM source file to compile')
47    argparser.add_argument('--output', '-o', required=False,
48                           help='Output file to write')
49    argparser.add_argument('--insts', required=False,
50                           action='store_true',
51                           help='Stop after translating to ' +
52                           'Subzero instructions')
53    argparser.add_argument('--no-local-syms', required=False,
54                           action='store_true',
55                           help="Don't keep local symbols in the pexe file")
56    argparser.add_argument('--llvm', required=False,
57                           action='store_true',
58                           help='Parse pexe into llvm IR first, then ' +
59                           'convert to Subzero')
60    argparser.add_argument('--llvm-source', required=False,
61                           action='store_true',
62                           help='Parse source directly into llvm IR ' +
63                           '(without generating a pexe), then ' +
64                           'convert to Subzero')
65    argparser.add_argument(
66        '--pnacl-sz', required=False, default='./pnacl-sz', metavar='PNACL-SZ',
67        help="Subzero translator 'pnacl-sz'")
68    argparser.add_argument('--pnacl-bin-path', required=False,
69                           default=(
70                             '{root}/toolchain/linux_x86/pnacl_newlib_raw/bin'
71                           ).format(root=FindBaseNaCl()),
72                           metavar='PNACL_BIN_PATH',
73                           help='Path to LLVM & Binutils executables ' +
74                                '(e.g. for building PEXE files)')
75    argparser.add_argument('--assemble', required=False,
76                           action='store_true',
77                           help='Assemble the output')
78    argparser.add_argument('--disassemble', required=False,
79                           action='store_true',
80                           help='Disassemble the assembled output')
81    argparser.add_argument('--dis-flags', required=False,
82                           action='append', default=[],
83                           help='Add a disassembler flag')
84    argparser.add_argument('--filetype', default='iasm', dest='filetype',
85                           choices=['obj', 'asm', 'iasm'],
86                           help='Output file type.  Default %(default)s')
87    argparser.add_argument('--forceasm', required=False, action='store_true',
88                           help='Force --filetype=asm')
89    argparser.add_argument('--target', default='x8632', dest='target',
90                           choices=['x8632','x8664','arm32','mips32'],
91                           help='Target architecture.  Default %(default)s')
92    argparser.add_argument('--echo-cmd', required=False,
93                           action='store_true',
94                           help='Trace command that generates ICE instructions')
95    argparser.add_argument('--tbc', required=False, action='store_true',
96                           help='Input is textual bitcode (not .ll)')
97    argparser.add_argument('--expect-fail', required=False, action='store_true',
98                           help='Negate success of run by using LLVM not')
99    argparser.add_argument('--allow-pnacl-reader-error-recovery',
100                           action='store_true',
101                           help='Continue parsing after first error')
102    argparser.add_argument('--args', '-a', nargs=argparse.REMAINDER,
103                           default=[],
104                           help='Remaining arguments are passed to pnacl-sz')
105    argparser.add_argument('--sandbox', required=False, action='store_true',
106                           help='Sandboxes the generated code')
107
108    args = argparser.parse_args()
109    pnacl_bin_path = args.pnacl_bin_path
110    llfile = args.input
111
112    if args.llvm and args.llvm_source:
113      raise RuntimeError("Can't specify both '--llvm' and '--llvm-source'")
114
115    if args.llvm_source and args.no_local_syms:
116      raise RuntimeError("Can't specify both '--llvm-source' and " +
117                         "'--no-local-syms'")
118
119    if args.llvm_source and args.tbc:
120      raise RuntimeError("Can't specify both '--tbc' and '--llvm-source'")
121
122    if args.llvm and args.tbc:
123      raise RuntimeError("Can't specify both '--tbc' and '--llvm'")
124
125    if args.forceasm:
126      if args.expect_fail:
127        args.forceasm = False
128      elif args.filetype == 'asm':
129        pass
130      elif args.filetype == 'iasm':
131        # TODO(sehr) implement forceasm for iasm.
132        pass
133      elif args.filetype == 'obj':
134        args.filetype = 'asm'
135        args.assemble = True
136
137    cmd = []
138    if args.tbc:
139      cmd = [os.path.join(pnacl_bin_path, 'pnacl-bcfuzz'), llfile,
140             '-bitcode-as-text', '-output', '-', '|']
141    elif not args.llvm_source:
142      cmd = [os.path.join(pnacl_bin_path, 'llvm-as'), llfile, '-o', '-', '|',
143             os.path.join(pnacl_bin_path, 'pnacl-freeze')]
144      if not args.no_local_syms:
145        cmd += ['--allow-local-symbol-tables']
146      cmd += ['|']
147    if args.expect_fail:
148      cmd += [os.path.join(pnacl_bin_path, 'not')]
149    cmd += [args.pnacl_sz]
150    cmd += ['--target', args.target]
151    if args.sandbox:
152      cmd += ['-sandbox']
153    if args.insts:
154      # If the tests are based on '-verbose inst' output, force
155      # single-threaded translation because dump output does not get
156      # reassembled into order.
157      cmd += ['-verbose', 'inst,global_init', '-notranslate', '-threads=0']
158    elif args.allow_pnacl_reader_error_recovery:
159      cmd += ['-allow-pnacl-reader-error-recovery', '-threads=0']
160    if not args.llvm_source:
161      cmd += ['--bitcode-format=pnacl']
162      if not args.no_local_syms:
163        cmd += ['--allow-local-symbol-tables']
164    if args.llvm or args.llvm_source:
165      cmd += ['--build-on-read=0']
166    else:
167      cmd += ['--build-on-read=1']
168    cmd += ['--filetype=' + args.filetype]
169    cmd += ['--emit-revision=0']
170    script_name = os.path.basename(sys.argv[0])
171    for _, arg in enumerate(args.args):
172      # Redirecting the output file needs to be done through the script
173      # because forceasm may introduce a new temporary file between pnacl-sz
174      # and llvm-mc.  Similar issues could occur when setting filetype, target,
175      # or sandbox through --args.  Filter and report an error.
176      if re.search('^-?-(o|output|filetype|target|sandbox)(=.+)?$', arg):
177        preferred_option = '--output' if re.search('^-?-o(=.+)?$', arg) else arg
178        print 'Option should be set using:'
179        print '    %s ... %s ... --args' % (script_name, preferred_option)
180        print 'rather than:'
181        print '    %s ... --args %s ...' % (script_name, arg)
182        exit(1)
183    asm_temp = None
184    output_file_name = None
185    keep_output_file = False
186    if args.output:
187      output_file_name = args.output
188      keep_output_file = True
189    cmd += args.args
190    if args.llvm_source:
191      cmd += [llfile]
192    if args.assemble or args.disassemble:
193      if not output_file_name:
194        # On windows we may need to close the file first before it can be
195        # re-opened by the other tools, so don't do delete-on-close,
196        # and instead manually delete.
197        asm_temp = tempfile.NamedTemporaryFile(delete=False)
198        asm_temp.close()
199        output_file_name = asm_temp.name
200    if args.assemble and args.filetype != 'obj':
201      cmd += (['|', os.path.join(pnacl_bin_path, 'llvm-mc')] +
202              TargetAssemblerFlags(args.target, args.sandbox) +
203              ['-filetype=obj', '-o', output_file_name])
204    elif output_file_name:
205      cmd += ['-o', output_file_name]
206    if args.disassemble:
207      # Show wide instruction encodings, diassemble, show relocs and
208      # dissasemble zeros.
209      cmd += (['&&', os.path.join(pnacl_bin_path, GetObjdumpCmd(args.target))] +
210              args.dis_flags +
211              ['-w', '-d', '-r', '-z'] + TargetDisassemblerFlags(args.target) +
212              [output_file_name])
213
214    stdout_result = shellcmd(cmd, echo=args.echo_cmd)
215    if not args.echo_cmd:
216      sys.stdout.write(stdout_result)
217    if asm_temp and not keep_output_file:
218      os.remove(output_file_name)
219
220if __name__ == '__main__':
221    main()
222