关于GCC编译优化讨论

1.简介

关于这个问题的讨论,其实是在工作中遇到了相关情况,特地写了一个demo来佐证一下自己的想法以及提出一些解决方法。

在编写代码或者针对OS进行优化时,GCC的相关优化选项是我们经常使用到的,毕竟通过编译器来进行代码优化比人力来说,还是挺香的。但这种机器优化行为,一方面,有可能破坏了我们对原本程序的设计流程,导致最终结果大相径庭。另一方面,也考验着我们的coding能力和对编译器的了解。下面就通过以下demo来说明一下。

2. 验证demo

/*************************************************************************
	> File Name: test.c
	> Author: 
	> Mail:
	> Created Time: Thu 19 May 2022 10:44:40 AM CST
************************************************************************/

#include<stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


static void *thread_start(void *arg)
{
	int *flag = (int *)arg;
	*flag = 1;
}

int main()
{
	pthread_t thread_id;
	int flag = 0;
	int *retval;

	pthread_create(&thread_id, NULL, &thread_start, &flag);

	while(!flag);

	pthread_join(thread_id, (void *)&retval);

	printf("Hello world\n");

	return 0;
}

从代码逻辑来看,这个验证demo实现的功能很简单,就是在主进程里判断一个flag,直到这个flag被创建的线程置1了,才退出循环,并且打印一句Hello world,但使用不同的GCC编译命令,却产生了不同的结果,编译命令如下:

gcc test.c -O0 -o test_O0 -lpthread
gcc test.c -O1 -o test_O1 -lpthread

对编译出来的test_O0和test_O1,执行结果大相径庭,test_O0可以顺利打印出Hello world,而test_O1却一直阻塞在while循环那里了。

对比一下汇编代码差异,如下图所示:
在这里插入图片描述
很明显,使用O0编译选项编译的源码,整个循环中流程如下,

  1. 从内存里把flag的值加载到eax寄存器
  2. 判断eax寄存器的值是否为0
  3. 如果为0,则跳转到0x40074f这个地址重新加载内存的值到eax寄存器,再回到步骤1,周而复始,直到条件不满足。

而O1编译选项下,整个循环流程如下:

  1. 从内存里把flag的值加载到eax寄存器
  2. 判断eax寄存器的值是否为0
  3. 如果为0,回到步骤2,周而复始,直到条件不满足。

使用O1优化,导致eax寄存器的值没有从内存更新,只读取了一次,所以while循环条件永远无法满足,导致while循环无法退出。

3.解决方法探讨

使用volatile关键字修饰循环判断变量,当一个变量被声明为volatile的,就是告诉编译器,即便当前编译的代码不会修改这个变量,但该变量对应的内存数据也有可能因为其他原因而被修改。这样编译器在生成汇编代码时,每次使用该变量时,都会对该变量所在的内存位置进行一次访问,确保获取到内存中最新的值。如果没有加上volatile,编译器为了效率,可能就把该变量代码的值加载到寄存器中,后续需要使用时,就从相应的寄存器读取即可,不会从内存读取,即便内存数据被修改了。

是否有其他方法,待讨论…

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值