diff --git a/src/Auditor.jl b/src/Auditor.jl index 0b47187ae..35b2aa8ea 100644 --- a/src/Auditor.jl +++ b/src/Auditor.jl @@ -135,9 +135,13 @@ function audit(prefix::Prefix, src_name::AbstractString = ""; shlib_files = filter(f -> startswith(f, prefix.path) && valid_library_path(f, platform), collapse_symlinks(bin_files)) for f in shlib_files - # Inspect all shared library files for our platform (but only if we're - # running native, don't try to load library files from other platforms) - if platforms_match(platform, HostPlatform()) + # Always include microarchitecture in the host platform: we don't want to try and + # dlopen a library built for an incompatible microarchitecture. + hp = augment_microarchitecture!(HostPlatform()) + set_compare_strategy!(hp, "march", march_comparison_strategy) + # Inspect all shared library files for our platform (but only if we're running + # native, don't try to load library files from other platforms or incompatible ISAs) + if platforms_match(platform, hp) if verbose @info("Checking shared library $(relpath(f, prefix.path))") end diff --git a/src/auditor/instruction_set.jl b/src/auditor/instruction_set.jl index 07beb52c4..7070c627a 100644 --- a/src/auditor/instruction_set.jl +++ b/src/auditor/instruction_set.jl @@ -1,4 +1,6 @@ using JSON +using Base.BinaryPlatforms: arch_march_isa_mapping, set_compare_strategy! +using Base.BinaryPlatforms.CPUID ## We start with definitions of instruction mnemonics, broken down by category: const instruction_categories = JSON.parsefile(joinpath(@__DIR__, "instructions.json"); @@ -168,3 +170,34 @@ function analyze_instruction_set(oh::ObjectHandle, platform::AbstractPlatform; v # Otherwise, return `min_march` and let 'em know! return min_march end + +function augment_microarchitecture!(platform::Platform) + haskey(platform, "march") && return platform + + host_arch = arch(HostPlatform()) + host_isas = arch_march_isa_mapping[host_arch] + idx = findlast(((name, isa),) -> isa <= CPUID.cpu_isa(), host_isas) + platform["march"] = first(host_isas[idx]) + return platform +end + +function march_comparison_strategy(a::String, b::String, a_requested::Bool, b_requested::Bool) + function get_arch_isa(isa_name::String) + for (arch, isas) in arch_march_isa_mapping + for (name, isa) in isas + name == isa_name && return arch, isa + end + end + return nothing, nothing + end + + a_arch, a_isa = get_arch_isa(a) + b_arch, b_isa = get_arch_isa(b) + if any(isnothing, (a_arch, b_arch)) || a_arch != b_arch + # Architectures are definitely not compatible, exit early + return false + end + + # ISA `a` is compatible with ISA `b` only if it's a subset of `b` + return a_isa ≤ b_isa +end