eclipse/cdt:-fPIC引起的线程局部变量(__thread)的SIGSEGV异常问题

最近在 ubuntu下用eclipse Neon.3 (4.6.3) 调试一个C工程时遇到一个好奇怪的问题:

一个应用程序A,调用一个静态库B,静态库中用__thread定义了线程局部变量(TLS,thread local storage),在eclipse跟踪进B的函数,代码执行到访问TLS变量时,程序直接就崩溃了,报了SIGSEGV错误异常(无效的内存引用),但是不跟踪直接运行代码是没有问题的。

以下是lib B的代码 testlib2.c

#include <stdlib.h>

#include "testlib2.h"

static __thread int tls_v = 12345;   
void test_tls(){
	printf("%d\n",tls_v);
}

对应的头文件testlib2.h

#ifndef TESTLIB2_H_
#define TESTLIB2_H_
void test_tls();
#endif /* TESTLIB2_H_ */

应用程序A代码

#include "testlib2.h"
int main(void) {
	test_tls();
	return EXIT_SUCCESS;
}

如下图,代码执行到读取tls_v变量的时候就直接崩溃了,如果调试时如果不跟踪进test_tls(),程序也能正常执行。
当我把lib B改为动态库时代码,调试正常。

在这里插入图片描述

百思不得其解啊,没办法网上仔细翻了关于线程局部变量的相关资料。以前只了解thread local storage的基本概念,知道它是线程独享的变量,并没有深入去研究。通过这次的问题,知道线程局部变量有4种访问模型
General Dynamic (GD)Local Dynamic (LD)Initial Executable (IE)Local Executable (LE),关于这4种模型的说明参见下面oracle的文章

Thread-Local Storage Access Models
https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter8-20.html

我们只需要知道这4种模型分类代表不同的tls变量访问能力。一般来说,程序员在编译自己的c/c++代码时是不用关心这个问题的。

然而编译器在编译代码时针对这种不同的访问模型会生成不同的代码。参见下面的关于gcc编译选项的gnu官方手册(《3.16 Options for Code Generation Conventions》)中关于-ftls-model选项的说明
-ftls-model选项用于指定tls变量的访问模型,引起我关注不是如何用它来设置tls-model,而是说明中的最后一行文字(如下图红框标):如果指定了-fpictls-model的默认值为General Dynamic (GD)否则为Initial Executable (IE)
在这里插入图片描述

看到这里我想到了我的静态库B在编译时指定了-fPIC选项。于是我去掉-fPIC选项重新编译,再跟踪可以通过了。如下图,可以看出,没有-fPIC选项时生成的汇编代码与前面有-fPIC选项时是不一样的。

在这里插入图片描述

虽然到目前为止,我还不知道为什么eclipse下对-fPIC选项编译的静态库中的TLS调试会造成异常,但总算知道这个问题产生的条件,后续开发中就可以避免了。

导致SIGSEGV异常问题出现是在几个条件下都具备的情况下发生的:
1.静态库中使用__thread变量
2.静态库编译使用了-fPIC选项
3.eclipse调试跟踪静态库的代码

参考资料

《3.16 Options for Code Generation Conventions》

《Thread-Local Storage Access Models》

《Thread-local storage》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值