OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2014 The Native Client Authors. All rights reserved. | 2 # Copyright 2014 The Native Client Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Script for linking the NaCl IRT and IRT core. | 6 """Script for linking the NaCl IRT and IRT core. |
7 | 7 |
8 This module will take care of linking the NaCl IRT. Compiling the libraries | 8 This module will take care of linking the NaCl IRT. Compiling the libraries |
9 and object files that go into the NaCl IRT is done outside of this script. | 9 and object files that go into the NaCl IRT is done outside of this script. |
10 | 10 |
11 Linking is factored out because the IRT has specific requirements for | 11 Linking is factored out because the IRT has specific requirements for |
12 where to place the text vs data segments, and also requires editting how | 12 where to place the text vs data segments, and also requires editting how |
13 TLS access is done. Thus, it's more complicated than the usual linking. | 13 TLS access is done. Thus, it's more complicated than the usual linking. |
14 """ | 14 """ |
15 | 15 |
16 import argparse | 16 import argparse |
17 import os | 17 import os |
18 import re | |
18 import sys | 19 import sys |
19 | 20 |
20 from build_nexe_tools import (CommandRunner, Error, FixPath, MakeDir) | 21 from build_nexe_tools import (CommandRunner, Error, FixPath, MakeDir) |
21 | 22 |
22 | 23 |
23 class IRTLinker(CommandRunner): | 24 class IRTLinker(CommandRunner): |
24 """Builder object that generates build command-lines and runs them. | 25 """Builder object that generates build command-lines and runs them. |
25 """ | 26 """ |
26 | 27 |
27 def __init__(self, options): | 28 def __init__(self, options): |
28 super(IRTLinker, self).__init__(options) | 29 super(IRTLinker, self).__init__(options) |
29 # IRT constraints for auto layout. | 30 # IRT constraints for auto layout. |
30 # IRT text can only go up to 256MB. Addresses after that are for data. | 31 # IRT text can only go up to 256MB. Addresses after that are for data. |
31 # Reserve an extra page because: | 32 # Reserve an extra page because: |
32 # * sel_ldr requires a HLT sled at the end of the dynamic code area; | 33 # * sel_ldr requires a HLT sled at the end of the dynamic code area; |
33 # * dynamic_load_test currently tests loading at the end of the dynamic | 34 # * dynamic_load_test currently tests loading at the end of the dynamic |
34 # code area. | 35 # code area. |
35 self.irt_text_max = 0x10000000 - 0x10000 | 36 self.irt_text_max = 0x10000000 - 0x10000 |
36 # Data can only go up to the sandbox_top - sizeof(stack). | 37 # Data can only go up to the sandbox_top - sizeof(stack). |
37 # NaCl allocates 16MB for the initial thread's stack (see | 38 # NaCl allocates 16MB for the initial thread's stack (see |
38 # NACL_DEFAULT_STACK_MAX in sel_ldr.h). | 39 # NACL_DEFAULT_STACK_MAX in sel_ldr.h). |
39 # Assume sandbox_top is 1GB, since even on x86-64 the limit would | 40 # Assume sandbox_top is 1GB, since even on x86-64 the limit would |
40 # only be 2GB (rip-relative references can only be +/- 2GB). | 41 # only be 2GB (rip-relative references can only be +/- 2GB). |
41 sandbox_top = 0x40000000 | 42 sandbox_top = 0x40000000 |
42 self.irt_data_max = sandbox_top - (16 << 20) | 43 self.irt_data_max = sandbox_top - (16 << 20) |
43 self.output = options.output | 44 self.output = options.output |
44 self.link_cmd = options.link_cmd | 45 self.link_cmd = options.link_cmd |
45 self.readelf_cmd = options.readelf_cmd | 46 self.readelf_cmd = options.readelf_cmd |
47 self.objdump_cmd = options.objdump_cmd | |
46 self.tls_edit = options.tls_edit | 48 self.tls_edit = options.tls_edit |
47 self.SetCommandsAreScripts(options.commands_are_scripts) | 49 self.SetCommandsAreScripts(options.commands_are_scripts) |
48 | 50 |
49 def GetIRTLayout(self, irt_file): | 51 def GetIRTLayout(self, irt_file): |
50 """Check if the IRT's data and text segment fit layout constraints and | 52 """Check if the IRT's data and text segment fit layout constraints and |
51 get sizes of the IRT's text and data segments. | 53 get sizes of the IRT's text and data segments. |
52 | 54 |
53 Returns a tuple containing: | 55 Returns a tuple containing: |
54 * whether the IRT data/text top addresses fit within the max limit | 56 * whether the IRT data/text top addresses fit within the max limit |
55 * current data/text top addrs | 57 * current data/text top addrs |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 'text_top=0x%x and data_top=0x%x\n' % ( | 157 'text_top=0x%x and data_top=0x%x\n' % ( |
156 text_top, data_top)) | 158 text_top, data_top)) |
157 self.Log('IRT layout fits: text_top=0x%x and data_top=0x%x' % | 159 self.Log('IRT layout fits: text_top=0x%x and data_top=0x%x' % |
158 (text_top, data_top)) | 160 (text_top, data_top)) |
159 | 161 |
160 tls_edit_cmd = [FixPath(self.tls_edit), pre_tls_edit_out, out] | 162 tls_edit_cmd = [FixPath(self.tls_edit), pre_tls_edit_out, out] |
161 tls_edit_err = self.Run(tls_edit_cmd, possibly_script=False) | 163 tls_edit_err = self.Run(tls_edit_cmd, possibly_script=False) |
162 if tls_edit_err: | 164 if tls_edit_err: |
163 raise Error('FAILED with %d: %s' % (err, ' '.join(tls_edit_cmd))) | 165 raise Error('FAILED with %d: %s' % (err, ' '.join(tls_edit_cmd))) |
164 | 166 |
167 def SandboxBaseCheck(self): | |
168 ''' | |
jvoung (off chromium)
2015/03/24 20:47:25
""" instead of ''' for docstrings and oneliner sum
Derek Schuff
2015/03/24 23:15:15
Done.
| |
169 This is a kind of lint check to ensure that the LLVM assembler's option for | |
170 hiding the sandbox base address on x86-64 is being used in all code compiled | |
171 into the IRT. It is only a heuristic intended to prevent accidental changes | |
172 in the IRT or toolchain build, and is not exhaustive. It is a stopgap until | |
173 we can fix https://code.google.com/p/nativeclient/issues/detail?id=3596 | |
174 ''' | |
175 cmd = [self.objdump_cmd, '-d', self.output] | |
176 output = self.Run(cmd, get_output=True) | |
177 # Disallow callq, all movs variants, all stos variants | |
178 # (objdump always disassembles 'call' as 'callq' in x86-64) | |
179 test_regex = r'\scallq\s|\smovs[bwlq]\s|\sstos[bwlq]\s' | |
180 # Disallow reads from rsp (other than %rsp,%rpb), and from rbp | |
181 test_regex += r'|[^(]%rsp,(?!%rbp)|[^(]%rbp,' | |
jvoung (off chromium)
2015/03/24 20:47:25
Hmm, so the trailing "," is required? What about
Derek Schuff
2015/03/24 23:15:15
It needs the trailing comma so that it doesn't cat
| |
182 # Disallow reads from %r11 or uses as a base register | |
183 test_regex += r'|%r11,' | |
184 # All indirect jumps must be through r11 | |
185 test_regex += r'|jmpq\s+\*%r(?!11)' | |
186 matched = re.search(test_regex, output) | |
187 if matched: | |
188 print 'The following instructions may reveal the sandbox base address:' | |
189 for line in output.splitlines(): | |
jvoung (off chromium)
2015/03/24 20:47:25
Hmm... can the splitlines() be done earlier?
My m
Derek Schuff
2015/03/24 23:15:15
I was attempting to avoid splitlines in the non-er
jvoung (off chromium)
2015/03/25 16:53:49
Okay sounds fine.
| |
190 match = re.search(test_regex, line) | |
jvoung (off chromium)
2015/03/24 20:47:25
3 space indent -> 2 space indent
Derek Schuff
2015/03/24 23:15:15
Done.
| |
191 if match: | |
192 print line | |
jvoung (off chromium)
2015/03/24 20:47:25
1 space indent -> 2 space indent
Derek Schuff
2015/03/24 23:15:15
Done.
| |
193 raise Error('IRT sandbox base address hiding lint check failed') | |
194 | |
195 else: | |
196 self.Log('Sandbox base address hiding lint check passed') | |
197 | |
165 | 198 |
166 def Main(): | 199 def Main(): |
167 parser = argparse.ArgumentParser() | 200 parser = argparse.ArgumentParser() |
168 parser.add_argument('-o', '--output', dest='output', required=True, | 201 parser.add_argument('-o', '--output', dest='output', required=True, |
169 help='Output filename') | 202 help='Output filename') |
170 parser.add_argument('--tls-edit', dest='tls_edit', required=True, | 203 parser.add_argument('--tls-edit', dest='tls_edit', required=True, |
171 help='Path of tls edit utility') | 204 help='Path of tls edit utility') |
172 parser.add_argument('--link-cmd', dest='link_cmd', required=True, | 205 parser.add_argument('--link-cmd', dest='link_cmd', required=True, |
173 help='Path of linker utility') | 206 help='Path of linker utility') |
174 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, | 207 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, |
175 help='Path of readelf utility') | 208 help='Path of readelf utility') |
176 parser.add_argument('-v', '--verbose', dest='verbose', default=False, | 209 parser.add_argument('--objdump-cmd', dest='objdump_cmd', required=False, |
210 help='Path of objdump utility') | |
211 parser.add_argument('-v', '--verbose', dest='verbose', default=True, | |
177 help='Enable verbosity', action='store_true') | 212 help='Enable verbosity', action='store_true') |
178 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', | 213 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', |
179 action='store_true', default=False, | 214 action='store_true', default=False, |
180 help='Indicate that toolchain commands are scripts') | 215 help='Indicate that toolchain commands are scripts') |
216 parser.add_argument('--sandbox-base-hiding-check', | |
217 dest='sandbox_base_hiding_check', action='store_true', | |
218 default=False) | |
jvoung (off chromium)
2015/03/24 20:47:25
help message?
| |
181 args, remaining_args = parser.parse_known_args() | 219 args, remaining_args = parser.parse_known_args() |
182 linker = IRTLinker(args) | 220 linker = IRTLinker(args) |
183 linker.Link(remaining_args) | 221 linker.Link(remaining_args) |
222 if args.sandbox_base_hiding_check: | |
223 linker.SandboxBaseCheck() | |
184 return 0 | 224 return 0 |
185 | 225 |
186 | 226 |
187 if __name__ == '__main__': | 227 if __name__ == '__main__': |
188 sys.exit(Main()) | 228 sys.exit(Main()) |
OLD | NEW |