#!/usr/bin/env python import subprocess import re import sys def get_init_array(filename): # Call objdump -s -j .init_array to get the contents of the .init_array section try: objdump_output = subprocess.check_output(['objdump', '-s', '-j', '.init_array', filename], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: return [] objdump_output = objdump_output.decode('utf-8') objdump_output = objdump_output.split('\n') found_contents = False constructors = [] for line in objdump_output: if line.startswith("Contents of section .init_array:"): found_contents = True continue if found_contents: if not line.strip(): break line_re = re.compile(r'^ *[0-9a-f]+ (([0-9a-f]+) ([0-9a-f]+)) ?(([0-9a-f]+) ([0-9a-f]+))?') m = line_re.match(line) if not m: continue addr = m.group(1).replace(' ', '') addr = int.from_bytes(bytes.fromhex(addr), 'little') constructors.append(addr) try: addr = m.group(4) if not addr: continue addr = addr.replace(' ', '') addr = int.from_bytes(bytes.fromhex(addr), 'little') constructors.append(addr) except IndexError: pass return constructors def check_for_ffast_math(filename, addr): # Call objdump to disassemble filename at addr objdump_process = subprocess.Popen( ['objdump', f'--start-address={hex(addr)}', '-d', filename], stdout=subprocess.PIPE ) found_stmxcsr, found_8040, found_rdmxcsr = False, False, False for line in iter(lambda: objdump_process.stdout.readline(), b""): line = line.decode('utf-8') if "stmxcsr" in line: found_stmxcsr = True if "0x8040" in line: found_8040 = True if "ldmxcsr" in line: found_rdmxcsr = True if "retq" in line: objdump_process.kill() break return found_stmxcsr and found_8040 and found_rdmxcsr for filename in sys.argv[1:]: print(f"{filename} ", end="", flush=True) constructors = get_init_array(filename) i = len(constructors) print(f"({i} constructor{'s'[:i^1]}) ", end="", flush=True) for addr in constructors: if check_for_ffast_math(filename, addr): print(f"contains ffast-math constructor at {hex(addr)}") break else: print("is clean")