OLD | NEW |
(Empty) | |
| 1 import sys |
| 2 import getopt |
| 3 import subprocess |
| 4 import tempfile |
| 5 import time |
| 6 def printUsage(): |
| 7 """Print usage string.""" |
| 8 print 'Usage: python bc2nexe.py --arch [x86-32,x86-64,arm] '\ |
| 9 '--output [out-file] in-file' |
| 10 |
| 11 def parseOpts(): |
| 12 """Parse program options and print usage string if necessary.""" |
| 13 try: |
| 14 opts, args = getopt.getopt(sys.argv[1:], '', ['arch=', 'output=']) |
| 15 except getopt.GetoptError, e: |
| 16 print e |
| 17 printUsage() |
| 18 sys.exit(0) |
| 19 output = None |
| 20 arch = None |
| 21 for opt, arg in opts: |
| 22 if opt == '--arch': |
| 23 arch = arg |
| 24 elif opt == '--output': |
| 25 output = arg |
| 26 if output is None: |
| 27 print '--output parameter is not found' |
| 28 printUsage() |
| 29 sys.exit(1) |
| 30 if arch is None: |
| 31 print '--arch parameter is not found' |
| 32 printUsage() |
| 33 sys.exit(1) |
| 34 return (output, arch, args) |
| 35 |
| 36 class Compiler(object): |
| 37 """Compiles bitcode to nexe.'""" |
| 38 def __init__(self, nacl): |
| 39 """Compiler constructor. |
| 40 |
| 41 Args: |
| 42 nacl: Path to the root of NaCl directory. |
| 43 """ |
| 44 self._NaCl = nacl |
| 45 |
| 46 def _llc(self, files, arch, output): |
| 47 """Convert bitcode files to assembler files. |
| 48 |
| 49 Args: |
| 50 files: List of bitcode files. |
| 51 arch: Cpu architecture. One of 'x86-32', 'x86-64', 'arm'. |
| 52 output: Assembler file name. |
| 53 """ |
| 54 if arch == 'x86-32': |
| 55 params = ['-march=x86', '-mcpu=pentium4'] |
| 56 elif arch == 'x86-64': |
| 57 params = ['-march=x86-64', '-mcpu=core2'] |
| 58 else: |
| 59 params = [ |
| 60 '-march=arm', |
| 61 '-mcpu=cortex-a8', |
| 62 '-mattr=-neon', |
| 63 '-mattr=+vfp3', |
| 64 '-arm-reserve-r9', |
| 65 '-sfi-cp-fudge', |
| 66 '-sfi-cp-fudge-percent=75', |
| 67 '-sfi-store', |
| 68 '-sfi-stack', |
| 69 '-sfi-branch', |
| 70 '-sfi-data', |
| 71 '-sfi-cp-disable-verify', |
| 72 '-no-inline-jumptables'] |
| 73 return subprocess.call( |
| 74 [self._toolchainBin + '/llc'] + params + |
| 75 ['-o', output] + files) |
| 76 |
| 77 def _assemble(self, files, arch, output): |
| 78 """Compile assembler code. |
| 79 |
| 80 Args: |
| 81 files: List of assembler files. |
| 82 arch: Cpu architecture. One of 'x86-32', 'x86-64', 'arm'. |
| 83 output: Object file name. |
| 84 """ |
| 85 if arch == 'x86-32': |
| 86 bin = self._toolchainGcc + '/bin/nacl64-as' |
| 87 params = ['--32', '--nacl-align', '5', '-n', '-mtune=i386'] |
| 88 elif arch == 'x86-64': |
| 89 bin = self._toolchainGcc + '/bin/nacl64-as' |
| 90 params = ['--64', '--nacl-align', '5', '-n', '-mtune=core2'] |
| 91 else: |
| 92 bin = self._toolchainBin + '/arm-none-linux-gnueabi-as' |
| 93 params = ['-mfpu=vfp3', '-march=armv7-a'] |
| 94 return subprocess.call( |
| 95 [bin] + params + ['-o', output] + files) |
| 96 |
| 97 def _linkNEXE(self, files, output): |
| 98 """Link object files and create *.nexe. |
| 99 |
| 100 Args: |
| 101 files: List of object files. |
| 102 output: *.nexe file name. |
| 103 """ |
| 104 return subprocess.call( |
| 105 [self._toolchainBin + '/arm-none-linux-gnueabi-ld', |
| 106 '--native-client', |
| 107 '-nostdlib', |
| 108 '-T', |
| 109 self._NaCl + '/native_client/tools/llvm/ld_script_x8664_untrusted', |
| 110 '-static', |
| 111 self._libPath + '/crt1.o', |
| 112 self._libPath + '/crti.o', |
| 113 self._libPath + '/crtbegin.o'] + |
| 114 files + |
| 115 [self._libPathBC + '/libc.a', |
| 116 self._libPathBC + '/libnacl.a', |
| 117 self._libPath + '/libcrt_platform.a', |
| 118 self._libPath + '/crtn.o', |
| 119 '-lgcc', |
| 120 '-L' + self._libPath, |
| 121 '-o', |
| 122 output]) |
| 123 |
| 124 def _initPaths(self, arch): |
| 125 """Initialize paths to important directories. |
| 126 |
| 127 Args: |
| 128 arch: Cpu architecture. One of 'x86-32', 'x86-64', 'arm'. |
| 129 """ |
| 130 self._toolchain = self._NaCl + \ |
| 131 '/native_client/toolchain/linux_arm-untrusted' |
| 132 self._toolchainBin = self._toolchain + '/arm-none-linux-gnueabi/bin' |
| 133 if arch == 'x86-32': |
| 134 self._libPath = self._toolchain + '/libs-x8632' |
| 135 elif arch == 'x86-64': |
| 136 self._libPath = self._toolchain + '/libs-x8664' |
| 137 else: |
| 138 self._libPath = self._toolchain + '/libs-arm' |
| 139 self._libPathBC = self._libPath + '-bc' |
| 140 self._toolchainGcc = self._NaCl + '/native_client/toolchain/linux_x86' |
| 141 |
| 142 def generateNEXE(self, files, arch, output): |
| 143 """Generate *.nexe from bitcode files. |
| 144 |
| 145 Args: |
| 146 files: List of bitcode files |
| 147 arch: Cpu architecture. One of 'x86-32', 'x86-64', 'arm'. |
| 148 output: *.nexe file name. |
| 149 """ |
| 150 self._initPaths(arch) |
| 151 tmpASfile = tempfile.NamedTemporaryFile() |
| 152 try: |
| 153 t0 = time.time() |
| 154 if self._llc(files, arch, tmpASfile.name) != 0: |
| 155 raise TranslateError('error while code generating') |
| 156 print "llc", "%.3f" % (time.time() - t0) |
| 157 tmpOfile = tempfile.NamedTemporaryFile() |
| 158 try: |
| 159 t0 = time.time() |
| 160 if self._assemble([tmpASfile.name], arch, tmpOfile.name) != 0: |
| 161 raise TranslateError('error while assembling') |
| 162 print "asm", "%.3f" % (time.time() - t0) |
| 163 t0 = time.time() |
| 164 if self._linkNEXE([tmpOfile.name], output) != 0: |
| 165 raise TranslateError('error while linking nexe') |
| 166 print "link", "%.3f" % (time.time() - t0) |
| 167 finally: |
| 168 tmpOfile.close() |
| 169 finally: |
| 170 tmpASfile.close() |
| 171 |
| 172 class TranslateError(Exception): |
| 173 """Exception when one of the compile stages returns non-zero.""" |
| 174 pass |
| 175 |
| 176 if __name__ == '__main__': |
| 177 output, arch, args = parseOpts() |
| 178 Compiler('../../../').generateNEXE(args, arch, output) |
OLD | NEW |