| 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 # Tool for reading linker script | |
| 13 | |
| 14 # TODO(pdox): Refactor driver_tools so that there is no circular dependency. | |
| 15 import driver_tools | |
| 16 import os | |
| 17 | |
| 18 def IsLinkerScript(filename): | |
| 19 return ParseLinkerScript(filename) is not None | |
| 20 | |
| 21 # Parses a linker script to determine additional ld arguments specified. | |
| 22 # Returns a list of linker arguments. | |
| 23 # | |
| 24 # For example, if the linker script contains | |
| 25 # | |
| 26 # GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux.so.2 ) ) | |
| 27 # | |
| 28 # Then this function will return: | |
| 29 # | |
| 30 # ['--start-group', '-l:libc.so.6', '-l:libc_nonshared.a', | |
| 31 # '--as-needed', '-l:ld-linux.so.2', '--no-as-needed', '--end-group'] | |
| 32 # | |
| 33 # Returns None on any parse error. | |
| 34 def ParseLinkerScript(filename): | |
| 35 fp = driver_tools.DriverOpen(filename, 'r') | |
| 36 | |
| 37 ret = [] | |
| 38 stack = [] | |
| 39 expect = '' # Expected next token | |
| 40 while True: | |
| 41 token = GetNextToken(fp) | |
| 42 if token is None: | |
| 43 # Tokenization error | |
| 44 return None | |
| 45 | |
| 46 if not token: | |
| 47 # EOF | |
| 48 break | |
| 49 | |
| 50 if expect: | |
| 51 if token == expect: | |
| 52 expect = '' | |
| 53 continue | |
| 54 else: | |
| 55 return None | |
| 56 | |
| 57 if not stack: | |
| 58 if token == 'INPUT': | |
| 59 expect = '(' | |
| 60 stack.append(token) | |
| 61 elif token == 'GROUP': | |
| 62 expect = '(' | |
| 63 ret.append('--start-group') | |
| 64 stack.append(token) | |
| 65 elif token == 'OUTPUT_FORMAT': | |
| 66 expect = '(' | |
| 67 stack.append(token) | |
| 68 elif token == 'EXTERN': | |
| 69 expect = '(' | |
| 70 stack.append(token) | |
| 71 elif token == ';': | |
| 72 pass | |
| 73 else: | |
| 74 return None | |
| 75 else: | |
| 76 if token == ')': | |
| 77 section = stack.pop() | |
| 78 if section == 'AS_NEEDED': | |
| 79 ret.append('--no-as-needed') | |
| 80 elif section == 'GROUP': | |
| 81 ret.append('--end-group') | |
| 82 elif token == 'AS_NEEDED': | |
| 83 expect = '(' | |
| 84 ret.append('--as-needed') | |
| 85 stack.append('AS_NEEDED') | |
| 86 elif stack[-1] == 'OUTPUT_FORMAT': | |
| 87 # Ignore stuff inside OUTPUT_FORMAT | |
| 88 pass | |
| 89 elif stack[-1] == 'EXTERN': | |
| 90 ret.append('--undefined=' + token) | |
| 91 else: | |
| 92 ret.append('-l:' + token) | |
| 93 | |
| 94 fp.close() | |
| 95 return ret | |
| 96 | |
| 97 | |
| 98 # Get the next token from the linker script | |
| 99 # Returns: '' for EOF. | |
| 100 # None on error. | |
| 101 def GetNextToken(fp): | |
| 102 token = '' | |
| 103 while True: | |
| 104 ch = fp.read(1) | |
| 105 | |
| 106 if not ch: | |
| 107 break | |
| 108 | |
| 109 # Whitespace terminates a token | |
| 110 # (but ignore whitespace before the token) | |
| 111 if ch in (' ', '\t', '\n'): | |
| 112 if token: | |
| 113 break | |
| 114 else: | |
| 115 continue | |
| 116 | |
| 117 # ( and ) are tokens themselves (or terminate existing tokens) | |
| 118 if ch in ('(',')'): | |
| 119 if token: | |
| 120 fp.seek(-1, os.SEEK_CUR) | |
| 121 break | |
| 122 else: | |
| 123 token = ch | |
| 124 break | |
| 125 | |
| 126 token += ch | |
| 127 if token.endswith('/*'): | |
| 128 if not ReadPastComment(fp, '*/'): | |
| 129 return None | |
| 130 token = token[:-2] | |
| 131 | |
| 132 return token | |
| 133 | |
| 134 def ReadPastComment(fp, terminator): | |
| 135 s = '' | |
| 136 while True: | |
| 137 ch = fp.read(1) | |
| 138 if not ch: | |
| 139 return False | |
| 140 s += ch | |
| 141 if s.endswith(terminator): | |
| 142 break | |
| 143 | |
| 144 return True | |
| OLD | NEW |