1# -*- python -*- 2# Copyright (c) 2015 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 6import os 7import os.path 8 9Import('env') 10 11if env.Bit('bitcode'): 12 Return() 13 14# elf_loader requires some IRT interfaces. 15if not env.Bit('tests_use_irt'): 16 Return() 17 18# The builds here don't make sense for dynamic linking. 19if not env.Bit('nacl_static_link'): 20 Return() 21 22# elf_loader only handles ELFCLASS32, not ELFCLASS64. 23# TODO(mcgrathr): Remove this check when x86-64 switches to ELFCLASS32. 24if env.Bit('build_x86_64'): 25 Return() 26 27nacl_env = env['NACL_ENV'] 28loader_nexe = nacl_env.File('${STAGING_DIR}/elf_loader.nexe') 29 30golden_file = env.File('echo.stdout') 31echo_args = open(str(golden_file)).read().splitlines() 32 33def BuildWithFlags(name, source, link_flags, c_flags=[], cppdefines=[]): 34 prog_env = env.Clone() 35 prog_env.Append(LINKFLAGS=link_flags) 36 prog_env.Append(CCFLAGS=c_flags) 37 prog_env.Append(CPPDEFINES=cppdefines) 38 obj = prog_env.ComponentObject(name + '.o', source) 39 prog = prog_env.ComponentProgram(name, obj) 40 return prog 41 42def LoaderTest(name, depends_on=None, **kwargs): 43 out_name = 'elf_loader_%s_test.out' % name 44 run_name = 'run_elf_loader_%s_test' % name 45 node = env.CommandSelLdrTestNacl(out_name, 46 loader_nexe, 47 sel_ldr_flags=['-a'], 48 **kwargs) 49 if depends_on is not None: 50 env.Depends(node, depends_on) 51 env.AddNodeToTestSuite(node, ['small_tests', 'sel_ldr_tests'], run_name) 52 53# For each test foo we run it in two variants: foo, where mmap works; 54# and foo_dyncode, where mmap refuses to work for the code segment. 55# This tests the fallback path using dyncode_create, replicating the 56# situation in the browser for a nexe not in a "blessed" location. 57def LoaderTests(name, depends_on=None, **kwargs): 58 LoaderTest(name, depends_on, **kwargs) 59 LoaderTest(name + '_dyncode', depends_on, 60 osenv=['NACL_FAULT_INJECTION=' + 61 'MMAP_FORCE_DESCRIPTOR_SAFETY_CHECK_FAIL=GF@'], 62 **kwargs) 63 64# These are arbitrary, but should be different from each, and positive. 65dyn_exit_status = 17 66pie_exit_status = 23 67 68# Build a tiny standalone ET_DYN object that will stand in for 69# a dynamic linker. Test loading that as the main program. 70interp_nexe = BuildWithFlags('interp', 'interp.c', 71 ['-nostdlib', '-shared'], 72 ['-fPIC', '-fno-asynchronous-unwind-tables'], 73 [['TEST_EXIT', str(dyn_exit_status)]]) 74LoaderTests('dyn', args=[interp_nexe], exit_status=dyn_exit_status) 75 76# nacl-clang fails to grok -pie. See: 77# https://code.google.com/p/nativeclient/issues/detail?id=4148 78# TODO(mcgrathr): Remove the conditional when that's fixed. 79if not env.Bit('nacl_clang'): 80 # Build a tiny PIE that uses 'interp' (above) as its "dynamic linker". 81 # Test loading an ET_DYN object with a PT_INTERP. 82 pie_nexe = BuildWithFlags('pie', 'interp.c', 83 ['-nostdlib', '-pie', 84 '-Wl,-dynamic-linker=%s' % interp_nexe.abspath], 85 ['-fPIE', '-fno-asynchronous-unwind-tables'], 86 [['TEST_EXIT', str(pie_exit_status)]]) 87 LoaderTests('pie', args=[pie_nexe], exit_status=pie_exit_status) 88 89# elf_loader itself loads at the canonical "main nexe" address of 0x20000. 90# This address just needs to be high enough above that to leave space for 91# elf_loader's own code segment. 92text_start = '-Ttext-segment=0x100000' 93 94# Build a normal executable both with and without a PT_INTERP. 95def EchoTest(name, interpreter=None, loader_args=[]): 96 nexe_name = 'echo_' + name 97 cppdefines = [] 98 if interpreter is not None: 99 cppdefines.append(['INTERPRETER', interpreter]) 100 nexe = BuildWithFlags(nexe_name, 'echo.c', 101 ['-Wl,' + text_start], 102 cppdefines=cppdefines) 103 LoaderTests(nexe_name, 104 depends_on=interp_nexe if interpreter is not None else None, 105 args=loader_args + [nexe] + echo_args, 106 stdout_golden=golden_file) 107 108EchoTest('plain') 109 110# Turn a native pathname on Windows into a '/'-separated one. 111interp_abspath = os.path.splitdrive(interp_nexe.abspath)[1].split(os.sep) 112EchoTest('interp', '/'.join(interp_abspath)) 113 114interp_name = '/' + interp_abspath[-1] 115interp_prefix = '/'.join(interp_abspath[:-1]) 116EchoTest('interp_prefix', interp_name, 117 ['--interp-prefix', interp_prefix]) 118 119onlycode_obj = env.ComponentObject('onlycode.o', 'onlycode.S') 120# Newer toolchains include an allocated SHT_NOTE section (.note.NaCl.ABI.*) 121# in every object file, that just contributes to RODATA. We do not want 122# any RODATA at all for this test. 123onlycode_text_obj = env.Command('onlycode_text.o', onlycode_obj, 124 '${OBJCOPY} -j .text ${SOURCES} ${TARGET}') 125onlycode_env = env.Clone() 126onlycode_env.Append(LINKFLAGS=[ 127 '-nostdlib', 128 '-Wl,--build-id=none', # A build ID is just more RODATA we don't want. 129 '-Wl,--section-start=.text=0x100000', 130 ]) 131nexe = onlycode_env.ComponentProgram('onlycode', onlycode_text_obj) 132LoaderTests('onlycode', args=[nexe]) 133