Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client / pnacl / driver / nativeld.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 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 #
7 # This is a thin wrapper for native LD. This is not meant to be
8 # used by the user, but is called from pnacl-translate.
9 # This implements the native linking part of translation.
10 #
11 # All inputs must be native objects or linker scripts.
12 #
13 # --pnacl-sb will cause the sandboxed LD to be used.
14 # The bulk of this file is logic to invoke the sandboxed translator.
15
16 import subprocess
17
18 from driver_tools import CheckTranslatorPrerequisites, GetArch, ParseArgs, \
19     Run, UnrecognizedOption
20 from driver_env import env
21 from driver_log import Log
22 import ldtools
23 import pathtools
24
25
26 EXTRA_ENV = {
27   'INPUTS'   : '',
28   'OUTPUT'   : '',
29
30   # the INPUTS file coming from the llc translation step
31   'LLC_TRANSLATED_FILE' : '',
32   'SPLIT_MODULE' : '0',
33   'USE_STDLIB': '1',
34
35   # Upstream gold has the segment gap built in, but the gap can be modified
36   # when not using the IRT. The gap does need to be at least one bundle so the
37   # halt sled can be added for the TCB in case the segment ends up being a
38   # multiple of 64k.
39   # --eh-frame-hdr asks the linker to generate an .eh_frame_hdr section,
40   # which is a presorted list of registered frames. This section is
41   # used by libgcc_eh/libgcc_s to avoid doing the sort during runtime.
42   # http://www.airs.com/blog/archives/462
43   #
44   # BE CAREFUL: anything added to LD_FLAGS should be synchronized with
45   # flags used by the in-browser translator.
46   # See: binutils/gold/nacl_file.cc
47   'LD_FLAGS'    : '-nostdlib ' +
48                   # Only relevant for ARM where it suppresses a warning.
49                   # Ignored for other archs.
50                   '--no-fix-cortex-a8 ' +
51                   '--eh-frame-hdr ' +
52                   # Give an error if any TEXTRELs occur.
53                   '-z text ' +
54                   '--build-id ',
55
56   'SEARCH_DIRS'        : '${SEARCH_DIRS_USER} ${SEARCH_DIRS_BUILTIN}',
57   'SEARCH_DIRS_USER'   : '',
58   'SEARCH_DIRS_BUILTIN': '${USE_STDLIB ? ${LIBS_NATIVE_ARCH}/}',
59
60   # Note: this is only used in the unsandboxed case
61   'RUN_LD' : '${LD} ${LD_FLAGS} ${inputs} -o ${output}'
62 }
63
64 def PassThrough(*args):
65   env.append('LD_FLAGS', *args)
66
67 LDPatterns = [
68   ( '-o(.+)',          "env.set('OUTPUT', pathtools.normalize($0))"),
69   ( ('-o', '(.+)'),    "env.set('OUTPUT', pathtools.normalize($0))"),
70
71   ( '-nostdlib',       "env.set('USE_STDLIB', '0')"),
72
73   ( '-L(.+)',
74     "env.append('SEARCH_DIRS_USER', pathtools.normalize($0))"),
75   ( ('-L', '(.*)'),
76     "env.append('SEARCH_DIRS_USER', pathtools.normalize($0))"),
77
78   # Note: we do not yet support all the combinations of flags which affect
79   # layout of the various sections and segments because the corner cases in gold
80   # may not all be worked out yet. They can be added (and tested!) as needed.
81   ( '(-static)',                  PassThrough),
82   ( '(-pie)',                     PassThrough),
83
84   ( ('(-Ttext=.*)'),              PassThrough),
85   ( ('(-Trodata=.*)'),            PassThrough),
86   ( ('(-Ttext-segment=.*)'),      PassThrough),
87   ( ('(-Trodata-segment=.*)'),    PassThrough),
88   ( ('(--rosegment-gap=.*)'),     PassThrough),
89   ( ('(--section-start)', '(.+)'),PassThrough),
90   ( ('(--section-start=.*)'),     PassThrough),
91   ( ('(-e)','(.*)'),              PassThrough),
92   ( '(--entry=.*)',               PassThrough),
93   ( '(-M)',                       PassThrough),
94   ( '(-t)',                       PassThrough),
95   ( ('-y','(.*)'),                PassThrough),
96   ( ('(-defsym)','(.*)'),         PassThrough),
97   ( '(-defsym=.*)',               PassThrough),
98   ( '-export-dynamic',            PassThrough),
99
100   ( '(--print-gc-sections)',      PassThrough),
101   ( '(--gc-sections)',            PassThrough),
102   ( '(--unresolved-symbols=.*)',  PassThrough),
103   ( '(--dynamic-linker=.*)',      PassThrough),
104   ( '(-g)',                       PassThrough),
105   ( '(--build-id)',               PassThrough),
106
107   ( '-melf_nacl',            "env.set('ARCH', 'X8632')"),
108   ( ('-m','elf_nacl'),       "env.set('ARCH', 'X8632')"),
109   ( '-melf64_nacl',          "env.set('ARCH', 'X8664')"),
110   ( ('-m','elf64_nacl'),     "env.set('ARCH', 'X8664')"),
111   ( '-marmelf_nacl',         "env.set('ARCH', 'ARM')"),
112   ( ('-m','armelf_nacl'),    "env.set('ARCH', 'ARM')"),
113   ( '-mmipselelf_nacl',      "env.set('ARCH', 'MIPS32')"),
114   ( ('-m','mipselelf_nacl'), "env.set('ARCH', 'MIPS32')"),
115
116   # Inputs and options that need to be kept in order
117   ( '(--no-as-needed)',    "env.append('INPUTS', $0)"),
118   ( '(--as-needed)',       "env.append('INPUTS', $0)"),
119   ( '(--start-group)',     "env.append('INPUTS', $0)"),
120   ( '(--end-group)',       "env.append('INPUTS', $0)"),
121   ( '(-Bstatic)',          "env.append('INPUTS', $0)"),
122   ( '(-Bdynamic)',         "env.append('INPUTS', $0)"),
123   # This is the file passed from llc during translation (used to be via shmem)
124   ( ('--llc-translated-file=(.*)'), "env.append('INPUTS', $0)\n"
125                                     "env.set('LLC_TRANSLATED_FILE', $0)"),
126   ( '-split-module=([0-9]+)', "env.set('SPLIT_MODULE', $0)"),
127   ( '(--(no-)?whole-archive)', "env.append('INPUTS', $0)"),
128
129   ( '(-l.*)',              "env.append('INPUTS', $0)"),
130   ( '(--undefined=.*)',    "env.append('INPUTS', $0)"),
131
132   ( '(-.*)',               UnrecognizedOption),
133   ( '(.*)',                "env.append('INPUTS', pathtools.normalize($0))"),
134 ]
135
136
137 def main(argv):
138   env.update(EXTRA_ENV)
139
140   ParseArgs(argv, LDPatterns)
141
142   GetArch(required=True)
143   inputs = env.get('INPUTS')
144   output = env.getone('OUTPUT')
145
146   if output == '':
147     output = pathtools.normalize('a.out')
148
149   # Expand all parameters
150   # This resolves -lfoo into actual filenames,
151   # and expands linker scripts into command-line arguments.
152   inputs = ldtools.ExpandInputs(inputs,
153                                 env.get('SEARCH_DIRS'),
154                                 True,
155                                 ldtools.LibraryTypes.NATIVE)
156
157   env.push()
158   env.set('inputs', *inputs)
159   env.set('output', output)
160
161   if env.getbool('SANDBOXED'):
162     RunLDSandboxed()
163   else:
164     Run('${RUN_LD}')
165   env.pop()
166   # only reached in case of no errors
167   return 0
168
169 def IsFlag(arg):
170   return arg.startswith('-')
171
172 def RunLDSandboxed():
173   if not env.getbool('USE_STDLIB'):
174     Log.Fatal('-nostdlib is not supported by the sandboxed translator')
175   CheckTranslatorPrerequisites()
176   # The "main" input file is the application's combined object file.
177   all_inputs = env.get('inputs')
178
179   main_input = env.getone('LLC_TRANSLATED_FILE')
180   if not main_input:
181     Log.Fatal("Sandboxed LD requires one shm input file")
182
183   outfile = env.getone('output')
184
185   modules = int(env.getone('SPLIT_MODULE'))
186   if modules > 1:
187     first_mainfile = all_inputs.index(main_input)
188     first_extra = all_inputs.index(main_input) + modules
189     # Just the split module files
190     llc_outputs = all_inputs[first_mainfile:first_extra]
191     # everything else
192     all_inputs = all_inputs[:first_mainfile] + all_inputs[first_extra:]
193   else:
194     llc_outputs = [main_input]
195
196   files = LinkerFiles(all_inputs)
197   ld_flags = env.get('LD_FLAGS')
198
199   script = MakeSelUniversalScriptForLD(ld_flags,
200                                        llc_outputs,
201                                        files,
202                                        outfile)
203
204
205   Run('${SEL_UNIVERSAL_PREFIX} ${SEL_UNIVERSAL} ' +
206       '${SEL_UNIVERSAL_FLAGS} -B ${IRT_BLOB} -- ${LD_SB}',
207       stdin_contents=script,
208       # stdout/stderr will be automatically dumped
209       # upon failure
210       redirect_stderr=subprocess.PIPE,
211       redirect_stdout=subprocess.PIPE)
212
213
214 def MakeSelUniversalScriptForLD(ld_flags,
215                                 llc_outputs,
216                                 files,
217                                 outfile):
218   """ Return sel_universal script text for invoking LD.nexe with the
219   given ld_flags, llc_outputs (which are treated specially), and
220   other input files (for native libraries). The output will be written
221   to outfile.  """
222   script = []
223
224   # Open the output file.
225   script.append('readwrite_file nexefile %s' % outfile)
226
227   files_to_map = list(files)
228   # Create a reverse-service mapping for each input file and add it to
229   # the sel universal script.
230   for f in files_to_map:
231     basename = pathtools.basename(f)
232     # If we are using the dummy shim, map it with the filename of the real
233     # shim, so the baked-in commandline will work.
234     if basename == 'libpnacl_irt_shim_dummy.a':
235       basename = 'libpnacl_irt_shim.a'
236     script.append('reverse_service_add_manifest_mapping files/%s %s' %
237                   (basename, f))
238
239   modules = len(llc_outputs)
240   script.extend(['readonly_file objfile%d %s' % (i, f)
241                  for i, f in zip(range(modules), llc_outputs)])
242   script.append('rpc RunWithSplit i(%d) ' % modules +
243                 ' '.join(['h(objfile%s)' % m for m in range(modules)] +
244                          ['h(invalid)' for x in range(modules, 16)]) +
245                 ' h(nexefile) *')
246   script.append('echo "ld complete"')
247   script.append('')
248   return '\n'.join(script)
249
250 # Given linker arguments (including -L, -l, and filenames),
251 # returns the list of files which are pulled by the linker,
252 # with real path names set set up the real -> flat name mapping.
253 def LinkerFiles(args):
254   ret = []
255   for f in args:
256     if IsFlag(f):
257       continue
258     else:
259       if not pathtools.exists(f):
260         Log.Fatal("Unable to open '%s'", pathtools.touser(f))
261       ret.append(f)
262   return ret