summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorsbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-29 22:52:20 +0000
committersbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-29 22:52:20 +0000
commit087332bd38a5ab9c6e580d242be2404bb1347b5b (patch)
tree83c907a7a300f70ad226d3b2763b11c9c74ec879 /native_client_sdk
parent7660284091909d6cad79ac4b8895d7c049ace453 (diff)
downloadchromium_src-087332bd38a5ab9c6e580d242be2404bb1347b5b.zip
chromium_src-087332bd38a5ab9c6e580d242be2404bb1347b5b.tar.gz
chromium_src-087332bd38a5ab9c6e580d242be2404bb1347b5b.tar.bz2
[NaCl SDK] remove --toolchain option from create_nmf.
This simplifies the create_nmf invocations in our example Makefiles. The --toolchain option was only needed to determin if an executable is dynamic or not (e.g. if it was built with glibc toolchain or not). With this change create_nmf now knows enough about the elf headers to determine this on its own. The -t/--toolchain is now deprecated (but not removed in case anyone was using it). R=binji BUG= Review URL: https://chromiumcodereview.appspot.com/11348287 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170267 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-xnative_client_sdk/src/build_tools/make_rules.py10
-rwxr-xr-xnative_client_sdk/src/tools/create_nmf.py181
2 files changed, 110 insertions, 81 deletions
diff --git a/native_client_sdk/src/build_tools/make_rules.py b/native_client_sdk/src/build_tools/make_rules.py
index d7f9c0e..ad5c819 100755
--- a/native_client_sdk/src/build_tools/make_rules.py
+++ b/native_client_sdk/src/build_tools/make_rules.py
@@ -16,7 +16,6 @@ NEWLIB_CC?=$(TC_PATH)/$(OSNAME)_x86_newlib/bin/i686-nacl-gcc -c
NEWLIB_CXX?=$(TC_PATH)/$(OSNAME)_x86_newlib/bin/i686-nacl-g++ -c
NEWLIB_LINK?=$(TC_PATH)/$(OSNAME)_x86_newlib/bin/i686-nacl-g++ -Wl,-as-needed
NEWLIB_LIB?=$(TC_PATH)/$(OSNAME)_x86_newlib/bin/i686-nacl-ar r
-NEWLIB_DUMP?=$(TC_PATH)/$(OSNAME)_x86_newlib/x86_64-nacl/bin/objdump
NEWLIB_CCFLAGS?=-MMD -pthread $(NACL_WARNINGS) -idirafter $(NACL_SDK_ROOT)/include
NEWLIB_LDFLAGS?=-pthread
"""
@@ -38,7 +37,6 @@ PNACL_CC?=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/pnacl-clang -c
PNACL_CXX?=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/pnacl-clang++ -c
PNACL_LINK?=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/pnacl-clang++
PNACL_LIB?=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/pnacl-ar r
-PNACL_DUMP?=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/objdump
PNACL_CCFLAGS?=-MMD -pthread $(NACL_WARNINGS) -idirafter $(NACL_SDK_ROOT)/include
PNACL_LDFLAGS?=-pthread
TRANSLATE:=$(TC_PATH)/$(OSNAME)_x86_pnacl/newlib/bin/pnacl-translate
@@ -141,7 +139,7 @@ WIN_LIB_RULES = {
#
NMF_RULE = """
<tc>/<config>/<proj>.nmf : <NMF_TARGETS>
-<TAB>$(NMF) -D $(<DUMP>) -o $@ $^ -t <tc> -s <tc>/<config>
+<TAB>$(NMF) -o $@ $^ -s <tc>/<config>
"""
NMF_EMPTY = """
@@ -151,7 +149,7 @@ NMF_EMPTY = """
GLIBC_NMF_RULE = """
<tc>/<config>/<proj>.nmf : <NMF_TARGETS>
-<TAB>$(NMF) -D $(<DUMP>) -o $@ $(GLIBC_PATHS) $^ -t <tc> -s <tc>/<config> $(GLIBC_REMAP)
+<TAB>$(NMF) -D $(<OBJDUMP>) -o $@ $(GLIBC_PATHS) $^ -s <tc>/<config> $(GLIBC_REMAP)
"""
EXT_MAP = {
@@ -428,7 +426,6 @@ class MakeRules(object):
tcname = tc
self.vars['<CC>'] = '%s_CC' % TC
self.vars['<CXX>'] = '%s_CXX' % TC
- self.vars['<DUMP>'] = '%s_DUMP' % TC
self.vars['<LIB>'] = '%s_LIB' % TC
self.vars['<LINK>'] = '%s_LINK' % TC
self.vars['<tc>'] = tc
@@ -489,10 +486,11 @@ def GenerateNMFRules(tc, main, dlls, cfg, arches):
for arch in arches:
replace = {
'<config>' : cfg,
- '<DUMP>' : '%s_DUMP' % tc.upper(),
'<TAB>' : '\t',
'<tc>' : tc
}
+ if tc == 'glibc':
+ replace['<OBJDUMP>'] = 'GLIBC_DUMP'
if '<ARCH>' in arch:
replace['<ARCH>'] = arch['<ARCH>']
for dll in dlls:
diff --git a/native_client_sdk/src/tools/create_nmf.py b/native_client_sdk/src/tools/create_nmf.py
index 2f8654f..4ece60a 100755
--- a/native_client_sdk/src/tools/create_nmf.py
+++ b/native_client_sdk/src/tools/create_nmf.py
@@ -85,6 +85,91 @@ class Error(Exception):
pass
+def ParseElfHeader(path):
+ """Determine properties of a nexe by parsing elf header.
+ Return tuple of architecture and boolean signalling whether
+ the executable is dynamic (has INTERP header) or static.
+ """
+ # From elf.h:
+ # typedef struct
+ # {
+ # unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ # Elf64_Half e_type; /* Object file type */
+ # Elf64_Half e_machine; /* Architecture */
+ # ...
+ # } Elf32_Ehdr;
+ elf_header_format = '16s2H'
+ elf_header_size = struct.calcsize(elf_header_format)
+
+ with open(path, 'rb') as f:
+ header = f.read(elf_header_size)
+
+ header = struct.unpack(elf_header_format, header)
+ e_ident, _, e_machine = header[:3]
+
+ elf_magic = '\x7fELF'
+ if e_ident[:4] != elf_magic:
+ raise Error("Not a valid NaCL executable: %s" % path)
+
+ e_machine_mapping = {
+ 3 : 'x86-32',
+ 40 : 'arm',
+ 62 : 'x86-64'
+ }
+ if e_machine not in e_machine_mapping:
+ raise Error("Unknown machine type: %s" % e_machine)
+
+ # Set arch based on the machine type in the elf header
+ arch = e_machine_mapping[e_machine]
+
+ # Now read the full header in either 64bit or 32bit mode
+ if arch == 'x86-64':
+ elf_header_format = '16s2HI3lI3H'
+ else:
+ elf_header_format = '16s2HI3II3H'
+
+ dynamic = IsDynamicElf(path, elf_header_format)
+ return arch, dynamic
+
+
+def IsDynamicElf(path, elf_header_format):
+ """Examine an elf file to determine if it is dynamically
+ linked or not.
+ This is determined by searching the program headers for
+ a header of type PT_INTERP.
+ """
+ elf_header_size = struct.calcsize(elf_header_format)
+
+ with open(path, 'rb') as f:
+ header = f.read(elf_header_size)
+ header = struct.unpack(elf_header_format, header)
+ p_header_offset = header[5]
+ p_header_entry_size = header[9]
+ num_p_header = header[10]
+ f.seek(p_header_offset)
+ p_headers = f.read(p_header_entry_size*num_p_header)
+
+ # Read the first word of each Phdr to find out its type.
+ #
+ # typedef struct
+ # {
+ # Elf32_Word p_type; /* Segment type */
+ # ...
+ # } Elf32_Phdr;
+ elf_phdr_format = 'I'
+ PT_INTERP = 3
+
+ while p_headers:
+ p_header = p_headers[:p_header_entry_size]
+ p_headers = p_headers[p_header_entry_size:]
+ phdr_type = struct.unpack(elf_phdr_format, p_header[:4])[0]
+ if phdr_type == PT_INTERP:
+ return True
+
+ return False
+
+
+
class ArchFile(object):
'''Simple structure containing information about
@@ -101,41 +186,7 @@ class ArchFile(object):
self.url = url
self.arch = arch
if arch is None:
- self._ReadElfHeader()
-
- def _ReadElfHeader(self):
- """Determine architecture of nexe by reading elf header."""
- # From elf.h:
- # typedef struct
- # {
- # unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
- # Elf64_Half e_type; /* Object file type */
- # Elf64_Half e_machine; /* Architecture */
- # ...
- # } Elf32_Ehdr;
- elf_header_format = '16s2H'
- elf_header_size = struct.calcsize(elf_header_format)
-
- with open(self.path, 'rb') as f:
- header = f.read(elf_header_size)
-
- header = struct.unpack(elf_header_format, header)
- e_ident, _, e_machine = header
-
- elf_magic = '\x7fELF'
- if e_ident[:4] != elf_magic:
- raise Error("Not a valid NaCL executable: %s" % self.path)
-
- e_machine_mapping = {
- 3 : 'x86-32',
- 40 : 'arm',
- 62 : 'x86-64'
- }
- if e_machine not in e_machine_mapping:
- raise Error("Unknown machine type: %s" % e_machine)
-
- # set arch based on the machine type in the elf header
- self.arch = e_machine_mapping[e_machine]
+ self.arch = ParseElfHeader(path)[0]
def __repr__(self):
return "<ArchFile %s>" % self.path
@@ -155,7 +206,7 @@ class NmfUtils(object):
def __init__(self, main_files=None, objdump=None,
lib_path=None, extra_files=None, lib_prefix=None,
- toolchain=None, remap=None):
+ remap=None):
'''Constructor
Args:
@@ -167,8 +218,6 @@ class NmfUtils(object):
lib_prefix: A list of path components to prepend to the library paths,
both for staging the libraries and for inclusion into the nmf file.
Examples: ['..'], ['lib_dir']
- toolchain: Specify which toolchain newlib|glibc|pnacl which can require
- different forms of the NMF.
remap: Remaps the library name in the manifest.
'''
self.objdump = objdump
@@ -178,10 +227,8 @@ class NmfUtils(object):
self.manifest = None
self.needed = {}
self.lib_prefix = lib_prefix or []
- self.toolchain = toolchain
self.remap = remap or {}
-
def GleanFromObjdump(self, files):
'''Get architecture and dependency information for given files
@@ -209,11 +256,15 @@ class NmfUtils(object):
input_info = {}
needed = set()
output, err_output = proc.communicate()
+ if proc.returncode:
+ raise Error('%s\nStdError=%s\nobjdump failed with error code: %d' %
+ (output, err_output, proc.returncode))
+
for line in output.splitlines(True):
# Objdump should display the architecture first and then the dependencies
# second for each file in the list.
matched = FormatMatcher.match(line)
- if matched is not None:
+ if matched:
filename = matched.group(1)
arch = OBJDUMP_ARCH_MAP[matched.group(2)]
if files[filename] is None or arch in files[filename]:
@@ -224,13 +275,9 @@ class NmfUtils(object):
path=filename,
url='/'.join(self.lib_prefix + [ARCH_LOCATION[arch], name]))
matched = NeededMatcher.match(line)
- if matched is not None:
+ if matched:
if files[filename] is None or arch in files[filename]:
needed.add('/'.join([arch, matched.group(1)]))
- status = proc.poll()
- if status != 0:
- raise Error('%s\nStdError=%s\nobjdump failed with error code: %d' %
- (output, err_output, status))
return input_info, needed
def FindLibsInPath(self, name):
@@ -261,10 +308,11 @@ class NmfUtils(object):
if self.needed:
return self.needed
- runnable = (self.toolchain != 'newlib' and self.toolchain != 'pnacl')
DebugPrint('GetNeeded(%s)' % self.main_files)
- if runnable:
+ dynamic = any(ParseElfHeader(f)[1] for f in self.main_files)
+
+ if dynamic:
examined = set()
all_files, unexamined = self.GleanFromObjdump(
dict([(f, None) for f in self.main_files]))
@@ -335,9 +383,11 @@ class NmfUtils(object):
FILES key mapped as 'main.exe' instead of it's original name so that the
loader can find it.'''
manifest = { FILES_KEY: {}, PROGRAM_KEY: {} }
- runnable = (self.toolchain != 'newlib' and self.toolchain != 'pnacl')
needed = self.GetNeeded()
+
+ runnable = any(n.endswith(RUNNABLE_LD) for n in needed)
+
for need, archinfo in needed.items():
urlinfo = { URL_KEY: archinfo.url }
name = archinfo.name
@@ -383,19 +433,6 @@ class NmfUtils(object):
return '\n'.join([line.rstrip() for line in pretty_lines]) + '\n'
-def DetermineToolchain(objdump):
- objdump = objdump.replace('\\', '/')
- paths = objdump.split('/')
- count = len(paths)
- for index in range(count - 2, 0, -1):
- if paths[index] == 'toolchain':
- if paths[index + 1].endswith('newlib'):
- return 'newlib'
- if paths[index + 1].endswith('glibc'):
- return 'glibc'
- raise Error('Could not deternime which toolchain to use.')
-
-
def Trace(msg):
if Trace.verbose:
sys.stderr.write(str(msg) + '\n')
@@ -403,7 +440,7 @@ def Trace(msg):
Trace.verbose = False
-def Main(argv):
+def main(argv):
parser = optparse.OptionParser(
usage='Usage: %prog [options] nexe [extra_libs...]')
parser.add_option('-o', '--output', dest='output',
@@ -425,9 +462,7 @@ def Main(argv):
parser.add_option('-r', '--remove', dest='remove',
help='Remove the prefix from the files.',
metavar='PATH')
- parser.add_option('-t', '--toolchain', dest='toolchain',
- help='Add DIRECTORY to library search path',
- default=None, metavar='TOOLCHAIN')
+ parser.add_option('-t', '--toolchain', help='Legacy option, do not use')
parser.add_option('-n', '--name', dest='name',
help='Rename FOO as BAR',
action='append', default=[], metavar='FOO,BAR')
@@ -435,21 +470,18 @@ def Main(argv):
help='Verbose output', action='store_true')
parser.add_option('-d', '--debug-mode',
help='Debug mode', action='store_true')
- (options, args) = parser.parse_args(argv)
+ options, args = parser.parse_args(argv)
if options.verbose:
Trace.verbose = True
if options.debug_mode:
DebugPrint.debug_mode = True
+ if options.toolchain is not None:
+ print "warning: option -t/--toolchain is deprecated."
+
if len(args) < 1:
raise Error("No nexe files specified. See --help for more info")
- if not options.toolchain:
- options.toolchain = DetermineToolchain(os.path.abspath(options.objdump))
-
- if options.toolchain not in ['newlib', 'glibc', 'pnacl']:
- raise Error('Unknown toolchain: ' + str(options.toolchain))
-
remap = {}
for ren in options.name:
parts = ren.split(',')
@@ -466,7 +498,6 @@ def Main(argv):
main_files=args,
lib_path=options.lib_path,
lib_prefix=path_prefix,
- toolchain=options.toolchain,
remap=remap)
nmf.GetManifest()
@@ -486,7 +517,7 @@ def Main(argv):
# Invoke this file directly for simple testing.
if __name__ == '__main__':
try:
- rtn = Main(sys.argv[1:])
+ rtn = main(sys.argv[1:])
except Error, e:
sys.stderr.write("%s: %s\n" % (os.path.basename(__file__), e))
rtn = 1