gcc编译选项与cpu指令集的影响

  • Post author:
  • Post category:其他




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 版权协议,转载请附上原文出处链接和本声明。