| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 # | |
| 6 # IMPORTANT NOTE: If you make local mods to this file, you must run: | |
| 7 # % tools/llvm/utman.sh driver | |
| 8 # in order for them to take effect in the scons build. This command | |
| 9 # updates the copy in the toolchain/ tree. | |
| 10 # | |
| 11 | |
| 12 from driver_tools import * | |
| 13 import platform | |
| 14 import random | |
| 15 import hashlib | |
| 16 | |
| 17 if not IsWindowsPython(): | |
| 18 import fcntl | |
| 19 | |
| 20 EXTRA_ENV = { | |
| 21 'NATIVE_HACK' : '0', # Only link native code, ignore bitcode libraries. | |
| 22 # | |
| 23 # This is currently only used for translating .pexe's | |
| 24 # which are linked against glibc. Since they continue | |
| 25 # to have native object dependencies, they have to go | |
| 26 # through pnacl-gcc again, followed by pnacl-ld. | |
| 27 # But since we know the bitcode dependencies have | |
| 28 # already been linked in, we remove those from the | |
| 29 # link line with this flag. | |
| 30 | |
| 31 'WHICH_LD' : 'BFD', # Which ld to use for native linking: GOLD or BFD | |
| 32 | |
| 33 'INPUTS' : '', | |
| 34 'OUTPUT' : '', | |
| 35 | |
| 36 # Library dependencies to add (as DT_NEEDED records) | |
| 37 # This only applies to native dynamic/shared linking. | |
| 38 # This is used during pso -> so translation to set the | |
| 39 # correct dependencies on the generated ELF file. | |
| 40 'LIBDEPS' : '', | |
| 41 | |
| 42 'SHARED' : '0', | |
| 43 'STATIC' : '0', | |
| 44 'PIC' : '0', | |
| 45 'STDLIB' : '1', | |
| 46 'RELOCATABLE': '0', | |
| 47 | |
| 48 'BAREBONES_LINK' : '0', | |
| 49 | |
| 50 'STRIP_MODE' : 'none', | |
| 51 | |
| 52 'STRIP_FLAGS' : '${STRIP_FLAGS_%STRIP_MODE%}', | |
| 53 'STRIP_FLAGS_all' : '-s', | |
| 54 'STRIP_FLAGS_debug': '-S', | |
| 55 | |
| 56 'PNACL_TRANSLATE_FLAGS': '${PIC ? -fPIC}', | |
| 57 | |
| 58 'OPT_FLAGS': '-O${OPT_LEVEL} ${OPT_STRIP_%STRIP_MODE%} ' + | |
| 59 '-inline-threshold=${OPT_INLINE_THRESHOLD}', | |
| 60 'OPT_INLINE_THRESHOLD': '100', | |
| 61 'OPT_LEVEL': '0', | |
| 62 'OPT_STRIP_none': '', | |
| 63 'OPT_STRIP_all': '-disable-opt --strip', | |
| 64 'OPT_STRIP_debug': '-disable-opt --strip-debug', | |
| 65 | |
| 66 # Sandboxed LD is always BFD. | |
| 67 'LD' : '${SANDBOXED ? ${LD_SB} ${LD_BFD_FLAGS} ' + | |
| 68 ' : ${LD_%WHICH_LD%} ${LD_%WHICH_LD%_FLAGS}}', | |
| 69 | |
| 70 'LD_BFD_FLAGS': '-m ${LD_EMUL} ${#LD_SCRIPT ? -T ${LD_SCRIPT}}', | |
| 71 | |
| 72 'LD_GOLD_FLAGS': '--native-client --oformat ${LD_GOLD_OFORMAT} ' + | |
| 73 '${#LD_SCRIPT ? -T ${LD_SCRIPT} : -Ttext=0x20000}', | |
| 74 | |
| 75 'GOLD_PLUGIN_ARGS': '-plugin=${GOLD_PLUGIN_SO} ' + | |
| 76 '-plugin-opt=emit-llvm ' + | |
| 77 '${LIBMODE_NEWLIB && !BAREBONES_LINK ? ' + | |
| 78 '-plugin-opt=-add-nacl-read-tp-dependency ' + | |
| 79 '-plugin-opt=-add-libgcc-dependencies}', | |
| 80 | |
| 81 # Symbols to wrap | |
| 82 'WRAP_SYMBOLS': '', | |
| 83 | |
| 84 # Common to both GOLD and BFD. | |
| 85 'LD_FLAGS' : '-nostdlib ${@AddPrefix:-L:SEARCH_DIRS} ' + | |
| 86 '${SHARED ? -shared} ${STATIC ? -static} ' + | |
| 87 '${RELOCATABLE ? -relocatable} ' + | |
| 88 '${LIBMODE_GLIBC && ' + | |
| 89 '!STATIC ? ${@AddPrefix:-rpath-link=:SEARCH_DIRS}}', | |
| 90 | |
| 91 | |
| 92 | |
| 93 'SEARCH_DIRS' : '${SEARCH_DIRS_USER} ${SEARCH_DIRS_BUILTIN}', | |
| 94 'SEARCH_DIRS_USER' : '', | |
| 95 'SEARCH_DIRS_BUILTIN': '${STDLIB ? ' + | |
| 96 '${LIBS_SDK_BC}/ ${LIBS_SDK_ARCH}/ ' + | |
| 97 '${LIBS_ARCH}/ ${LIBS_BC}/}', | |
| 98 | |
| 99 # Standard Library Directories | |
| 100 'LIBS_BC' : '${BASE}/lib', | |
| 101 | |
| 102 'LIBS_ARCH' : '${LIBS_%ARCH%}', | |
| 103 'LIBS_ARM' : '${BASE}/lib-arm', | |
| 104 'LIBS_X8632' : '${BASE}/lib-x86-32', | |
| 105 'LIBS_X8664' : '${BASE}/lib-x86-64', | |
| 106 | |
| 107 'LIBS_SDK_BC' : '${BASE_SDK}/lib', | |
| 108 | |
| 109 'LIBS_SDK_ARCH' : '${LIBS_SDK_%ARCH%}', | |
| 110 'LIBS_SDK_X8632' : '${BASE_SDK}/lib-x86-32', | |
| 111 'LIBS_SDK_X8664' : '${BASE_SDK}/lib-x86-64', | |
| 112 'LIBS_SDK_ARM' : '${BASE_SDK}/lib-arm', | |
| 113 | |
| 114 | |
| 115 'LD_GOLD_OFORMAT' : '${LD_GOLD_OFORMAT_%ARCH%}', | |
| 116 'LD_GOLD_OFORMAT_ARM' : 'elf32-littlearm', | |
| 117 'LD_GOLD_OFORMAT_X8632' : 'elf32-nacl', | |
| 118 'LD_GOLD_OFORMAT_X8664' : 'elf64-nacl', | |
| 119 | |
| 120 'LD_EMUL' : '${LD_EMUL_%ARCH%}', | |
| 121 'LD_EMUL_ARM' : 'armelf_nacl', | |
| 122 'LD_EMUL_X8632' : 'elf_nacl', | |
| 123 'LD_EMUL_X8664' : 'elf64_nacl', | |
| 124 | |
| 125 'EMITMODE' : '${RELOCATABLE ? relocatable : ' + | |
| 126 '${STATIC ? static : ' + | |
| 127 '${SHARED ? shared : dynamic}}}', | |
| 128 | |
| 129 'LD_SCRIPT' : '${LD_SCRIPT_%LIBMODE%_%EMITMODE%}', | |
| 130 | |
| 131 # For newlib, omit the -T flag (the builtin linker script works fine). | |
| 132 'LD_SCRIPT_newlib_static': '', | |
| 133 | |
| 134 # For glibc, the linker script is always explicitly specified. | |
| 135 'LD_SCRIPT_glibc_static' : '${LD_EMUL}.x.static', | |
| 136 'LD_SCRIPT_glibc_shared' : '${LD_EMUL}.xs', | |
| 137 'LD_SCRIPT_glibc_dynamic': '${LD_EMUL}.x', | |
| 138 | |
| 139 'LD_SCRIPT_newlib_relocatable': '', | |
| 140 'LD_SCRIPT_glibc_relocatable' : '', | |
| 141 | |
| 142 'BCLD' : '${LD_GOLD}', | |
| 143 'BCLD_FLAGS': '${LD_GOLD_FLAGS} ' + | |
| 144 '${!SHARED && !RELOCATABLE ? --undef-sym-check} ' + | |
| 145 '${GOLD_PLUGIN_ARGS} ${LD_FLAGS}', | |
| 146 | |
| 147 | |
| 148 'LIBDEPS_FLAGS': '${@AddPrefix:--add-extra-dt-needed :LIBDEPS}', | |
| 149 | |
| 150 'RUN_LD' : '${LD} ${LD_FLAGS} ${LIBDEPS_FLAGS} ${inputs} -o "${output}"', | |
| 151 | |
| 152 'RUN_BCLD': ('${BCLD} ${BCLD_FLAGS} ${inputs} ' | |
| 153 '-o "${output}"'), | |
| 154 } | |
| 155 env.update(EXTRA_ENV) | |
| 156 | |
| 157 LDPatterns = [ | |
| 158 ( '--pnacl-native-hack', "env.set('NATIVE_HACK', '1')"), | |
| 159 ( '--pnacl-add-libdep=(.+)', "env.append('LIBDEPS', $0)"), | |
| 160 ( ('--add-translate-option=(.+)'), | |
| 161 "env.append('PNACL_TRANSLATE_FLAGS', $0)"), | |
| 162 # todo(dschuff): get rid of this when we get closer to tip and fix bug 1941 | |
| 163 ( ('--add-opt-option=(.+)'), | |
| 164 "env.append('OPT_FLAGS', $0)"), | |
| 165 | |
| 166 ( '-o(.+)', "env.set('OUTPUT', pathtools.normalize($0))"), | |
| 167 ( ('-o', '(.+)'), "env.set('OUTPUT', pathtools.normalize($0))"), | |
| 168 | |
| 169 ( '-barebones-link', "env.set('BAREBONES_LINK', '1')"), | |
| 170 | |
| 171 ( '-shared', "env.set('SHARED', '1')"), | |
| 172 | |
| 173 ( '-static', "env.set('STATIC', '1')\n" | |
| 174 "env.set('SHARED', '0')"), | |
| 175 ( '-nostdlib', "env.set('STDLIB', '0')"), | |
| 176 | |
| 177 ( '-r', "env.set('RELOCATABLE', '1')"), | |
| 178 ( '-relocatable', "env.set('RELOCATABLE', '1')"), | |
| 179 | |
| 180 ( ('-L', '(.+)'), | |
| 181 "env.append('SEARCH_DIRS_USER', pathtools.normalize($0))\n"), | |
| 182 ( '-L(.+)', | |
| 183 "env.append('SEARCH_DIRS_USER', pathtools.normalize($0))\n"), | |
| 184 | |
| 185 ( ('(-rpath)','(.*)'), | |
| 186 "env.append('LD_FLAGS', $0+'='+pathtools.normalize($1))"), | |
| 187 ( ('(-rpath)=(.*)'), | |
| 188 "env.append('LD_FLAGS', $0+'='+pathtools.normalize($1))"), | |
| 189 | |
| 190 ( ('(-rpath-link)','(.*)'), | |
| 191 "env.append('LD_FLAGS', $0+'='+pathtools.normalize($1))"), | |
| 192 ( ('(-rpath-link)=(.*)'), | |
| 193 "env.append('LD_FLAGS', $0+'='+pathtools.normalize($1))"), | |
| 194 | |
| 195 ( ('(-Ttext)','(.*)'), "env.append('LD_FLAGS', $0, $1)"), | |
| 196 ( ('(-Ttext=.*)'), "env.append('LD_FLAGS', $0)"), | |
| 197 | |
| 198 # This overrides the builtin linker script. | |
| 199 ( ('-T', '(.*)'), "env.set('LD_SCRIPT', pathtools.normalize($0))"), | |
| 200 | |
| 201 ( ('-e','(.*)'), "env.append('LD_FLAGS', '-e', $0)"), | |
| 202 ( ('(--section-start)','(.*)'), "env.append('LD_FLAGS', $0, $1)"), | |
| 203 ( '(-?-soname=.*)', "env.append('LD_FLAGS', $0)"), | |
| 204 ( ('(-?-soname)', '(.*)'), "env.append('LD_FLAGS', $0, $1)"), | |
| 205 ( '(--eh-frame-hdr)', "env.append('LD_FLAGS', $0)"), | |
| 206 ( '(-M)', "env.append('LD_FLAGS', $0)"), | |
| 207 ( '(-t)', "env.append('LD_FLAGS', $0)"), | |
| 208 ( ('-y','(.*)'), "env.append('LD_FLAGS', '-y', $0)"), | |
| 209 ( ('-defsym','(.*)'), "env.append('LD_FLAGS', '-defsym', $0)"), | |
| 210 | |
| 211 ( '(--print-gc-sections)', "env.append('LD_FLAGS', $0)"), | |
| 212 ( '(-gc-sections)', "env.append('LD_FLAGS', $0)"), | |
| 213 ( '(--unresolved-symbols=.*)', "env.append('LD_FLAGS', $0)"), | |
| 214 | |
| 215 ( '-melf_nacl', "env.set('ARCH', 'X8632')"), | |
| 216 ( ('-m','elf_nacl'), "env.set('ARCH', 'X8632')"), | |
| 217 ( '-melf64_nacl', "env.set('ARCH', 'X8664')"), | |
| 218 ( ('-m','elf64_nacl'), "env.set('ARCH', 'X8664')"), | |
| 219 ( '-marmelf_nacl', "env.set('ARCH', 'ARM')"), | |
| 220 ( ('-m','armelf_nacl'), "env.set('ARCH', 'ARM')"), | |
| 221 | |
| 222 ( ('-?-wrap', '(.+)'), "env.append('WRAP_SYMBOLS', $0)"), | |
| 223 ( ('-?-wrap=(.+)'), "env.append('WRAP_SYMBOLS', $0)"), | |
| 224 | |
| 225 # NOTE: For scons tests, the code generation fPIC flag is used with pnacl-ld. | |
| 226 ( '-fPIC', "env.set('PIC', '1')"), | |
| 227 | |
| 228 # This controls LTO optimization. | |
| 229 # opt does not support -Os but internally it is identical to -O2 | |
| 230 # opt also does not support -O4 but -O4 is how you ask llvm-gcc for LTO, so we | |
| 231 # can support it as well | |
| 232 ( '-Os', "env.set('OPT_LEVEL', '2')"), | |
| 233 ( '-O4', "env.set('OPT_LEVEL', '3')"), | |
| 234 ( '-O([0-3])', "env.set('OPT_LEVEL', $0)"), | |
| 235 | |
| 236 ( '-s', "env.append('STRIP_MODE', 'all')"), | |
| 237 ( '--strip-all', "env.append('STRIP_MODE', 'all')"), | |
| 238 ( '-S', "env.append('STRIP_MODE', 'debug')"), | |
| 239 ( '--strip-debug', "env.append('STRIP_MODE', 'debug')"), | |
| 240 | |
| 241 # Inputs and options that need to be kept in order | |
| 242 ( '(-l.*)', "env.append('INPUTS', $0)"), | |
| 243 ( ('(-l)','(.*)'), "env.append('INPUTS', $0+$1)"), | |
| 244 ( '(--no-as-needed)', "env.append('INPUTS', $0)"), | |
| 245 ( '(--as-needed)', "env.append('INPUTS', $0)"), | |
| 246 ( '(--start-group)', "env.append('INPUTS', $0)"), | |
| 247 ( '(--end-group)', "env.append('INPUTS', $0)"), | |
| 248 ( '(-Bstatic)', "env.append('INPUTS', $0)"), | |
| 249 ( '(-Bdynamic)', "env.append('INPUTS', $0)"), | |
| 250 ( '(--(no-)?whole-archive)', "env.append('INPUTS', $0)"), | |
| 251 ( '(-.*)', UnrecognizedOption), | |
| 252 ( '(.*)', "env.append('INPUTS', pathtools.normalize($0))"), | |
| 253 ] | |
| 254 | |
| 255 | |
| 256 def main(argv): | |
| 257 ParseArgs(argv, LDPatterns) | |
| 258 | |
| 259 if env.getbool('RELOCATABLE'): | |
| 260 if env.getbool('SHARED'): | |
| 261 Log.Fatal("-r and -shared may not be used together") | |
| 262 env.set('STATIC', '0') | |
| 263 env.set('BAREBONES_LINK', '1') | |
| 264 | |
| 265 if env.getbool('LIBMODE_NEWLIB'): | |
| 266 if env.getbool('SHARED'): | |
| 267 Log.Fatal("Cannot generate shared objects with newlib-based toolchain") | |
| 268 env.set('STATIC', '1') | |
| 269 | |
| 270 inputs = env.get('INPUTS') | |
| 271 output = env.getone('OUTPUT') | |
| 272 | |
| 273 if output == '': | |
| 274 output = pathtools.normalize('a.out') | |
| 275 | |
| 276 # If the user passed -arch, then they want native output. | |
| 277 arch_flag_given = GetArch() is not None | |
| 278 | |
| 279 if not arch_flag_given: | |
| 280 # If the arch flag was not given, we must auto-detect the link arch. | |
| 281 # This is for two reasons: | |
| 282 # 1) gold (for bitcode linking) requires an architecture | |
| 283 # 2) we don't know which standard search directories to use | |
| 284 # until ARCH is correctly set. (see SEARCH_DIRS_BUILTIN) | |
| 285 DetectArch(inputs) | |
| 286 | |
| 287 assert(GetArch() is not None) | |
| 288 | |
| 289 # If there's a linker script which needs to be searched for, find it. | |
| 290 LocateLinkerScript() | |
| 291 | |
| 292 # Expand all -l flags | |
| 293 ExpandLibFlags(inputs) | |
| 294 | |
| 295 # Expand input files which are linker scripts | |
| 296 inputs = ExpandLinkerScripts(inputs) | |
| 297 | |
| 298 if env.getbool('LIBMODE_GLIBC'): | |
| 299 TranslateInputs(inputs) | |
| 300 | |
| 301 # NATIVE HACK | |
| 302 native_left, native_right = RemoveBitcode(inputs) | |
| 303 if env.getbool('NATIVE_HACK'): | |
| 304 inputs = native_left + native_right | |
| 305 # END NATIVE HACK | |
| 306 | |
| 307 has_native, has_bitcode = AnalyzeInputs(inputs) | |
| 308 | |
| 309 # If there is bitcode, we do a bitcode link. If -arch is also specified, | |
| 310 # we invoke pnacl-translate afterwards. | |
| 311 if has_bitcode: | |
| 312 if env.getbool('SHARED'): | |
| 313 bitcode_type = 'pso' | |
| 314 native_type = 'so' | |
| 315 elif env.getbool('RELOCATABLE'): | |
| 316 bitcode_type = 'po' | |
| 317 native_type = 'o' | |
| 318 else: | |
| 319 bitcode_type = 'pexe' | |
| 320 native_type = 'nexe' | |
| 321 elif has_native: | |
| 322 # If there is no bitcode, then we do a native link only. | |
| 323 if not arch_flag_given: | |
| 324 Log.Fatal("Native linking requires -arch") | |
| 325 else: | |
| 326 Log.Fatal("No input objects") | |
| 327 | |
| 328 # Path A: Bitcode link, then opt, then translate. | |
| 329 if has_bitcode: | |
| 330 tng = TempNameGen([], output) | |
| 331 chain = DriverChain(inputs, output, tng) | |
| 332 chain.add(LinkBC, 'pre_opt.' + bitcode_type) | |
| 333 if NeedsWrap(): | |
| 334 chain.add(WrapDIS, 'before_wrap.ll') | |
| 335 chain.add(WrapLL, 'after_wrap.ll') | |
| 336 chain.add(WrapAS, 'after_wrap.' + bitcode_type) | |
| 337 if env.getone('OPT_LEVEL') != '0': | |
| 338 chain.add(DoOPT, 'opt.' + bitcode_type) | |
| 339 elif env.getone('STRIP_MODE') != 'none': | |
| 340 chain.add(DoStrip, 'stripped.' + bitcode_type) | |
| 341 if arch_flag_given: | |
| 342 # TODO(pdox): This should call pnacl-translate and nothing | |
| 343 # else. However, since we still use native objects in the | |
| 344 # scons and gcc builds, and special LD flags, we can't | |
| 345 # translate without including these extra libraries/flags. | |
| 346 chain.add(DoTranslate, 'o', mode = '-c') | |
| 347 chain.add(DoNativeLink, native_type, | |
| 348 native_left = native_left, | |
| 349 native_right = native_right) | |
| 350 chain.run() | |
| 351 return 0 | |
| 352 else: | |
| 353 # Path B: Native link only | |
| 354 LinkNative(inputs, output) | |
| 355 | |
| 356 return 0 | |
| 357 | |
| 358 def IsLib(arg): | |
| 359 return arg.startswith('-l') | |
| 360 | |
| 361 def IsFlag(arg): | |
| 362 return arg.startswith('-') and not IsLib(arg) | |
| 363 | |
| 364 def IsUndefMarker(arg): | |
| 365 return arg.startswith('--undefined=') | |
| 366 | |
| 367 def ExpandLibFlags(inputs): | |
| 368 for i in xrange(len(inputs)): | |
| 369 f = inputs[i] | |
| 370 if IsFlag(f): | |
| 371 continue | |
| 372 if IsLib(f): | |
| 373 inputs[i] = FindLib(f) | |
| 374 | |
| 375 def LocateLinkerScript(): | |
| 376 ld_script = env.getone('LD_SCRIPT') | |
| 377 if not ld_script: | |
| 378 # No linker script specified | |
| 379 return | |
| 380 | |
| 381 if ld_script.startswith('/'): | |
| 382 # Already absolute path | |
| 383 return | |
| 384 | |
| 385 search_dirs = env.get('SEARCH_DIRS') | |
| 386 path = FindFile([ld_script], search_dirs) | |
| 387 if not path: | |
| 388 Log.Fatal("Unable to find linker script '%s'", ld_script) | |
| 389 | |
| 390 env.set('LD_SCRIPT', path) | |
| 391 | |
| 392 def FindFirstLinkerScriptInput(inputs): | |
| 393 for i in xrange(len(inputs)): | |
| 394 f = inputs[i] | |
| 395 if IsFlag(f): | |
| 396 continue | |
| 397 if FileType(f) == 'ldscript': | |
| 398 return (i, f) | |
| 399 | |
| 400 return (None, None) | |
| 401 | |
| 402 def ExpandLinkerScripts(inputs): | |
| 403 while True: | |
| 404 # Find a ldscript in the input list | |
| 405 i, path = FindFirstLinkerScriptInput(inputs) | |
| 406 | |
| 407 # If none, we are done. | |
| 408 if path is None: | |
| 409 break | |
| 410 | |
| 411 new_inputs = ldtools.ParseLinkerScript(path) | |
| 412 ExpandLibFlags(new_inputs) | |
| 413 inputs = inputs[:i] + new_inputs + inputs[i+1:] | |
| 414 | |
| 415 # Handle --undefined=sym | |
| 416 ret = [] | |
| 417 for f in inputs: | |
| 418 if IsUndefMarker(f): | |
| 419 env.append('LD_FLAGS', f) | |
| 420 else: | |
| 421 ret.append(f) | |
| 422 | |
| 423 return ret | |
| 424 | |
| 425 def IsBitcodeInput(f): | |
| 426 if IsFlag(f): | |
| 427 return False | |
| 428 # .pso files are not considered bitcode input because | |
| 429 # they are translated to .so before invoking ld | |
| 430 return IsBitcodeArchive(f) or FileType(f) == 'po' | |
| 431 | |
| 432 def RemoveBitcode(inputs): | |
| 433 # Library order is important. We need to reinsert the | |
| 434 # bitcode translation object in between the objects on | |
| 435 # the left and the objects/libraries on the right. | |
| 436 left = [] | |
| 437 right = [] | |
| 438 found_bc = False | |
| 439 for f in inputs: | |
| 440 if IsBitcodeInput(f): | |
| 441 found_bc = True | |
| 442 continue | |
| 443 if not found_bc: | |
| 444 left.append(f) | |
| 445 else: | |
| 446 right.append(f) | |
| 447 | |
| 448 return (left,right) | |
| 449 | |
| 450 # Determine the kind of input files. | |
| 451 # Make sure the input files are valid. | |
| 452 # Make sure the input files have matching architectures. | |
| 453 # Returns (has_native, has_bitcode) | |
| 454 def AnalyzeInputs(inputs): | |
| 455 has_native = False | |
| 456 has_bitcode = False | |
| 457 count = 0 | |
| 458 | |
| 459 for f in inputs: | |
| 460 if IsFlag(f): | |
| 461 continue | |
| 462 elif IsBitcodeInput(f): | |
| 463 has_bitcode |= True | |
| 464 elif IsNative(f): | |
| 465 ArchMerge(f, True) | |
| 466 has_native |= True | |
| 467 elif IsNativeArchive(f): | |
| 468 ArchMerge(f, True) | |
| 469 has_native |= True | |
| 470 elif FileType(f) == 'pso': | |
| 471 pass | |
| 472 else: | |
| 473 Log.Fatal("%s: Unexpected type of file for linking (%s)", | |
| 474 pathtools.touser(f), FileType(f)) | |
| 475 count += 1 | |
| 476 | |
| 477 if count == 0: | |
| 478 Log.Fatal("no input files") | |
| 479 | |
| 480 return (has_native, has_bitcode) | |
| 481 | |
| 482 def DetectArch(inputs): | |
| 483 # Scan the inputs looking for a native file (.o or .so). | |
| 484 # At this point, library searches can only use the directories passed in | |
| 485 # with -L. Since we can't search the arch-specific standard search | |
| 486 # directories, there may be missing libraries, which we must ignore. | |
| 487 search_dirs = env.get('SEARCH_DIRS_USER') | |
| 488 | |
| 489 for f in inputs: | |
| 490 if IsFlag(f): | |
| 491 continue | |
| 492 if IsLib(f): | |
| 493 f = FindLib(f, search_dirs, must_find = False) | |
| 494 if not f: | |
| 495 # Ignore missing libraries | |
| 496 continue | |
| 497 | |
| 498 # TODO(pdox): If needed, we could also grab ARCH from linker scripts, | |
| 499 # either directly (using OUTPUT_ARCH or OUTPUT_FORMAT) or | |
| 500 # indirectly by expanding the linker script's INPUTS/GROUP. | |
| 501 if IsNative(f) or IsNativeArchive(f): | |
| 502 ArchMerge(f, True) | |
| 503 return | |
| 504 | |
| 505 # If we've reached here, there are no externally-specified native objects. | |
| 506 # It should be safe to assume the default neutral architecture. | |
| 507 SetArch('X8632') | |
| 508 return | |
| 509 | |
| 510 | |
| 511 def RunLDSRPC(): | |
| 512 CheckTranslatorPrerequisites() | |
| 513 # The "main" input file is the application's combined object file. | |
| 514 all_inputs = env.get('inputs') | |
| 515 | |
| 516 ############################################################# | |
| 517 # This is kind of arbitrary, but we need to treat one file as | |
| 518 # the "main" file for sandboxed LD. When this code moves into | |
| 519 # pnacl-translate, the selection of the main_input will be the | |
| 520 # object emitted by llc. This make a lot more sense. | |
| 521 objects = filter(lambda u: u.endswith('.o'), all_inputs) | |
| 522 if len(objects) == 0: | |
| 523 print "Sandboxed LD requires at least one .o file" | |
| 524 main_input = objects[0] | |
| 525 ############################################################# | |
| 526 | |
| 527 outfile = env.getone('output') | |
| 528 | |
| 529 assert(main_input != '') | |
| 530 files = LinkerFiles(all_inputs) | |
| 531 ld_flags = env.get('LD_FLAGS') + env.get('LD_BFD_FLAGS') | |
| 532 | |
| 533 # In this mode, we assume we only use the builtin linker script. | |
| 534 assert(env.getone('LD_SCRIPT') == '') | |
| 535 script = MakeSelUniversalScriptForLD(ld_flags, | |
| 536 main_input, | |
| 537 files, | |
| 538 outfile) | |
| 539 | |
| 540 RunWithLog('${SEL_UNIVERSAL_PREFIX} ${SEL_UNIVERSAL} ' + | |
| 541 '${SEL_UNIVERSAL_FLAGS} -- ${LD_SRPC}', | |
| 542 stdin=script, echo_stdout = False, echo_stderr = False) | |
| 543 | |
| 544 def MakeSelUniversalScriptForFile(filename): | |
| 545 """ Return sel_universal script text for sending a commandline argument | |
| 546 representing an input file to LD.nexe. """ | |
| 547 script = [] | |
| 548 basename = pathtools.basename(filename) | |
| 549 # A nice name for making a sel_universal variable. | |
| 550 # Hopefully this does not clash... | |
| 551 nicename = basename.replace('.','_').replace('-','_') | |
| 552 script.append('echo "adding %s"' % basename) | |
| 553 script.append('readonly_file %s %s' % (nicename, filename)) | |
| 554 script.append('rpc AddFile s("%s") h(%s) *' % (basename, nicename)) | |
| 555 script.append('rpc AddArg s("%s") *' % basename) | |
| 556 return script | |
| 557 | |
| 558 | |
| 559 def MakeSelUniversalScriptForLD(ld_flags, | |
| 560 main_input, | |
| 561 files, | |
| 562 outfile): | |
| 563 """ Return sel_universal script text for invoking LD.nexe with the | |
| 564 given ld_flags, main_input (which is treated specially), and | |
| 565 other input files. The output will be written to outfile. """ | |
| 566 script = [] | |
| 567 | |
| 568 # Go through all the arguments and add them. | |
| 569 # Based on the format of RUN_LD, the order of arguments is: | |
| 570 # ld_flags, then input files (which are more sensitive to order). | |
| 571 # Omit the "-o" for output so that it will use "a.out" internally. | |
| 572 # We will take the fd from "a.out" and write it to the proper -o filename. | |
| 573 for flag in ld_flags: | |
| 574 script.append('rpc AddArg s("%s") *' % flag) | |
| 575 script.append('') | |
| 576 | |
| 577 # We need to virtualize these files. | |
| 578 for f in files: | |
| 579 if f == main_input: | |
| 580 # Reload the temporary main_input object file into a new shmem region. | |
| 581 basename = pathtools.basename(f) | |
| 582 script.append('file_size %s in_size' % f) | |
| 583 script.append('shmem in_file in_addr ${in_size}') | |
| 584 script.append('load_from_file %s ${in_addr} 0 ${in_size}' % f) | |
| 585 script.append('rpc AddFileWithSize s("%s") h(in_file) i(${in_size}) *' % | |
| 586 basename) | |
| 587 script.append('rpc AddArg s("%s") *' % basename) | |
| 588 else: | |
| 589 script += MakeSelUniversalScriptForFile(f) | |
| 590 script.append('') | |
| 591 | |
| 592 script.append('rpc Link * h() i()') | |
| 593 script.append('set_variable out_file ${result0}') | |
| 594 script.append('set_variable out_size ${result1}') | |
| 595 script.append('map_shmem ${out_file} out_addr') | |
| 596 script.append('save_to_file %s ${out_addr} 0 ${out_size}' % outfile) | |
| 597 script.append('echo "ld complete"') | |
| 598 script.append('') | |
| 599 return '\n'.join(script) | |
| 600 | |
| 601 def DoOPT(infile, outfile): | |
| 602 opt_flags = env.get('OPT_FLAGS') | |
| 603 RunDriver('pnacl-opt', opt_flags + [ infile, '-o', outfile ]) | |
| 604 | |
| 605 def DoStrip(infile, outfile): | |
| 606 strip_flags = env.get('STRIP_FLAGS') | |
| 607 RunDriver('pnacl-strip', strip_flags + [ infile, '-o', outfile ]) | |
| 608 | |
| 609 def DoTranslate(infile, outfile, mode = ''): | |
| 610 args = [infile, '-o', outfile] | |
| 611 if mode: | |
| 612 args += [mode] | |
| 613 args += env.get('PNACL_TRANSLATE_FLAGS') | |
| 614 RunDriver('pnacl-translate', args) | |
| 615 | |
| 616 def DoNativeLink(infile, outfile, native_left, native_right): | |
| 617 LinkNative(native_left + [infile] + native_right, outfile) | |
| 618 | |
| 619 def LinkBC(inputs, output): | |
| 620 '''Input: a bunch of bc/o/lib input files | |
| 621 Output: a combined & optimized bitcode file | |
| 622 ''' | |
| 623 # Produce combined bitcode file | |
| 624 RunWithEnv('${RUN_BCLD}', | |
| 625 inputs=inputs, | |
| 626 output=output) | |
| 627 | |
| 628 ###################################################################### | |
| 629 # Bitcode Link Wrap Symbols Hack | |
| 630 ###################################################################### | |
| 631 | |
| 632 def NeedsWrap(): | |
| 633 return len(env.get('WRAP_SYMBOLS')) > 0 | |
| 634 | |
| 635 def WrapDIS(infile, outfile): | |
| 636 RunDriver('pnacl-dis', [infile, '-o', outfile], suppress_arch = True) | |
| 637 | |
| 638 def WrapLL(infile, outfile): | |
| 639 assert(FileType(infile) == 'll') | |
| 640 symbols = env.get('WRAP_SYMBOLS') | |
| 641 Log.Info('Wrapping symbols: ' + ' '.join(symbols)) | |
| 642 | |
| 643 fpin = DriverOpen(infile, 'r') | |
| 644 fpout = DriverOpen(outfile, 'w') | |
| 645 while True: | |
| 646 line = fpin.readline() | |
| 647 if not line: | |
| 648 break | |
| 649 | |
| 650 for s in symbols: | |
| 651 # Relabel the real function | |
| 652 if line.startswith('define'): | |
| 653 line = line.replace('@' + s + '(', '@__real_' + s + '(') | |
| 654 | |
| 655 # Remove declarations of __real_xyz symbol. | |
| 656 # Because we are actually defining it now, leaving the declaration around | |
| 657 # would cause an error. (bitcode should have either a define or declare, | |
| 658 # not both). | |
| 659 if line.startswith('declare') and '__real_' in line: | |
| 660 line = '' | |
| 661 | |
| 662 # Relabel the wrapper to the original name. | |
| 663 line = line.replace('@__wrap_' + s + '(', '@' + s + '(') | |
| 664 # Do the same renaming when the function appears in debug metadata. | |
| 665 # Case: !123 = metadata !{i32 456, ... metadata !"__wrap_FOO", ..., \ | |
| 666 # i32 (i32)* @__wrap_FOO} ; [ DW_TAG_subprogram ] | |
| 667 line = line.replace('@__wrap_' + s + '}', | |
| 668 '@' + s + '}') | |
| 669 line = line.replace('metadata !"__wrap_' + s + '"', | |
| 670 'metadata !"' + s + '"') | |
| 671 # Case: !llvm.dbg.lv.__wrap_FOO = !{!789} | |
| 672 line = line.replace('llvm.dbg.lv.__wrap_' + s + ' ', | |
| 673 'llvm.dbg.lv.' + s + ' ') | |
| 674 | |
| 675 fpout.write(line) | |
| 676 fpin.close() | |
| 677 fpout.close() | |
| 678 | |
| 679 | |
| 680 def WrapAS(infile, outfile): | |
| 681 RunDriver('pnacl-as', [infile, '-o', outfile], suppress_arch = True) | |
| 682 | |
| 683 ###################################################################### | |
| 684 # END Bitcode Link Wrap Symbols Hack | |
| 685 ###################################################################### | |
| 686 | |
| 687 | |
| 688 # This is a temporary hack. | |
| 689 # | |
| 690 # Until gold can recognize that .pso files should be treated like | |
| 691 # dynamic dependencies, we need to translate them first. | |
| 692 def TranslateInputs(inputs): | |
| 693 arch = GetArch() | |
| 694 | |
| 695 for i in xrange(len(inputs)): | |
| 696 f = inputs[i] | |
| 697 if IsFlag(f): | |
| 698 continue | |
| 699 if FileType(f) == 'pso': | |
| 700 inputs[i] = TranslatePSO(arch, f) | |
| 701 | |
| 702 def TranslatePSO(arch, path): | |
| 703 """ Translates a pso and returns the filename of the native so """ | |
| 704 assert(FileType(path) == 'pso') | |
| 705 assert(arch) | |
| 706 if not pathtools.exists(path): | |
| 707 Log.Fatal("Couldn't open %s", pathtools.touser(path)) | |
| 708 path_dir = pathtools.dirname(path) | |
| 709 cache_dir = pathtools.join(path_dir, 'pnacl_cache') | |
| 710 try: | |
| 711 os.mkdir(cache_dir) | |
| 712 except OSError: | |
| 713 pass | |
| 714 | |
| 715 output_base = pathtools.join(cache_dir, pathtools.basename(path)) + '.' + arch | |
| 716 | |
| 717 # Acquire a lock. | |
| 718 lock = FileLock(output_base) | |
| 719 if not lock: | |
| 720 # Add a random number to the file name to prevent collisions | |
| 721 output_base += '.%d' % random.getrandbits(32) | |
| 722 | |
| 723 output = '%s.so' % output_base | |
| 724 | |
| 725 # Make sure the existing file matches | |
| 726 if lock: | |
| 727 md5file = '%s.md5' % output_base | |
| 728 md5 = GetMD5Sum(path) | |
| 729 if pathtools.exists(output): | |
| 730 existing_md5 = ReadMD5(md5file) | |
| 731 if existing_md5 == md5: | |
| 732 lock.release() | |
| 733 return output | |
| 734 | |
| 735 # TODO(pdox): Some driver flags, in particular --pnacl-driver-set | |
| 736 # and --pnacl-driver-append, could adversely affect the translation, | |
| 737 # and should probably not be passed along. However, since this is a | |
| 738 # temporary solution, and we never use those flags in combination | |
| 739 # with glibc, we'll just let them pass for now. | |
| 740 RunDriver('pnacl-translate', | |
| 741 ['-no-save-temps', | |
| 742 # -arch needs to be provided, whether or not | |
| 743 # there was an -arch to this invocation. | |
| 744 '-arch', arch, path, '-o', output], | |
| 745 suppress_arch = True) # To avoid duplicate -arch | |
| 746 if lock: | |
| 747 WriteMD5(md5, md5file) | |
| 748 lock.release() | |
| 749 else: | |
| 750 TempFiles.add(output) | |
| 751 | |
| 752 return output | |
| 753 | |
| 754 def ReadMD5(file): | |
| 755 fp = DriverOpen(file, 'r', fail_ok = True) | |
| 756 if not fp: | |
| 757 return '' | |
| 758 s = fp.read() | |
| 759 fp.close() | |
| 760 return s | |
| 761 | |
| 762 def WriteMD5(s, file): | |
| 763 fp = DriverOpen(file, 'w') | |
| 764 fp.write(s) | |
| 765 fp.close() | |
| 766 | |
| 767 def GetMD5Sum(path): | |
| 768 m = hashlib.md5() | |
| 769 fp = DriverOpen(path, 'r') | |
| 770 m.update(fp.read()) | |
| 771 fp.close() | |
| 772 return m.hexdigest() | |
| 773 | |
| 774 def FileLock(filename): | |
| 775 if IsWindowsPython(): | |
| 776 return None | |
| 777 else: | |
| 778 return FileLockUnix(filename) | |
| 779 | |
| 780 class FileLockUnix(object): | |
| 781 def __init__(self, path): | |
| 782 self.lockfile = path + '.lock' | |
| 783 self.fd = None | |
| 784 self.acquire() | |
| 785 | |
| 786 def acquire(self): | |
| 787 fd = DriverOpen(self.lockfile, 'w+') | |
| 788 fcntl.lockf(fd, fcntl.LOCK_EX) | |
| 789 self.fd = fd | |
| 790 | |
| 791 def release(self): | |
| 792 if self.fd is not None: | |
| 793 fcntl.lockf(self.fd, fcntl.LOCK_UN) | |
| 794 self.fd.close() | |
| 795 self.fd = None | |
| 796 | |
| 797 # Final native linking step | |
| 798 # TODO(pdox): Move this into pnacl-translator. | |
| 799 def LinkNative(inputs, output): | |
| 800 env.push() | |
| 801 env.set('inputs', *inputs) | |
| 802 env.set('output', output) | |
| 803 | |
| 804 if env.getbool('SANDBOXED') and env.getbool('SRPC'): | |
| 805 RunLDSRPC() | |
| 806 else: | |
| 807 RunWithLog('${RUN_LD}') | |
| 808 | |
| 809 env.pop() | |
| 810 return | |
| 811 | |
| 812 def FindFile(search_names, search_dirs): | |
| 813 for curdir in search_dirs: | |
| 814 for name in search_names: | |
| 815 path = pathtools.join(curdir, name) | |
| 816 if pathtools.exists(path): | |
| 817 return path | |
| 818 return None | |
| 819 | |
| 820 def FindLib(arg, searchdirs = None, must_find = True): | |
| 821 """Returns the full pathname for the library input. | |
| 822 For example, name might be "-lc" or "-lm". | |
| 823 Returns None if the library is not found. | |
| 824 """ | |
| 825 assert(IsLib(arg)) | |
| 826 name = arg[len('-l'):] | |
| 827 is_whole_name = (name[0] == ':') | |
| 828 | |
| 829 if searchdirs is None: | |
| 830 searchdirs = env.get('SEARCH_DIRS') | |
| 831 | |
| 832 searchnames = [] | |
| 833 if is_whole_name: | |
| 834 # -l:filename (search for the filename) | |
| 835 name = name[1:] | |
| 836 searchnames.append(name) | |
| 837 | |
| 838 # .pso may exist in lieu of .so, or vice versa. | |
| 839 if '.so' in name: | |
| 840 searchnames.append(name.replace('.so', '.pso')) | |
| 841 if '.pso' in name: | |
| 842 searchnames.append(name.replace('.pso', '.so')) | |
| 843 else: | |
| 844 # -lfoo | |
| 845 shared_ok = not env.getbool('STATIC') | |
| 846 if shared_ok: | |
| 847 extensions = [ 'pso', 'so', 'a' ] | |
| 848 else: | |
| 849 extensions = [ 'a' ] | |
| 850 for ext in extensions: | |
| 851 searchnames.append('lib' + name + '.' + ext) | |
| 852 | |
| 853 foundpath = FindFile(searchnames, searchdirs) | |
| 854 if foundpath: | |
| 855 return foundpath | |
| 856 | |
| 857 if must_find: | |
| 858 if is_whole_name: | |
| 859 label = name | |
| 860 else: | |
| 861 label = arg | |
| 862 Log.Fatal("Cannot find '%s'", label) | |
| 863 | |
| 864 return None | |
| 865 | |
| 866 # Given linker arguments (including -L, -l, and filenames), | |
| 867 # returns the list of files which are pulled by the linker. | |
| 868 def LinkerFiles(args): | |
| 869 ret = [] | |
| 870 for f in args: | |
| 871 if IsFlag(f): | |
| 872 continue | |
| 873 else: | |
| 874 if not pathtools.exists(f): | |
| 875 Log.Fatal("Unable to open '%s'", pathtools.touser(f)) | |
| 876 ret.append(f) | |
| 877 return ret | |
| 878 | |
| 879 if __name__ == "__main__": | |
| 880 DriverMain(main) | |
| OLD | NEW |