1# -*- 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 6Import('env') 7 8# All tests below involve native assembler 9 10HALT_SLED_SIZE=32 11 12# Valgrind gets confused by these tests 13 14if env.IsRunningUnderValgrind(): 15 Return() 16 17# glibc linker script enforces gap; test needs to be updated to use 18# custom linker script in this case. 19if env.Bit('nacl_glibc'): 20 Return() 21 22# TODO(dschuff): either re-enable this test after we have fully transitioned 23# to new-style layout and ironed out any potential gold issues, or remove 24# all pnacl-specific stuff below and in the asm files. 25# 26# It is unlikely that we will re-enable these tests under the PNaCl 27# toolchain, because they depend on invoking "ld" directly, which is not 28# really a supported use of the PNaCl toolchain. These tests are too 29# dependent on the layout that the linker happens to produce, so the tests 30# are likely to break or become ineffective if the linker is changed. 31if env.Bit('bitcode'): 32 Return() 33 34# TODO(petarj): Enable these tests when llvm integrated assembler can handle 35# expressions from nacl_text_pad_test.S. 36if env.Bit('build_mips32') and env.Bit('nacl_clang'): 37 Return() 38 39# ---------------------------------------------------------- 40# Tests that require a NaCl module 41# ---------------------------------------------------------- 42 43if env.Bit('build_x86_32'): 44 nacl_text_pad_asm = 'arch/x86_32/nacl_text_pad_test.S' 45elif env.Bit('build_x86_64'): 46 nacl_text_pad_asm = 'arch/x86_64/nacl_text_pad_test.S' 47elif env.Bit('build_arm'): 48 nacl_text_pad_asm = 'arch/arm/nacl_text_pad_test.S' 49elif env.Bit('build_mips32'): 50 nacl_text_pad_asm = 'arch/mips/nacl_text_pad_test.S' 51else: 52 raise Exception('unknown architecture') 53 54def NewAsmEnv(env, defines, rodata_address, rwdata_address): 55 asm_env = env.Clone() 56 # NOTE(robertm): convert this to pure C code so that most of this 57 # special handling can be eliminated 58 link_cmd = ('${LD} -static -e _start ${TEXT_START} ${RO_START} ${RW_START}' + 59 ' -o ${TARGET} ${SOURCES}') 60 61 if env.Bit('build_x86_32'): 62 link_cmd += ' -melf_i386_nacl' 63 elif env.Bit('build_x86_64'): 64 link_cmd += ' -melf_x86_64_nacl' 65 elif env.Bit('build_arm'): 66 link_cmd += ' -marmelf_nacl' 67 elif env.Bit('build_mips32'): 68 link_cmd += ' -mmipselelf_nacl' 69 else: 70 raise Exception('unknown architecture') 71 72 asm_env['LINKCOM'] = link_cmd 73 74 asm_env.Append(CPPDEFINES = [ 75 ['NACL_BUILD_ARCH', '${BUILD_ARCHITECTURE}' ], 76 ['NACL_BUILD_SUBARCH', '${BUILD_SUBARCH}' ], 77 ]) 78 79 asm_env.Append(CPPDEFINES=defines) 80 81 asm_env['TEXT_START'] = '--section-start .text=0x%x' % 0x20000 82 if rodata_address: 83 asm_env['RO_START'] = '-Trodata-segment=0x%x' % rodata_address 84 if rwdata_address: 85 asm_env['RW_START'] = '--section-start .data=0x%x' % rwdata_address 86 87 return asm_env 88 89 90ALLOCATION_SIZE = 0x10000 91START_OF_TEXT = 0x20000 92TEXT_SIZE_BOUND = 0x10000 # estimate of test code size 93RODATA_SIZE_BOUND = 0x10000 94RWDATA_SIZE = 0x4 # if we have rwdata, we must use exactly one word! 95 96 97def EndOfText(text_end_modulus): 98 return START_OF_TEXT + text_end_modulus 99 100 101def RoundUpToAllocSize(size): 102 return (size + ALLOCATION_SIZE - 1) & ~(ALLOCATION_SIZE - 1) 103 104 105def TextGap(text_end): 106 end_of_text = EndOfText(text_end) 107 rounded_end_of_text = RoundUpToAllocSize(end_of_text) 108 text_gap = rounded_end_of_text - end_of_text 109 return text_gap 110 111 112def NaturalRodataStart(text_end): 113 extra = 0 114 text_gap = TextGap(text_end) 115 if text_gap < HALT_SLED_SIZE: 116 extra = ALLOCATION_SIZE 117 return RoundUpToAllocSize(START_OF_TEXT + TEXT_SIZE_BOUND + extra) 118 119 120def ExpectedBreak(text_end, rodata_addr, rwdata_addr, rwdata_size): 121 # The new linker always pads the text segment out to a page boundary. 122 text_end = RoundUpToAllocSize(text_end) 123 if rwdata_addr is None: 124 if rodata_addr is None: 125 break_addr = NaturalRodataStart(text_end) 126 else: 127 break_addr = RoundUpToAllocSize(rodata_addr + RODATA_SIZE_BOUND) 128 else: 129 break_addr = rwdata_addr + rwdata_size 130 return break_addr 131 132test_specs = [ (0x10000, 'no'), 133 (0x10000 - 32, 'small'), 134 ( 0x8000, 'large'), 135 (0x10000 - 28, 'too_small') ] 136 137rwdata_address = None # none for now 138 139for text_end, variant in test_specs: 140 for rodata_address, name_modifier in [ (None, ''), 141 (0, '_ro'), 142 (0x100000, '_ro_dyn') ]: 143 144 if rodata_address is None and env.UsesAbiNote(): 145 # This toolchain always produces some rodata. 146 rodata_address = 0 147 148 # rodata_address is None when no .rodata section should appear 149 # in the generated nexe, and is 0 when it should appear in the 150 # natural location (as defined by the linker script); when it 151 # has a non-zero numeric value, then the .rodata section is 152 # forced to start at that address. 153 if rodata_address == 0: 154 rodata_address = NaturalRodataStart(text_end) 155 # rodata_address is None or a non-zero integer 156 157 break_address = ExpectedBreak(text_end, 158 rodata_address, 159 rwdata_address, 160 RWDATA_SIZE) 161 162 defines=[] 163 for (symbol, value) in [('TEXT_EXTEND', text_end), 164 ('EXPECTED_BREAK', break_address), 165 ('EXPECTED_RODATA', rodata_address), 166 ('EXPECTED_RWDATA', rwdata_address)]: 167 if value is not None: 168 defines += [[symbol, str(value)]] 169 170 asm_env = NewAsmEnv(env, defines, rodata_address, rwdata_address) 171 172 base_name = 'nacl_text_' + variant + '_pad' + name_modifier + '_test' 173 obj = asm_env.ComponentObject(base_name + '.o', nacl_text_pad_asm) 174 175 nexe = asm_env.ComponentProgram(base_name, [obj]) 176 177 if (rodata_address is not None and 178 rodata_address <= START_OF_TEXT + ALLOCATION_SIZE): 179 # With the new linker, the code segment is padded out to 180 # ALLOCATION_SIZE with nops, so the rodata segment starts immediately 181 # thereafter with no space for a halt sled. Ensure sel_ldr catches 182 # that case. NaClAbort() behaves differently when code coverage is 183 # enabled: it calls exit() rather than abort(). 184 if 'TRUSTED_ENV' in env and env['TRUSTED_ENV'].Bit('coverage_enabled'): 185 expected_exit_status = 'naclabort_coverage' 186 else: 187 expected_exit_status = 'trusted_sigabrt' 188 else: 189 expected_exit_status = 0 190 191 node = env.CommandSelLdrTestNacl(base_name + '.out', nexe, 192 exit_status=expected_exit_status) 193 194 env.AddNodeToTestSuite(node, 195 ['small_tests', 'sel_ldr_sled_tests'], 196 'run_' + base_name) 197