#!/usr/bin/python # This scripts check all the required stuff for proper support of GNU indirect # functions (ifunc). # To properly support ifunc, both the toolchain (gcc + binutils) and the runtime # (glibc or bionic) must support it. import os import sys import subprocess import shlex from subprocess import Popen, PIPE, STDOUT, call import re def lexical_greater_or_equals(a, b): if (a[0] > b[0]): return True; if (a[0] < b[0]): return False; if (a[1] > b[1]): return True; if (a[1] < b[1]): return False; return (a[2] >= b[2]) if (len(sys.argv) < 3): print("Usage: " + sys.argv[0] + " ") sys.exit(1) gccpath = sys.argv[1] if (sys.argv[2] == "intel64"): arch = "-m64" elif (sys.argv[2] == "ia32"): arch = "-m32" else: print("Unsupported arch " + sys.argv[2] + " must be ia32 or intel64") sys.exit(1) p = subprocess.Popen([gccpath, arch, "-v"], stdout=PIPE, stderr=STDOUT) gcc_out = p.communicate(); p.wait() gcc_ver_re = re.compile(r'version (\d+)\.(\d+).(\d*)', re.MULTILINE) gcc_ver = gcc_ver_re.search(gcc_out[0]) if (gcc_ver is None): print("Unexpected output string from gcc:\n" + glibc_ver_out) sys.exit(1) gcc_major = int(gcc_ver.group(1)) gcc_middle = int(gcc_ver.group(2)) gcc_minor = 0 if (gcc_ver.group(3) != ""): gcc_minor = int(gcc_ver.group(3)) if (not lexical_greater_or_equals([gcc_major, gcc_middle, gcc_minor], [4, 5, 0])): print("gcc version doesn't support ifunc - must be at least 4.5.0") sys.exit(1) p = subprocess.Popen([gccpath, arch, "-Wl,--version"], stdout=PIPE, stderr=STDOUT) binutils_out = p.communicate(); p.wait() version_re = re.compile(r'(\d+)\.(\d+)\.(\d+)', re.MULTILINE) version = version_re.search(binutils_out[0]) if version is None: print("Unexpected output string from ld:\n" + binutils_out) sys.exit(1) binutils_major = int(version.group(1)) binutils_middle = int(version.group(2)) binutils_minor = int(version.group(3)) if (not lexical_greater_or_equals([binutils_major, binutils_middle, binutils_minor], [2, 20, 1])): print("Binutils version doesn't support ifunc - must be at least 2.20.1") sys.exit(1) p = subprocess.Popen([gccpath, arch, "-print-file-name=libc.so.6"], stdout=PIPE, stderr=STDOUT) glibc_path = p.communicate(); p.wait() glibc_path_stripped = glibc_path[0].strip() if (not os.path.isfile(glibc_path_stripped)): print("glibc path not found: " + glibc_path) sys.exit(1) p = subprocess.Popen([glibc_path_stripped], stdout=PIPE, stderr=STDOUT) glibc_ver_out = p.communicate(); p.wait() glibc_ver_re = re.compile(r'version (\d+)\.(\d+).(\d*)', re.MULTILINE) glibc_ver = glibc_ver_re.search(glibc_ver_out[0]) if (glibc_ver is None): print("Unexpected output string from glibc:\n" + glibc_ver_out) sys.exit(1) glibc_major = int(glibc_ver.group(1)) glibc_middle = int(glibc_ver.group(2)) glibc_minor = 0 if (glibc_ver.group(3) != ""): glibc_minor = int(glibc_ver.group(3)) if (not lexical_greater_or_equals([glibc_major, glibc_middle, glibc_minor], [2, 11, 1])): print("glibc version doesn't support ifunc - must be at least 2.11.1") sys.exit(1) print("IFUNC_SUPPORTED") sys.exit(0)