`
骑猪逛街666
  • 浏览: 141733 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

MySQL编译选项 -fno-strict-aliasing随手记

 
阅读更多

阅读原文请点击

摘要: 最近发布的MySQL8.0.2版本中,将gcc的编译选项从--fno-strict-aliasing移除,也就是说打开strict aliasing, 根据worklog #10344 的描述,在单线程的性能测试中,有最多%4的性能提升,还是相当可观的。

最近发布的MySQL8.0.2版本中,将gcc的编译选项从--fno-strict-aliasing移除,也就是说打开strict aliasing, 根据worklog #10344 的描述,在单线程的性能测试中,有最多%4的性能提升,还是相当可观的。这个flag在我们内部编译版本中也是一直打开的,但一直不知甚解。本文是网上搜索文档和自己试验的小结。

首先strict aliasing是个什么鬼? --fno-strict-aliasing对应的是--f-strict-aliasing,GCC文档的解释如下:

Allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int, but not a void* or a double. A character type may alias any other type.

Stackoverflow上关于strict aliasing规则的问题

当使用strict aliasing时, 编译器会认为在不同类型之间的转换不会发生,因此执行更激进的编译优化,例如reorder执行顺序。

Strcit aliasing只能隐式的开启或者显式的禁止掉。在-o2或更高的编译级别上会被隐式开启。

这里举个简单的例子,参考网络 上这篇文章

$cat x.c
#include <stdio.h>
#include <stdint.h>

int main()
{
        int a = 0x12345678;

        uint16_t* const sp = (uint16_t*)&a;
        uint16_t hi = sp[0];
        uint16_t lo = sp[1];

        sp[1] = hi;
        sp[0] = lo;

        printf("%x\n", a);

        return 0;
}

函数的功能很简单,对一个数字的高低位进行交换

gcc版本

$gcc --version
gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)

执行strict aliasing (O2及以上默认打开)

$gcc -O2  x.c

$./a.out
12345678

非strict aliasing (显式指定-fno-strict-aliasing)

$gcc -O2 -fno-strict-aliasing x.c

$./a.out
56781234

不同的gcc flag,两次的执行结果居然完全不相同,只有第二次才实现了预期功能。因为默认情况下不报warning,我们把告警打开看看:

$gcc -O2 -Wstrict-aliasing x.c
x.c: In function ‘main’:
x.c:13: warning: dereferencing pointer ‘sp’ does break strict-aliasing rules
x.c:9: warning: dereferencing pointer ‘sp’ does break strict-aliasing rules
x.c:8: note: initialized from here
x.c:10: warning: dereferencing pointer ‘({anonymous})’ does break strict-aliasing rules
x.c:10: note: initialized from here
x.c:12: warning: dereferencing pointer ‘({anonymous})’ does break strict-aliasing rules
x.c:12: note: initialized from her

果然在使用strict aliasing时,因为破坏了严格aliasing的规则大量报警,因此如果我们要使用strict aliasing,一定要打开报警,并重视每个warning。

回到刚才的问题,为什么strict aliasing会输出最原始的数据,而不是修改后的数据呢 ? 看起来就好像后面的修改全部被忽略掉了一样。 我们来看看编译后的代码。可以看到两个汇编代码完全不相同。编译器认为代码里不可能出现不规范的类型转换,所以在错误的案例里,a的未被修改的值被直接抛给了printf函数

正确的 (gcc -O2 -fno-strict-aliasing x.c)

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004d0 <+0>:     sub    $0x18,%rsp
   0x00000000004004d4 <+4>:     mov    $0x4005f8,%edi
   0x00000000004004d9 <+9>:     xor    %eax,%eax
   0x00000000004004db <+11>:    movw   $0x5678,0xe(%rsp)
   0x00000000004004e2 <+18>:    movw   $0x1234,0xc(%rsp)
   0x00000000004004e9 <+25>:    mov    0xc(%rsp),%esi
   0x00000000004004ed <+29>:    callq  0x4003b8 <printf@plt>
   0x00000000004004f2 <+34>:    xor    %eax,%eax
   0x00000000004004f4 <+36>:    add    $0x18,%rsp
   0x00000000004004f8 <+40>:    retq
End of assembler dump.

错误的 (gcc -O2 -fstrict-aliasing x.c)

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004d0 <+0>:     sub    $0x18,%rsp
   0x00000000004004d4 <+4>:     mov    $0x12345678,%esi
   0x00000000004004d9 <+9>:     mov    $0x4005f8,%edi
   0x00000000004004de <+14>:    xor    %eax,%eax
   0x00000000004004e0 <+16>:    movw   $0x5678,0xe(%rsp)
   0x00000000004004e7 <+23>:    movw   $0x1234,0xc(%rsp)
   0x00000000004004ee <+30>:    callq  0x4003b8 <printf@plt>
   0x00000000004004f3 <+35>:    xor    %eax,%eax
   0x00000000004004f5 <+37>:    add    $0x18,%rsp
   0x00000000004004f9 <+41>:    retq
End of assembler dump.

但是如果我换成高版本的gcc,例如4.8版本,两种编译方式都没有问题,甚至加上-Wstrict-aliasing连报警都没有。只有加上-Wstrict-aliasing=1才报warning

$/opt/rh/devtoolset-2/root/usr/bin/gcc --version
gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)

$/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fno-strict-aliasing x.c

$./a.out
56781234

/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fstrict-aliasing x.c

$./a.out
56781234

$/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fstrict-aliasing -Wstrict-aliasing=1 x.c
x.c: In function ‘main’:
x.c:9:2: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
  uint16_t* const sp = (uint16_t*)&a;

网上搜了一下,Stackoverflow上有一些类似的问题 1, 2。 我理解这应该是gcc编译器的高版本对类型转换规则的识别可能做的更加好,细节不太了解,如有看到这篇文章的朋友,求帮忙修正 :)

!!!无论如何, 如果你需要打开strict aliasing, 一定要打开Wstrict-aliasing,消除代码warning。 同时在代码上也要尽量减少这种不同类型的转换。

在MySQL移除-fno-strict-aliasing后, 也看到了一些担忧,因为mysql的codebase毕竟已经相当古老了, 而当前并没有一些静态或动态的分析工具能够找到所有违反strict aliasing规则的地方。可能存在潜在的风险。

阅读原文请点击

分享到:
评论

相关推荐

    严格别名规则“-fstrict-aliasing”和“-fno-strict-aliasing”及类型双关

    “-fstrict-aliasing”表示启用严格别名规则,“-fno-strict-aliasing”表示禁用严格别名规则,当gcc的编译优化参数为“-O2”、“-O3”和“-Os”时,默认会打开“-fstrict-aliasing”。 什么是严格别名规则?gcc对...

    warning: dereferencing type-punned pointer will break strict-aliasing rules

    1. 使用 `-fno-strict-aliasing` 参数来禁用 strict aliasing 优化。这可以消除警告,但可能导致程序运行效率下降,因为它放弃了可能的性能优化。 2. 修改代码,避免违反 strict aliasing 规则。这通常意味着使用 `...

    gpio.rar_ARM Linux GPIO_ARM驱动_arm 驱动_linux gpio_linux io 驱动

    leddrv.c 编译方式 arm-elf-gcc -D__KERNEL__ -I你的uClinux目录/linux-2.4.x/include-Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__...

    pip 错误unused-command-line-argument-hard-error-in-future解决办法

    在我的Mac Air上,用pip安装一些Python库时,偶尔就会遇到一些报错,关于“unused-command-line-argument-hard-error-in-future”,错误如下:复制代码 代码如下:cc -fno-strict-aliasing -fno-common -dynamic -...

    GCC使用详解,不错的东西

    GCC 的一些其他选项还有 -ansi、-fno-asm、-fno-strict-prototype 等,用于控制编译器的行为和生成的代码。 GCC 是一个功能强大且灵活的编译器,提供了许多选项和参数,帮助开发者快速编译和生成高效的代码。

    Linux中gcc g++常用编译选项

    -fno-strict-prototype:对 g++ 生效,使用这个选项,g++ 将对不带参数的函数都认为没有显式的对参数的个数和类型说明。 -fthis-is-variable:使得 this 可以作为一般变量使用。 -fcond-mismatch:允许条件表达式...

    mysql-5.5.14.tar.gz

    CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" cmake . -LH|more //CMake下查看MySQL的编译配置 cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DEXTRA_CHARSETS=all make make ...

    asn基础知识

    contexts -fno-keep-types -fno-keep-modules -fno-keep-tags -fno-keep-values -fno-keep-extensions -fno-keep-all -fno-keep-private-members -fno-keep-public-members -fno-keep-static-members -fno-keep-...

    GCC编译器参数详解

    -fno-strict-prototype 参数用于对 g++ 起作用,使用该参数时,g++ 将对不带参数的函数认为没有显式的参数类型说明。例如:`g++ -fno-strict-prototype hello.cpp` 11. 允许条件表达式的第二和第三参数类型不匹配...

    解决Python安装cryptography报错问题

    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DUSE__THREAD -DHAVE_SYNC_SYNCHRONIZE -I/usr/include/ffi -I/usr/include/libffi -I/usr/include/python2.7 -c c/_...

    gcc g++ 中文编译选项详解 手册

    GCC G++ 编译选项详解手册 ...* -fno-strict-aliasing:禁用严格别名规则 本文档提供了 GCC 和 G++ 编译器的详细使用说明和选项解释,旨在帮助用户更好地使用 GCC 和 G++ 编译器来编译和链接 C 和 C++ 源代码。

    网络安全补丁实验作业.docx

    编译选项-fno-stack-protector可以禁用栈保护机制,以便测试栈溢出的漏洞。例如,在上面的代码中,我们使用gcc编译器的-fno-stack-protector选项来禁用栈保护机制,以便测试栈溢出的漏洞。 这篇实验报告讨论了gets...

    qBigInt:Big Integer KDB +算法的C库

    Linux这样使用gcc进行编译:gcc -D KXVER = 3 -Wall -fno-strict-aliasing -Wno-括号-g -O2 -shared -fPIC -o bigint.so bigint.c -lgmp 在Mac上使用gcc进行编译:gcc -bundle -undefined dynamic_lookup b

    Esp8266编译工具xtensa-lx106-elf

    乐鑫Esp8266编译工具xtensa-lx106-elf 下载 xtensa-lx106-elf.tar.bz2 解压至/opt目录 tar jxvf xtensa-lx106-elf.bz2 -C /opt 非root修改权限 chmod 777 /opt/xtensa-lx106-elf 配置环境变量 gedit /etc/...

    bl602-re:BL602 Blob的逆向工程

    unknown-elf-gcc_8.3.0 -march=rv32imfc -mabi=ilp32f -gdwarf -Os -std=gnu99 -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -fshort-enums -ffreestanding -fno-strict-aliasing 目标可能...

    mysql数据库安装.pdf

    CC=gcc CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-thread-safe-client --enable-shared --with-ssl ``` 然后运行`...

    GCC使用指南(C/C++)

    - `-fno-strict-aliasing`: 关闭严格的别名检查。 - `-fno-builtin`: 不使用内置函数。 - `-funsigned-char`: 将字符类型视为无符号。 - `-fno-asm`: 禁止使用内联汇编。 ##### 编译时的警告选项 这些选项帮助...

Global site tag (gtag.js) - Google Analytics