1*8d67ca89SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8d67ca89SAndroid Build Coastguard Worker# 3*8d67ca89SAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project 4*8d67ca89SAndroid Build Coastguard Worker# All rights reserved. 5*8d67ca89SAndroid Build Coastguard Worker# 6*8d67ca89SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*8d67ca89SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions 8*8d67ca89SAndroid Build Coastguard Worker# are met: 9*8d67ca89SAndroid Build Coastguard Worker# * Redistributions of source code must retain the above copyright 10*8d67ca89SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 11*8d67ca89SAndroid Build Coastguard Worker# * Redistributions in binary form must reproduce the above copyright 12*8d67ca89SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in 13*8d67ca89SAndroid Build Coastguard Worker# the documentation and/or other materials provided with the 14*8d67ca89SAndroid Build Coastguard Worker# distribution. 15*8d67ca89SAndroid Build Coastguard Worker# 16*8d67ca89SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17*8d67ca89SAndroid Build Coastguard Worker# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18*8d67ca89SAndroid Build Coastguard Worker# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19*8d67ca89SAndroid Build Coastguard Worker# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20*8d67ca89SAndroid Build Coastguard Worker# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21*8d67ca89SAndroid Build Coastguard Worker# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22*8d67ca89SAndroid Build Coastguard Worker# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23*8d67ca89SAndroid Build Coastguard Worker# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24*8d67ca89SAndroid Build Coastguard Worker# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25*8d67ca89SAndroid Build Coastguard Worker# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26*8d67ca89SAndroid Build Coastguard Worker# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*8d67ca89SAndroid Build Coastguard Worker# SUCH DAMAGE. 28*8d67ca89SAndroid Build Coastguard Worker 29*8d67ca89SAndroid Build Coastguard Worker# Generate a benchmark using a JSON dump of ELF file symbols and relocations. 30*8d67ca89SAndroid Build Coastguard Worker 31*8d67ca89SAndroid Build Coastguard Workerimport argparse 32*8d67ca89SAndroid Build Coastguard Workerimport codecs 33*8d67ca89SAndroid Build Coastguard Workerimport json 34*8d67ca89SAndroid Build Coastguard Workerimport math 35*8d67ca89SAndroid Build Coastguard Workerimport os 36*8d67ca89SAndroid Build Coastguard Workerimport re 37*8d67ca89SAndroid Build Coastguard Workerimport shlex 38*8d67ca89SAndroid Build Coastguard Workerimport shutil 39*8d67ca89SAndroid Build Coastguard Workerimport subprocess 40*8d67ca89SAndroid Build Coastguard Workerimport sys 41*8d67ca89SAndroid Build Coastguard Workerimport tempfile 42*8d67ca89SAndroid Build Coastguard Workerimport textwrap 43*8d67ca89SAndroid Build Coastguard Workerimport typing 44*8d67ca89SAndroid Build Coastguard Workerfrom enum import Enum 45*8d67ca89SAndroid Build Coastguard Workerfrom typing import Dict, List, Optional, Set 46*8d67ca89SAndroid Build Coastguard Workerfrom subprocess import PIPE, DEVNULL 47*8d67ca89SAndroid Build Coastguard Workerfrom pathlib import Path 48*8d67ca89SAndroid Build Coastguard Worker 49*8d67ca89SAndroid Build Coastguard Workerfrom common_types import LoadedLibrary, SymbolRef, SymBind, SymKind, bfs_walk, json_to_elf_tree 50*8d67ca89SAndroid Build Coastguard Worker 51*8d67ca89SAndroid Build Coastguard Worker 52*8d67ca89SAndroid Build Coastguard Workerg_obfuscate = True 53*8d67ca89SAndroid Build Coastguard Workerg_benchmark_name = 'linker_reloc_bench' 54*8d67ca89SAndroid Build Coastguard Worker 55*8d67ca89SAndroid Build Coastguard Worker 56*8d67ca89SAndroid Build Coastguard WorkerkBionicSonames: Set[str] = set([ 57*8d67ca89SAndroid Build Coastguard Worker 'libc.so', 58*8d67ca89SAndroid Build Coastguard Worker 'libdl.so', 59*8d67ca89SAndroid Build Coastguard Worker 'libdl_android.so', 60*8d67ca89SAndroid Build Coastguard Worker 'libm.so', 61*8d67ca89SAndroid Build Coastguard Worker 'ld-android.so', 62*8d67ca89SAndroid Build Coastguard Worker]) 63*8d67ca89SAndroid Build Coastguard Worker 64*8d67ca89SAndroid Build Coastguard Worker# Skip these symbols so the benchmark runs on multiple C libraries (glibc, Bionic, musl). 65*8d67ca89SAndroid Build Coastguard WorkerkBionicIgnoredSymbols: Set[str] = set([ 66*8d67ca89SAndroid Build Coastguard Worker '__FD_ISSET_chk', 67*8d67ca89SAndroid Build Coastguard Worker '__FD_SET_chk', 68*8d67ca89SAndroid Build Coastguard Worker '__assert', 69*8d67ca89SAndroid Build Coastguard Worker '__assert2', 70*8d67ca89SAndroid Build Coastguard Worker '__b64_ntop', 71*8d67ca89SAndroid Build Coastguard Worker '__cmsg_nxthdr', 72*8d67ca89SAndroid Build Coastguard Worker '__cxa_thread_atexit_impl', 73*8d67ca89SAndroid Build Coastguard Worker '__errno', 74*8d67ca89SAndroid Build Coastguard Worker '__gnu_basename', 75*8d67ca89SAndroid Build Coastguard Worker '__gnu_strerror_r', 76*8d67ca89SAndroid Build Coastguard Worker '__memcpy_chk', 77*8d67ca89SAndroid Build Coastguard Worker '__memmove_chk', 78*8d67ca89SAndroid Build Coastguard Worker '__memset_chk', 79*8d67ca89SAndroid Build Coastguard Worker '__open_2', 80*8d67ca89SAndroid Build Coastguard Worker '__openat_2', 81*8d67ca89SAndroid Build Coastguard Worker '__pread64_chk', 82*8d67ca89SAndroid Build Coastguard Worker '__pread_chk', 83*8d67ca89SAndroid Build Coastguard Worker '__read_chk', 84*8d67ca89SAndroid Build Coastguard Worker '__readlink_chk', 85*8d67ca89SAndroid Build Coastguard Worker '__register_atfork', 86*8d67ca89SAndroid Build Coastguard Worker '__sF', 87*8d67ca89SAndroid Build Coastguard Worker '__strcat_chk', 88*8d67ca89SAndroid Build Coastguard Worker '__strchr_chk', 89*8d67ca89SAndroid Build Coastguard Worker '__strcpy_chk', 90*8d67ca89SAndroid Build Coastguard Worker '__strlcat_chk', 91*8d67ca89SAndroid Build Coastguard Worker '__strlcpy_chk', 92*8d67ca89SAndroid Build Coastguard Worker '__strlen_chk', 93*8d67ca89SAndroid Build Coastguard Worker '__strncat_chk', 94*8d67ca89SAndroid Build Coastguard Worker '__strncpy_chk', 95*8d67ca89SAndroid Build Coastguard Worker '__strncpy_chk2', 96*8d67ca89SAndroid Build Coastguard Worker '__strrchr_chk', 97*8d67ca89SAndroid Build Coastguard Worker '__system_property_area_serial', 98*8d67ca89SAndroid Build Coastguard Worker '__system_property_find', 99*8d67ca89SAndroid Build Coastguard Worker '__system_property_foreach', 100*8d67ca89SAndroid Build Coastguard Worker '__system_property_get', 101*8d67ca89SAndroid Build Coastguard Worker '__system_property_read', 102*8d67ca89SAndroid Build Coastguard Worker '__system_property_serial', 103*8d67ca89SAndroid Build Coastguard Worker '__system_property_set', 104*8d67ca89SAndroid Build Coastguard Worker '__umask_chk', 105*8d67ca89SAndroid Build Coastguard Worker '__vsnprintf_chk', 106*8d67ca89SAndroid Build Coastguard Worker '__vsprintf_chk', 107*8d67ca89SAndroid Build Coastguard Worker 'android_dlopen_ext', 108*8d67ca89SAndroid Build Coastguard Worker 'android_set_abort_message', 109*8d67ca89SAndroid Build Coastguard Worker 'arc4random_buf', 110*8d67ca89SAndroid Build Coastguard Worker 'dl_unwind_find_exidx', 111*8d67ca89SAndroid Build Coastguard Worker 'fts_close', 112*8d67ca89SAndroid Build Coastguard Worker 'fts_open', 113*8d67ca89SAndroid Build Coastguard Worker 'fts_read', 114*8d67ca89SAndroid Build Coastguard Worker 'fts_set', 115*8d67ca89SAndroid Build Coastguard Worker 'getprogname', 116*8d67ca89SAndroid Build Coastguard Worker 'gettid', 117*8d67ca89SAndroid Build Coastguard Worker 'isnanf', 118*8d67ca89SAndroid Build Coastguard Worker 'lseek64', 119*8d67ca89SAndroid Build Coastguard Worker 'lstat64', 120*8d67ca89SAndroid Build Coastguard Worker 'mallinfo', 121*8d67ca89SAndroid Build Coastguard Worker 'malloc_info', 122*8d67ca89SAndroid Build Coastguard Worker 'pread64', 123*8d67ca89SAndroid Build Coastguard Worker 'pthread_gettid_np', 124*8d67ca89SAndroid Build Coastguard Worker 'pwrite64', 125*8d67ca89SAndroid Build Coastguard Worker 'res_mkquery', 126*8d67ca89SAndroid Build Coastguard Worker 'strlcpy', 127*8d67ca89SAndroid Build Coastguard Worker 'strtoll_l', 128*8d67ca89SAndroid Build Coastguard Worker 'strtoull_l', 129*8d67ca89SAndroid Build Coastguard Worker 'tgkill', 130*8d67ca89SAndroid Build Coastguard Worker]) 131*8d67ca89SAndroid Build Coastguard Worker 132*8d67ca89SAndroid Build Coastguard Worker 133*8d67ca89SAndroid Build Coastguard WorkerDefinitions = Dict[str, LoadedLibrary] 134*8d67ca89SAndroid Build Coastguard Worker 135*8d67ca89SAndroid Build Coastguard Workerdef build_symbol_index(lib: LoadedLibrary) -> Definitions: 136*8d67ca89SAndroid Build Coastguard Worker defs: Dict[str, LoadedLibrary] = {} 137*8d67ca89SAndroid Build Coastguard Worker for lib in bfs_walk(lib): 138*8d67ca89SAndroid Build Coastguard Worker for sym in lib.syms.values(): 139*8d67ca89SAndroid Build Coastguard Worker if not sym.defined: continue 140*8d67ca89SAndroid Build Coastguard Worker defs.setdefault(sym.name, lib) 141*8d67ca89SAndroid Build Coastguard Worker return defs 142*8d67ca89SAndroid Build Coastguard Worker 143*8d67ca89SAndroid Build Coastguard Worker 144*8d67ca89SAndroid Build Coastguard Workerdef check_rels(root: LoadedLibrary, defs: Definitions) -> None: 145*8d67ca89SAndroid Build Coastguard Worker # Find every symbol for every relocation in the load group. 146*8d67ca89SAndroid Build Coastguard Worker has_missing = False 147*8d67ca89SAndroid Build Coastguard Worker for lib in bfs_walk(root): 148*8d67ca89SAndroid Build Coastguard Worker rels = lib.rels 149*8d67ca89SAndroid Build Coastguard Worker for sym in rels.got + rels.jump_slots + [sym for off, sym in rels.symbolic]: 150*8d67ca89SAndroid Build Coastguard Worker if sym.name not in defs: 151*8d67ca89SAndroid Build Coastguard Worker if sym.is_weak: 152*8d67ca89SAndroid Build Coastguard Worker pass # print('info: weak undefined', lib.soname, r) 153*8d67ca89SAndroid Build Coastguard Worker else: 154*8d67ca89SAndroid Build Coastguard Worker print(f'error: {lib.soname}: unresolved relocation to {sym.name}') 155*8d67ca89SAndroid Build Coastguard Worker has_missing = True 156*8d67ca89SAndroid Build Coastguard Worker if has_missing: sys.exit('error: had unresolved relocations') 157*8d67ca89SAndroid Build Coastguard Worker 158*8d67ca89SAndroid Build Coastguard Worker 159*8d67ca89SAndroid Build Coastguard Worker# Obscure names to avoid polluting Android code search. 160*8d67ca89SAndroid Build Coastguard Workerdef rot13(text: str) -> str: 161*8d67ca89SAndroid Build Coastguard Worker if g_obfuscate: 162*8d67ca89SAndroid Build Coastguard Worker result = codecs.getencoder("rot-13")(text)[0] 163*8d67ca89SAndroid Build Coastguard Worker assert isinstance(result, str) 164*8d67ca89SAndroid Build Coastguard Worker return result 165*8d67ca89SAndroid Build Coastguard Worker else: 166*8d67ca89SAndroid Build Coastguard Worker return text 167*8d67ca89SAndroid Build Coastguard Worker 168*8d67ca89SAndroid Build Coastguard Worker 169*8d67ca89SAndroid Build Coastguard Workerdef make_asm_file(lib: LoadedLibrary, is_main: bool, out_filename: Path, map_out_filename: Path, 170*8d67ca89SAndroid Build Coastguard Worker defs: Definitions) -> bool: 171*8d67ca89SAndroid Build Coastguard Worker 172*8d67ca89SAndroid Build Coastguard Worker def trans_sym(name: str, ver: Optional[str]) -> Optional[str]: 173*8d67ca89SAndroid Build Coastguard Worker nonlocal defs 174*8d67ca89SAndroid Build Coastguard Worker d = defs.get(name) 175*8d67ca89SAndroid Build Coastguard Worker if d is not None and d.soname in kBionicSonames: 176*8d67ca89SAndroid Build Coastguard Worker if name in kBionicIgnoredSymbols: return None 177*8d67ca89SAndroid Build Coastguard Worker # Discard relocations to newer Bionic symbols, because there aren't many of them, and 178*8d67ca89SAndroid Build Coastguard Worker # they would limit where the benchmark can run. 179*8d67ca89SAndroid Build Coastguard Worker if ver == 'LIBC': return name 180*8d67ca89SAndroid Build Coastguard Worker return None 181*8d67ca89SAndroid Build Coastguard Worker return 'b_' + rot13(name) 182*8d67ca89SAndroid Build Coastguard Worker 183*8d67ca89SAndroid Build Coastguard Worker versions: Dict[Optional[str], List[str]] = {} 184*8d67ca89SAndroid Build Coastguard Worker 185*8d67ca89SAndroid Build Coastguard Worker with open(out_filename, 'w') as out: 186*8d67ca89SAndroid Build Coastguard Worker out.write(f'// AUTO-GENERATED BY {os.path.basename(__file__)} -- do not edit manually\n') 187*8d67ca89SAndroid Build Coastguard Worker out.write(f'#include "{g_benchmark_name}_asm.h"\n') 188*8d67ca89SAndroid Build Coastguard Worker out.write('.data\n') 189*8d67ca89SAndroid Build Coastguard Worker out.write('.p2align 4\n') 190*8d67ca89SAndroid Build Coastguard Worker 191*8d67ca89SAndroid Build Coastguard Worker if is_main: 192*8d67ca89SAndroid Build Coastguard Worker out.write('.text\n' 'MAIN\n') 193*8d67ca89SAndroid Build Coastguard Worker 194*8d67ca89SAndroid Build Coastguard Worker for d in lib.syms.values(): 195*8d67ca89SAndroid Build Coastguard Worker if not d.defined: continue 196*8d67ca89SAndroid Build Coastguard Worker sym = trans_sym(d.name, None) 197*8d67ca89SAndroid Build Coastguard Worker if sym is None: continue 198*8d67ca89SAndroid Build Coastguard Worker binding = 'weak' if d.bind == SymBind.Weak else 'globl' 199*8d67ca89SAndroid Build Coastguard Worker if d.kind == SymKind.Func: 200*8d67ca89SAndroid Build Coastguard Worker out.write('.text\n' 201*8d67ca89SAndroid Build Coastguard Worker f'.{binding} {sym}\n' 202*8d67ca89SAndroid Build Coastguard Worker f'.type {sym},%function\n' 203*8d67ca89SAndroid Build Coastguard Worker f'{sym}:\n' 204*8d67ca89SAndroid Build Coastguard Worker 'nop\n') 205*8d67ca89SAndroid Build Coastguard Worker else: # SymKind.Var 206*8d67ca89SAndroid Build Coastguard Worker out.write('.data\n' 207*8d67ca89SAndroid Build Coastguard Worker f'.{binding} {sym}\n' 208*8d67ca89SAndroid Build Coastguard Worker f'.type {sym},%object\n' 209*8d67ca89SAndroid Build Coastguard Worker f'{sym}:\n' 210*8d67ca89SAndroid Build Coastguard Worker f'.space __SIZEOF_POINTER__\n') 211*8d67ca89SAndroid Build Coastguard Worker versions.setdefault(d.ver_name, []).append(sym) 212*8d67ca89SAndroid Build Coastguard Worker 213*8d67ca89SAndroid Build Coastguard Worker out.write('.text\n') 214*8d67ca89SAndroid Build Coastguard Worker for r in lib.rels.jump_slots: 215*8d67ca89SAndroid Build Coastguard Worker sym = trans_sym(r.name, r.ver) 216*8d67ca89SAndroid Build Coastguard Worker if sym is None: continue 217*8d67ca89SAndroid Build Coastguard Worker if r.is_weak: out.write(f'.weak {sym}\n') 218*8d67ca89SAndroid Build Coastguard Worker out.write(f'CALL({sym})\n') 219*8d67ca89SAndroid Build Coastguard Worker out.write('.text\n') 220*8d67ca89SAndroid Build Coastguard Worker for r in lib.rels.got: 221*8d67ca89SAndroid Build Coastguard Worker sym = trans_sym(r.name, r.ver) 222*8d67ca89SAndroid Build Coastguard Worker if sym is None: continue 223*8d67ca89SAndroid Build Coastguard Worker if r.is_weak: out.write(f'.weak {sym}\n') 224*8d67ca89SAndroid Build Coastguard Worker out.write(f'GOT_RELOC({sym})\n') 225*8d67ca89SAndroid Build Coastguard Worker 226*8d67ca89SAndroid Build Coastguard Worker out.write('.data\n') 227*8d67ca89SAndroid Build Coastguard Worker out.write('local_label:\n') 228*8d67ca89SAndroid Build Coastguard Worker 229*8d67ca89SAndroid Build Coastguard Worker image = [] 230*8d67ca89SAndroid Build Coastguard Worker for off in lib.rels.relative: 231*8d67ca89SAndroid Build Coastguard Worker image.append((off, f'DATA_WORD(local_label)\n')) 232*8d67ca89SAndroid Build Coastguard Worker for off, r in lib.rels.symbolic: 233*8d67ca89SAndroid Build Coastguard Worker sym = trans_sym(r.name, r.ver) 234*8d67ca89SAndroid Build Coastguard Worker if sym is None: continue 235*8d67ca89SAndroid Build Coastguard Worker text = f'DATA_WORD({sym})\n' 236*8d67ca89SAndroid Build Coastguard Worker if r.is_weak: text += f'.weak {sym}\n' 237*8d67ca89SAndroid Build Coastguard Worker image.append((off, text)) 238*8d67ca89SAndroid Build Coastguard Worker image.sort() 239*8d67ca89SAndroid Build Coastguard Worker 240*8d67ca89SAndroid Build Coastguard Worker cur_off = 0 241*8d67ca89SAndroid Build Coastguard Worker for off, text in image: 242*8d67ca89SAndroid Build Coastguard Worker if cur_off < off: 243*8d67ca89SAndroid Build Coastguard Worker out.write(f'.space (__SIZEOF_POINTER__ * {off - cur_off})\n') 244*8d67ca89SAndroid Build Coastguard Worker cur_off = off 245*8d67ca89SAndroid Build Coastguard Worker out.write(text) 246*8d67ca89SAndroid Build Coastguard Worker cur_off += 1 247*8d67ca89SAndroid Build Coastguard Worker 248*8d67ca89SAndroid Build Coastguard Worker has_map_file = False 249*8d67ca89SAndroid Build Coastguard Worker if len(versions) > 0 and list(versions.keys()) != [None]: 250*8d67ca89SAndroid Build Coastguard Worker has_map_file = True 251*8d67ca89SAndroid Build Coastguard Worker with open(map_out_filename, 'w') as out: 252*8d67ca89SAndroid Build Coastguard Worker if None in versions: 253*8d67ca89SAndroid Build Coastguard Worker print(f'error: {out_filename} has both unversioned and versioned symbols') 254*8d67ca89SAndroid Build Coastguard Worker print(versions.keys()) 255*8d67ca89SAndroid Build Coastguard Worker sys.exit(1) 256*8d67ca89SAndroid Build Coastguard Worker for ver in sorted(versions.keys()): 257*8d67ca89SAndroid Build Coastguard Worker assert ver is not None 258*8d67ca89SAndroid Build Coastguard Worker out.write(f'{rot13(ver)} {{\n') 259*8d67ca89SAndroid Build Coastguard Worker if len(versions[ver]) > 0: 260*8d67ca89SAndroid Build Coastguard Worker out.write(' global:\n') 261*8d67ca89SAndroid Build Coastguard Worker out.write(''.join(f' {x};\n' for x in versions[ver])) 262*8d67ca89SAndroid Build Coastguard Worker out.write(f'}};\n') 263*8d67ca89SAndroid Build Coastguard Worker 264*8d67ca89SAndroid Build Coastguard Worker return has_map_file 265*8d67ca89SAndroid Build Coastguard Worker 266*8d67ca89SAndroid Build Coastguard Worker 267*8d67ca89SAndroid Build Coastguard Workerclass LibNames: 268*8d67ca89SAndroid Build Coastguard Worker def __init__(self, root: LoadedLibrary): 269*8d67ca89SAndroid Build Coastguard Worker self._root = root 270*8d67ca89SAndroid Build Coastguard Worker self._names: Dict[LoadedLibrary, str] = {} 271*8d67ca89SAndroid Build Coastguard Worker all_libs = [x for x in bfs_walk(root) if x is not root and x.soname not in kBionicSonames] 272*8d67ca89SAndroid Build Coastguard Worker num_digits = math.ceil(math.log10(len(all_libs) + 1)) 273*8d67ca89SAndroid Build Coastguard Worker if g_obfuscate: 274*8d67ca89SAndroid Build Coastguard Worker self._names = {x : f'{i:0{num_digits}}' for i, x in enumerate(all_libs)} 275*8d67ca89SAndroid Build Coastguard Worker else: 276*8d67ca89SAndroid Build Coastguard Worker self._names = {x : re.sub(r'\.so$', '', x.soname) for x in all_libs} 277*8d67ca89SAndroid Build Coastguard Worker 278*8d67ca89SAndroid Build Coastguard Worker def name(self, lib: LoadedLibrary) -> str: 279*8d67ca89SAndroid Build Coastguard Worker if lib is self._root: 280*8d67ca89SAndroid Build Coastguard Worker return f'{g_benchmark_name}_main' 281*8d67ca89SAndroid Build Coastguard Worker else: 282*8d67ca89SAndroid Build Coastguard Worker return f'lib{g_benchmark_name}_{self._names[lib]}' 283*8d67ca89SAndroid Build Coastguard Worker 284*8d67ca89SAndroid Build Coastguard Worker 285*8d67ca89SAndroid Build Coastguard Worker# Generate a ninja file directly that builds the benchmark using a C compiler driver and ninja. 286*8d67ca89SAndroid Build Coastguard Worker# Using a driver directly can be faster than building with Soong, and it allows testing 287*8d67ca89SAndroid Build Coastguard Worker# configurations that Soong can't target, like musl. 288*8d67ca89SAndroid Build Coastguard Workerdef make_ninja_benchmark(root: LoadedLibrary, defs: Definitions, cc: str, out: Path) -> None: 289*8d67ca89SAndroid Build Coastguard Worker 290*8d67ca89SAndroid Build Coastguard Worker lib_names = LibNames(root) 291*8d67ca89SAndroid Build Coastguard Worker 292*8d67ca89SAndroid Build Coastguard Worker def lib_dso_name(lib: LoadedLibrary) -> str: 293*8d67ca89SAndroid Build Coastguard Worker return lib_names.name(lib) + '.so' 294*8d67ca89SAndroid Build Coastguard Worker 295*8d67ca89SAndroid Build Coastguard Worker ninja = open(out / 'build.ninja', 'w') 296*8d67ca89SAndroid Build Coastguard Worker include_path = os.path.relpath(os.path.dirname(__file__) + '/../include', out) 297*8d67ca89SAndroid Build Coastguard Worker common_flags = f"-Wl,-rpath-link,. -lm -I{include_path}" 298*8d67ca89SAndroid Build Coastguard Worker ninja.write(textwrap.dedent(f'''\ 299*8d67ca89SAndroid Build Coastguard Worker rule exe 300*8d67ca89SAndroid Build Coastguard Worker command = {cc} -fpie -pie $in -o $out {common_flags} $extra_args 301*8d67ca89SAndroid Build Coastguard Worker rule dso 302*8d67ca89SAndroid Build Coastguard Worker command = {cc} -fpic -shared $in -o $out -Wl,-soname,$out {common_flags} $extra_args 303*8d67ca89SAndroid Build Coastguard Worker ''')) 304*8d67ca89SAndroid Build Coastguard Worker 305*8d67ca89SAndroid Build Coastguard Worker for lib in bfs_walk(root): 306*8d67ca89SAndroid Build Coastguard Worker if lib.soname in kBionicSonames: continue 307*8d67ca89SAndroid Build Coastguard Worker 308*8d67ca89SAndroid Build Coastguard Worker lib_base_name = lib_names.name(lib) 309*8d67ca89SAndroid Build Coastguard Worker asm_name = lib_base_name + '.S' 310*8d67ca89SAndroid Build Coastguard Worker map_name = lib_base_name + '.map' 311*8d67ca89SAndroid Build Coastguard Worker asm_path = out / asm_name 312*8d67ca89SAndroid Build Coastguard Worker map_path = out / map_name 313*8d67ca89SAndroid Build Coastguard Worker 314*8d67ca89SAndroid Build Coastguard Worker has_map_file = make_asm_file(lib, lib is root, asm_path, map_path, defs) 315*8d67ca89SAndroid Build Coastguard Worker needed = ' '.join([lib_dso_name(x) for x in lib.needed if x.soname not in kBionicSonames]) 316*8d67ca89SAndroid Build Coastguard Worker 317*8d67ca89SAndroid Build Coastguard Worker if lib is root: 318*8d67ca89SAndroid Build Coastguard Worker ninja.write(f'build {lib_base_name}: exe {asm_name} {needed}\n') 319*8d67ca89SAndroid Build Coastguard Worker else: 320*8d67ca89SAndroid Build Coastguard Worker ninja.write(f'build {lib_dso_name(lib)}: dso {asm_name} {needed}\n') 321*8d67ca89SAndroid Build Coastguard Worker if has_map_file: 322*8d67ca89SAndroid Build Coastguard Worker ninja.write(f' extra_args = -Wl,--version-script={map_name}\n') 323*8d67ca89SAndroid Build Coastguard Worker 324*8d67ca89SAndroid Build Coastguard Worker ninja.close() 325*8d67ca89SAndroid Build Coastguard Worker 326*8d67ca89SAndroid Build Coastguard Worker subprocess.run(['ninja', '-C', str(out), lib_names.name(root)], check=True) 327*8d67ca89SAndroid Build Coastguard Worker 328*8d67ca89SAndroid Build Coastguard Worker 329*8d67ca89SAndroid Build Coastguard Workerdef make_soong_benchmark(root: LoadedLibrary, defs: Definitions, out: Path) -> None: 330*8d67ca89SAndroid Build Coastguard Worker 331*8d67ca89SAndroid Build Coastguard Worker lib_names = LibNames(root) 332*8d67ca89SAndroid Build Coastguard Worker 333*8d67ca89SAndroid Build Coastguard Worker bp = open(out / 'Android.bp', 'w') 334*8d67ca89SAndroid Build Coastguard Worker bp.write(f'// AUTO-GENERATED BY {os.path.basename(__file__)} -- do not edit\n') 335*8d67ca89SAndroid Build Coastguard Worker 336*8d67ca89SAndroid Build Coastguard Worker bp.write(f'package {{ default_applicable_licenses: ["bionic_benchmarks_license"], }}\n') 337*8d67ca89SAndroid Build Coastguard Worker bp.write(f'cc_defaults {{\n') 338*8d67ca89SAndroid Build Coastguard Worker bp.write(f' name: "{g_benchmark_name}_all_libs",\n') 339*8d67ca89SAndroid Build Coastguard Worker bp.write(f' runtime_libs: [\n') 340*8d67ca89SAndroid Build Coastguard Worker for lib in bfs_walk(root): 341*8d67ca89SAndroid Build Coastguard Worker if lib.soname in kBionicSonames: continue 342*8d67ca89SAndroid Build Coastguard Worker if lib is root: continue 343*8d67ca89SAndroid Build Coastguard Worker bp.write(f' "{lib_names.name(lib)}",\n') 344*8d67ca89SAndroid Build Coastguard Worker bp.write(f' ],\n') 345*8d67ca89SAndroid Build Coastguard Worker bp.write(f'}}\n') 346*8d67ca89SAndroid Build Coastguard Worker 347*8d67ca89SAndroid Build Coastguard Worker for lib in bfs_walk(root): 348*8d67ca89SAndroid Build Coastguard Worker if lib.soname in kBionicSonames: continue 349*8d67ca89SAndroid Build Coastguard Worker 350*8d67ca89SAndroid Build Coastguard Worker lib_base_name = lib_names.name(lib) 351*8d67ca89SAndroid Build Coastguard Worker asm_name = lib_base_name + '.S' 352*8d67ca89SAndroid Build Coastguard Worker map_name = lib_base_name + '.map' 353*8d67ca89SAndroid Build Coastguard Worker asm_path = out / asm_name 354*8d67ca89SAndroid Build Coastguard Worker map_path = out / map_name 355*8d67ca89SAndroid Build Coastguard Worker 356*8d67ca89SAndroid Build Coastguard Worker has_map_file = make_asm_file(lib, lib is root, asm_path, map_path, defs) 357*8d67ca89SAndroid Build Coastguard Worker 358*8d67ca89SAndroid Build Coastguard Worker if lib is root: 359*8d67ca89SAndroid Build Coastguard Worker bp.write(f'cc_binary {{\n') 360*8d67ca89SAndroid Build Coastguard Worker bp.write(f' defaults: ["{g_benchmark_name}_binary"],\n') 361*8d67ca89SAndroid Build Coastguard Worker else: 362*8d67ca89SAndroid Build Coastguard Worker bp.write(f'cc_test_library {{\n') 363*8d67ca89SAndroid Build Coastguard Worker bp.write(f' defaults: ["{g_benchmark_name}_library"],\n') 364*8d67ca89SAndroid Build Coastguard Worker bp.write(f' name: "{lib_base_name}",\n') 365*8d67ca89SAndroid Build Coastguard Worker bp.write(f' srcs: ["{asm_name}"],\n') 366*8d67ca89SAndroid Build Coastguard Worker bp.write(f' shared_libs: [\n') 367*8d67ca89SAndroid Build Coastguard Worker for need in lib.needed: 368*8d67ca89SAndroid Build Coastguard Worker if need.soname in kBionicSonames: continue 369*8d67ca89SAndroid Build Coastguard Worker bp.write(f' "{lib_names.name(need)}",\n') 370*8d67ca89SAndroid Build Coastguard Worker bp.write(f' ],\n') 371*8d67ca89SAndroid Build Coastguard Worker if has_map_file: 372*8d67ca89SAndroid Build Coastguard Worker bp.write(f' version_script: "{map_name}",\n') 373*8d67ca89SAndroid Build Coastguard Worker bp.write('}\n') 374*8d67ca89SAndroid Build Coastguard Worker 375*8d67ca89SAndroid Build Coastguard Worker bp.close() 376*8d67ca89SAndroid Build Coastguard Worker 377*8d67ca89SAndroid Build Coastguard Worker 378*8d67ca89SAndroid Build Coastguard Workerdef main() -> None: 379*8d67ca89SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 380*8d67ca89SAndroid Build Coastguard Worker parser.add_argument('input', type=str) 381*8d67ca89SAndroid Build Coastguard Worker parser.add_argument('out_dir', type=str) 382*8d67ca89SAndroid Build Coastguard Worker parser.add_argument('--ninja', action='store_true', 383*8d67ca89SAndroid Build Coastguard Worker help='Generate a benchmark using a compiler and ninja rather than Soong') 384*8d67ca89SAndroid Build Coastguard Worker parser.add_argument('--cc', 385*8d67ca89SAndroid Build Coastguard Worker help='For --ninja, a target-specific C clang driver and flags (e.g. "' 386*8d67ca89SAndroid Build Coastguard Worker '$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang' 387*8d67ca89SAndroid Build Coastguard Worker ' -fuse-ld=lld")') 388*8d67ca89SAndroid Build Coastguard Worker 389*8d67ca89SAndroid Build Coastguard Worker args = parser.parse_args() 390*8d67ca89SAndroid Build Coastguard Worker 391*8d67ca89SAndroid Build Coastguard Worker if args.ninja: 392*8d67ca89SAndroid Build Coastguard Worker if args.cc is None: sys.exit('error: --cc required with --ninja') 393*8d67ca89SAndroid Build Coastguard Worker 394*8d67ca89SAndroid Build Coastguard Worker out = Path(args.out_dir) 395*8d67ca89SAndroid Build Coastguard Worker with open(Path(args.input)) as f: 396*8d67ca89SAndroid Build Coastguard Worker root = json_to_elf_tree(json.load(f)) 397*8d67ca89SAndroid Build Coastguard Worker defs = build_symbol_index(root) 398*8d67ca89SAndroid Build Coastguard Worker check_rels(root, defs) 399*8d67ca89SAndroid Build Coastguard Worker 400*8d67ca89SAndroid Build Coastguard Worker if out.exists(): shutil.rmtree(out) 401*8d67ca89SAndroid Build Coastguard Worker os.makedirs(str(out)) 402*8d67ca89SAndroid Build Coastguard Worker 403*8d67ca89SAndroid Build Coastguard Worker if args.ninja: 404*8d67ca89SAndroid Build Coastguard Worker make_ninja_benchmark(root, defs, args.cc, out) 405*8d67ca89SAndroid Build Coastguard Worker else: 406*8d67ca89SAndroid Build Coastguard Worker make_soong_benchmark(root, defs, out) 407*8d67ca89SAndroid Build Coastguard Worker 408*8d67ca89SAndroid Build Coastguard Worker 409*8d67ca89SAndroid Build Coastguard Workerif __name__ == '__main__': 410*8d67ca89SAndroid Build Coastguard Worker main() 411