在自定义libc中实现线程本地存储

我正在为非常小的和静态链接的程序实现一小部分libc,我认为添加TLS支持将是一个很好的学习体验.我用Ulrich Drepper’s TLS document作为参考.

我设置了两个字符串来试试这个:

static __thread const char msg1[] = "TLS (1).\n"; /* 10 bytes */
static __thread const char msg2[] = "TLS (2).\n"; /* 10 bytes */

编译器生成以下指令以访问它们:

mov    rbx,QWORD PTR fs:0x0 ; Load TLS.
lea    rsi,[rbx-0x14]       ; Get a pointer to 'msg1'. 20 byte offset.
lea    rsi,[rbx-0xa]        ; Get a pointer to 'msg2'. 10 byte offset.

我们假设我将TCB放在堆栈的某个位置:

struct tcb {
    void* self; /* Points to self. I read that this was necessary somewhere. */
    int errno;  /* Per-thread errno variable. */
    int padding;
};

然后将TLS区域放在它旁边的tls =& tcb – tls_size.然后我将FS寄存器设置为指向fs = tls tls_size,并将TLS初始化映像复制到tls.

但是,这不起作用.我已经验证通过将tls_image中的20个字节写入stdout来正确定位TLS初始化映像.这或者让我相信我错误地放置了TCB和/或TLS区域,或者我不符合ABI.

>我使用arch_prctl(2)设置FS寄存器.我是否需要以某种方式使用set_thread_area(2)?
>我没有dtv.我假设这不是必要的,因为我静态链接.

关于我做错了什么的任何想法?非常感谢!

最佳答案

I’m implementing a small subset of libc for very small and statically
linked programs,and I figured that adding TLS support would be a good
learning experience.

真棒的想法!我必须在项目中实现自己的TLS,因为我无法使用任何常见的线程库,如pthread.我没有完全解决您的问题,但分享我的经验可能会有用.

再看看这个link,它可能会有用.

I set the FS register using arch_prctl(2). Do I need to use
set_thread_area(2) somehow?

答案取决于您实际使用的架构.如果您使用的是x86-64位,则应该专门使用arch_prctl将FS寄存器设置为您要用作TLS的内存区域(它允许您处理大于4GB的内存区域).而对于x86-32,您必须使用set_thread_area,因为它是内核支持的唯一系统调用.

我的实现背后的想法是为每个线程分配一个私有内存区域,并将其地址保存到%GS寄存器中.这是一个相当简单的方法,但在我的情况下,它运作得很好.每次要访问线程的私有区域时,只需要将%GS中保存的值和标识内存位置的偏移量用作基址.我通常为每个线程分配一个内存页面(4096),然后将它分成8个字节的块.因此,每个线程有512个私有内存插槽,可以像索引从0到511的数组一样访问.

这是我使用的代码:

#

define _GNU_SOURCE 1 

#include "tls.h"
#include 

这是带有一些宏的标题:

#ifndef TLS_H
#define TLS_H

#include 

每个线程要完成的第一个操作是安装TLS内存区域.一旦TLS被初始化,每个线程就可以开始使用该区域作为私有TLS.

相关文章

文章浏览阅读1.8k次,点赞63次,收藏54次。Linux下的目录权限...
文章浏览阅读1.6k次,点赞44次,收藏38次。关于Qt的安装、Wi...
本文介绍了使用shell脚本编写一个 Hello
文章浏览阅读1.5k次,点赞37次,收藏43次。【Linux】初识Lin...
文章浏览阅读3k次,点赞34次,收藏156次。Linux超详细笔记,...
文章浏览阅读6.8k次,点赞109次,收藏114次。【Linux】 Open...