IFC 7.1 GenuineIntel check: workaround

From: Mark Mackey (markm_at_chiark.greenend.org.uk)
Date: 07/07/04

  • Next message: Steve Lionel: "Re: IFC 7.1 GenuineIntel check: workaround"
    Date: 07 Jul 2004 12:30:48 +0100 (BST)
    
    

    Hi all.

    I'm still using ifc 7.1 (8.0 doesn't like my code, or vice versa). The
    latest version (Linux ia32 7.1.040) has some useful bugfixes from
    previous versions but is crippled on non-Intel processors: the
    vectorised math library checks for a GenuineIntel chip and disables
    SSE/SSE2 code. As a result, code compiled with -axK will run just the
    generic (slow) ia32 code on Athlons, while code compiled with -xK will
    segfault.

    Intel say that this is a bug inadvertently introduced into the math
    libraries, and that they have no plans to fix it.

    Luckily, it's easy to work around. The attached Perl script (also
    available at http://www.swallowtail.org/intel_check_patch.txt in case
    word wraps etc bugger up the code below) patches the affected libirc.a
    file. The libimf.so file is also affected by this bug, so if you use
    -i_dynamic you'll have to patch that file to: it should be pretty simple
    to modify this script to do that.

    Note: if you got the previous version of this message before I
    cancelled it, use this script instead. I'd attached the wrong copy of
    the script to the previous one, and it patches libirc so that SSE fails
    on _all_ chips, even Intel ones :).

    8<---------------------------------------------------------------------

    #!/usr/bin/perl
    #
    # (C) Copyright M. D Mackey 2004. This program may be freely modified and redistributed.
    #
    # A short program to patch the 'libirc.a' file from the Intel Fortran Compiler
    # version 7.1.040 (build 20040309Z). May work on other builds also, but is not
    # guaranteed. The patch removes the check for the string "GenuineIntel" in the
    # CPUID flags of the processor, thus making SSE/SSE2 code work on AMD chips that
    # support it.
    #
    # Creates a file 'libirc.a.bak' containing the original contents of libirc.a.
    #
    # If you want to check for a successful patch, do
    #
    # objdump -d libirc.a.bak > old
    # objdump -d libirc.a > new
    #
    # and examine the differences between 'old' and 'new'. Three lines
    # should have changed in __intel_cpu_indicator_init:
    #
    # 3d 47 65 6e 75 cmp $0x756e6547,%eax
    # ...
    # 3d 69 6e 65 49 cmp $0x49656e69,%eax
    # ...
    # 3d 6e 74 65 6c cmp $0x6c65746e,%eax
    #
    # (these check for "GenuineIntel"). These lines should all be changed to
    # a9 00 00 00 00 test $0x00000000,%eax
    #
    # Note that the "GenuineIntel" check is still present in
    # libimf.so, so if you link with the -i_dynamic flag you'll
    # have to patch that file yourself.
    #

    open(LIBIRC,"libirc.a") or help();
    my($libirc)=join('',<LIBIRC>);
    close(LIBIRC);

    # libirc is small, so let's do things the simple way...
    #
    my($unp)=unpack('H*',$libirc);
    my($count);
    $count=($unp=~s/3d47656e75/a900000000/);
    die("Failure patching 3d 47 65 6e 75: libirc.a has either already been patched or is the wrong version\n") unless ($count==1);

    $count=($unp=~s/3d696e6549/a900000000/);
    die("Failure patching 3d 69 6e 65 49: libirc.a has either already been patched or is the wrong version\n") unless ($count==1);

    $count=($unp=~s/3d6e74656c/a900000000/);
    die("Failure patching 3d 6e 74 65 6c: libirc.a has either already been patched or is the wrong version\n") unless ($count==1);

    open(OUTPUT,">libirc.a.tmp") or die;
    print OUTPUT pack('H*',$unp);
    close(OUTPUT);
    if (! -f "libirc.a.bak") {
      rename("libirc.a","libirc.a.bak") or die("Couldn't rename libirc.a to libirc.a.bak: $!\n");
    }
    rename("libirc.a.tmp","libirc.a") or die("Couldn't rename libirc.a.tmp to libirc.a: $!\n");
    print STDERR "Patch operation on libirc.a successful\n";
    exit(0);

    sub help {
      print STDERR <<EOUSAGE;

    Some versions of the Intel Fortran Compiler produce code which checks whether
    the CPU is made by Intel or not, and disables MMX/SSE/SSE2 code if it isn't.
    This program patches the compiler libraries to remove this check, so that e.g.
    programs compiled with -axW will use SSE2 code on Athlon 64 chips.

    To run the patch, simply execute this script in the
    /opt/intel/compiler70/ia32/lib directory: the file 'libirc.a' will be patched.
    A backup copy of libirc.a will be made first, so if it all goes wrong you won't
    lose anthing.

    This script was tested against ifc version 7.1.040, build 20040309Z, and may
    not work on other versions. It shouldn't break anything, however.

    EOUSAGE
      exit(1);
    }

    __END__
      
    8<-----------------------------------------------------------------------

    -- 
    Mark Mackey 
    "The determined Real Programmer can write Fortran programs in any language."
    		 - "Real Programmers don't use Pascal"
    

  • Next message: Steve Lionel: "Re: IFC 7.1 GenuineIntel check: workaround"

    Relevant Pages