http://nxr.netbsd.org/xref/src/external/gpl3/gcc/dist/libgcc/config/i386/cpuinfo.c#284 calls __get_cpuid with 0 level, then we end up in: http://nxr.netbsd.org/xref/src/external/gpl3/gcc/dist/gcc/config/i386/cpuid.h#263 and end up calling __cpuid even though __get_cpuid_max returns 0. This breaks on early i486 processors that don't have the cpuid instruction and we end up getting SIGILL. Our fix is to explicitly check for 0 to prevent that: unsigned int *__ecx, unsigned int *__edx) { unsigned int __ext = __level & 0x80000000; + unsigned int __maxlevel = __get_cpuid_max (__ext, 0); - if (__get_cpuid_max (__ext, 0) < __level) + if (__maxlevel == 0 || __maxlevel < __level) return 0; __cpuid (__level, *__eax, *__ebx, *__ecx, *__edx);
Patches should goto gcc-patches@ and should be based off the trunk of GCC.
Created attachment 41284 [details] Amended cpuid patch. Here's an amended patch against the trunk. Also sent mail to gcc-patches@
Author: uros Date: Mon May 1 15:38:14 2017 New Revision: 247439 URL: https://gcc.gnu.org/viewcvs?rev=247439&root=gcc&view=rev Log: PR target/68491 * config/i386/cpuid.h (__get_cpuid): Always return 0 when __get_cpuid_max returns 0. (__get_cpuid_count): Ditto. Modified: trunk/gcc/ChangeLog trunk/gcc/config/i386/cpuid.h
Author: uros Date: Tue May 2 20:36:26 2017 New Revision: 247523 URL: https://gcc.gnu.org/viewcvs?rev=247523&root=gcc&view=rev Log: Backport from mainline 2017-05-01 Uros Bizjak <ubizjak@gmail.com> PR target/68491 * config/i386/cpuid.h (__get_cpuid): Always return 0 when __get_cpuid_max returns 0. (__get_cpuid_count): Ditto. Modified: branches/gcc-7-branch/gcc/ChangeLog branches/gcc-7-branch/gcc/config/i386/cpuid.h
Author: uros Date: Wed May 3 18:19:28 2017 New Revision: 247561 URL: https://gcc.gnu.org/viewcvs?rev=247561&root=gcc&view=rev Log: Backport from mainline 2017-05-01 Uros Bizjak <ubizjak@gmail.com> PR target/68491 * config/i386/cpuid.h (__get_cpuid): Always return 0 when __get_cpuid_max returns 0. (__get_cpuid_count): Ditto. Modified: branches/gcc-6-branch/gcc/ChangeLog branches/gcc-6-branch/gcc/config/i386/cpuid.h
Author: uros Date: Wed May 3 20:00:50 2017 New Revision: 247566 URL: https://gcc.gnu.org/viewcvs?rev=247566&root=gcc&view=rev Log: Backport from mainline 2017-05-01 Uros Bizjak <ubizjak@gmail.com> PR target/68491 * config/i386/cpuid.h (__get_cpuid): Always return 0 when __get_cpuid_max returns 0. Modified: branches/gcc-5-branch/gcc/ChangeLog branches/gcc-5-branch/gcc/config/i386/cpuid.h
Fixed everywhere.
*** Bug 81218 has been marked as a duplicate of this bug. ***
I'm a bit late to the party, but this patch seems dubious to me. __get_cpuid_max() fails to distinguish between CPUs that have max level 0 (although I doubt that any such CPUs exist) and CPUs that don't have CPUID at all. Shouldn't __get_cpuid_max return -1 if CPUID isn't there or, alternatively, just generally return the last level + 1 (and 0 if CPUID isn't there)?
On Jun 27, 4:26pm, gcc-bugzilla@gcc.gnu.org ("luto at kernel dot org") wrote: -- Subject: [Bug target/68491] libgcc calls __get_cpuid with 0 level breaks o | I'm a bit late to the party, but this patch seems dubious to me.=20 | __get_cpuid_max() fails to distinguish between CPUs that have max level 0 | (although I doubt that any such CPUs exist) and CPUs that don't have CPUID = | at | all. | | Shouldn't __get_cpuid_max return -1 if CPUID isn't there or, alternatively,= | | just generally return the last level + 1 (and 0 if CPUID isn't there)? | Yes, it should. That would be cleaner, but my goal was minimal change not refactoring :-) christos
(In reply to Andy Lutomirski from comment #9) > I'm a bit late to the party, but this patch seems dubious to me. > __get_cpuid_max() fails to distinguish between CPUs that have max level 0 > (although I doubt that any such CPUs exist) and CPUs that don't have CPUID > at all. No, cpuid leaf 0 will never return zero [1]. [1] https://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Highest_Function_Parameter