cpu支持的指令集
不同的CPU就和一个干活的员工一样,能力有强有弱。能力的强弱除了处理速度意外,支持的指令集数量也是关键点。
我们在linux系统上可以用lscpu命令或者cat /proc/cpuinfo来查看cpu可支持的指令集:
[root@localhost ~]# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 4
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 15
Model: 6
Model name: Intel(R) Xeon(R) Gold 5120 CPU @ 2.20GHz
Stepping: 3
CPU MHz: 2194.840
BogoMIPS: 4389.68
Hypervisor vendor: KVM
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 4096K
NUMA node0 CPU(s): 0-3
Flags:(指令集) fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx lm constant_tsc nopl xtopology cpuid tsc_known_freq pni cx16 x2apic hypervisor lahf_lm pti
最后一行的flags就是CPU所支持的指令集。/proc/cpuinfo中同理,就不赘述了。
CPU只能运行支持指令集范围的汇编指令,否则会出现SIGILL错误导致进程coredump。下面我们用一个例子来解释。
案例:执行avx指令出现SIGILL
环境:qemu虚机
OS:centos 8.2
编译器:gcc-8.3.1
cpu:Intel® Xeon® Gold 5120 CPU @ 2.20GHz。因为是虚机,没有avx、avx2指令集
demo:很简单,主要是加入浮点的运算
#include <stdio.h>
#define NUM 20
struct data_pool
{
float f_a[NUM];
int i_a[NUM];
};
void main()
{
struct data_pool A;
for(int i = 0; i < NUM; i++)
{
A.i_a[i]=i;
A.f_a[i]=i + 0.33432;
}
for(int i = 0; i < NUM; i++)
{
printf("%d: A.i_a: %d A.f_a: %f\n", i, A.i_a[i], A.f_a[i]);
}
}
编译指令,我们分两种
正常不指定指令集的编译:
[root@localhost ~]# gcc hello.c -o normal_hello
[root@localhost ~]# ./normal_hello
0: A.i_a: 0 A.f_a: 0.334320
1: A.i_a: 1 A.f_a: 1.334320
2: A.i_a: 2 A.f_a: 2.334320
3: A.i_a: 3 A.f_a: 3.334320
4: A.i_a: 4 A.f_a: 4.334320
5: A.i_a: 5 A.f_a: 5.334320
6: A.i_a: 6 A.f_a: 6.334320
7: A.i_a: 7 A.f_a: 7.334320
8: A.i_a: 8 A.f_a: 8.334320
9: A.i_a: 9 A.f_a: 9.334320
10: A.i_a: 10 A.f_a: 10.334320
11: A.i_a: 11 A.f_a: 11.334320
12: A.i_a: 12 A.f_a: 12.334320
13: A.i_a: 13 A.f_a: 13.334320
14: A.i_a: 14 A.f_a: 14.334320
15: A.i_a: 15 A.f_a: 15.334320
16: A.i_a: 16 A.f_a: 16.334320
17: A.i_a: 17 A.f_a: 17.334320
18: A.i_a: 18 A.f_a: 18.334320
19: A.i_a: 19 A.f_a: 19.334320 运行正常
**指定avx指令集的编译:**出现非法命令导致进程退出
[root@localhost ~]# gcc hello.c -mavx -o avx_hello
[root@localhost ~]# ./avx_hello
Illegal instruction (core dumped) 运行异常coredump
原因分析
我们通过coredumpctl debug(低版本为coredumpctl gdb)调试上面的coredump文件
Type "apropos word" to search for commands related to "word"...
Reading symbols from /root/avx_hello...(no debugging symbols found)...done.
[New LWP 4033]
Core was generated by `./avx_hello'.
Program terminated with signal SIGILL, Illegal instruction.
#0 0x00000000004005fd in main ()
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64
可以发现是收到SIGILL信号退出,非法指令。
反汇编main:
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004005d6 <+0>: push %rbp
0x00000000004005d7 <+1>: mov %rsp,%rbp
0x00000000004005da <+4>: sub $0xb0,%rsp
0x00000000004005e1 <+11>: movl $0x0,-0x4(%rbp)
0x00000000004005e8 <+18>: jmp 0x400624 <main+78>
0x00000000004005ea <+20>: mov -0x4(%rbp),%eax
0x00000000004005ed <+23>: cltq
0x00000000004005ef <+25>: lea 0x10(%rax),%rdx
0x00000000004005f3 <+29>: mov -0x4(%rbp),%eax
0x00000000004005f6 <+32>: mov %eax,-0xa0(%rbp,%rdx,4)
=> 0x00000000004005fd <+39>: vcvtsi2sdl -0x4(%rbp),%xmm1,%xmm1 出问题点vcvtsi2sdl指令
0x0000000000400602 <+44>: vmovsd 0x136(%rip),%xmm0 # 0x400740
0x000000000040060a <+52>: vaddsd %xmm0,%xmm1,%xmm0
0x000000000040060e <+56>: vcvtsd2ss %xmm0,%xmm0,%xmm0
0x0000000000400612 <+60>: mov -0x4(%rbp),%eax
0x0000000000400615 <+63>: cltq
0x0000000000400617 <+65>: vmovss %xmm0,-0xb0(%rbp,%rax,4)
0x0000000000400620 <+74>: addl $0x1,-0x4(%rbp)
0x0000000000400624 <+78>: cmpl $0x13,-0x4(%rbp)
…………
然后网上查找改指令:确实只有支持avx指令集的cpu才有。顾非法退出;
https://www.felixcloutier.com/x86/cvtsi2sd
版权声明:本文为qq_36382062原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。