Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TLS (thread-local storage) tutorial #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tls/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/__thread
/__thread-static
/tsd
/tsd-static
31 changes: 31 additions & 0 deletions tls/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
CFLAGS = -Wall
LDLIBS = -lpthread

.PHONY: all clean

all: __thread __thread-static tsd tsd-static indirect_modify

__thread-static: __thread.o
$(CC) $(LDLFAGS) -static -o $@ $^ $(LDLIBS)

__thread: __thread.o

__thread.o: __thread.c

tsd-static: tsd.o
$(CC) $(LDLFAGS) -static -o $@ $^ $(LDLIBS)

tsd: tsd.o

tsd.o: tsd.c

indirect_modify: indirect_modify.o

indirect_modify.o: indirect_modify.c
$(CC) $(CFLAGS) -fstack-protector-strong -c -o $@ $<

clean:
-rm -f __thread.o __thread __thread-static
-rm -f tsd.o tsd tsd-static
-rm -f indirect_modify.o indirect_modify
-rm -f *~
11 changes: 11 additions & 0 deletions tls/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Thread-Local Storage

This is a tutorial / presentation on thread-local storage (TLS).
TLS is a per-thread memory area used to store thread-specific data.
Global data that are required to be specific per thread are usually stored as part of the TLS.

https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter8-1/index.html

https://chao-tic.github.io/blog/2018/12/25/tls

https://wiki.osdev.org/Thread_Local_Storage
63 changes: 63 additions & 0 deletions tls/__thread.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>

static __thread size_t me;
static __thread size_t you;
static __thread size_t them = 543;

static void *tf(void *arg)
{
unsigned long id = (unsigned long) arg;
static __thread size_t us = 13;

me = 200 + id;
us += id*id;
printf("me in thread (%p): %zu\n", &me, me);
printf("you in thread (%p): %zu\n", &you, you);
printf("you in thread (%p): %zu\n", &them, them);
printf("us in thread (%p): %zu\n", &us, us);
printf("errno in thread (%p): %d\n", &errno, errno);

return NULL;
}

int main(void)
{
pthread_t new;
int err;

me = 100;
you = 999;
them = 3;
printf("me before create (%p): %zu\n", &me, me);
printf("you before create (%p): %zu\n", &you, you);
printf("them before create (%p): %zu\n", &them, them);
printf("errno before create (%p): %d\n", &errno, errno);

err = pthread_create(&new, NULL, tf, (void *) 1);
if (err < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
err = pthread_create(&new, NULL, tf, (void *) 2);
if (err < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}

printf("me after create before join (%p): %zu\n", &me, me);
printf("you after create before join (%p): %zu\n", &you, you);
printf("them after create before join (%p): %zu\n", &them, them);
printf("errno after create before join (%p): %d\n", &errno, errno);
pthread_join(new, NULL);
printf("me after join (%p): %zu\n", &me, me);
printf("you after join (%p): %zu\n", &you, you);
printf("them after join (%p): %zu\n", &them, them);
printf("errno after join (%p): %d\n", &errno, errno);

return 0;
}
Binary file added tls/indirect_modify
Binary file not shown.
58 changes: 58 additions & 0 deletions tls/indirect_modify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>

/*
* Offset is determined by running the program and computing
* (&age - &placeholder) / sizeof(unsigned int).
*/
#define OFFSET_FROM_LOCAL_TO_TLS 522

/*
* &age is at fs:0xfffffffffffffffc, i.e. tcb-0x4
* stack guard is at fs:0x28, i.e. tcb+x028
* offset is (0x28-(-0x04))/4 = 11
*/
#define OFFSET_FROM_TLS_TO_STACK_GUARD 11

static __thread unsigned int age;

static void *tf(void *arg)
{
unsigned int placeholder;
unsigned int *ptr;
unsigned long *stack_guard_ptr;

ptr = &placeholder;
printf("placeholder address: %p\n", &placeholder);

age = 22;
printf("age (address: %p): %u\n", &age, age);

* (ptr + OFFSET_FROM_LOCAL_TO_TLS) = 99;
printf("age (address: %p): %u\n", &age, age);

/* Print then overwrite stack guard with some gibberish. */
stack_guard_ptr = (unsigned long *) (ptr + OFFSET_FROM_LOCAL_TO_TLS + OFFSET_FROM_TLS_TO_STACK_GUARD);
printf("stack guard / canary (address: %p): 0x%016lx\n", stack_guard_ptr, *stack_guard_ptr);
* (stack_guard_ptr) = 0xaabbccddeeff0011;

return NULL;
}

int main(void)
{
pthread_t new;
int err;

err = pthread_create(&new, NULL, tf, (void *) 1);
if (err < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
pthread_join(new, NULL);

return 0;
}
57 changes: 57 additions & 0 deletions tls/tsd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>

static pthread_key_t me_key;
static pthread_key_t you_key;
static pthread_key_t them_key;

static void *tf(void *arg)
{
pthread_setspecific(me_key, (const void *) 200);
printf("me_key in thread (%p): %u, me value in thread: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key));
printf("you_key in thread (%p): %u, you value in thread: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key));
printf("them_key in thread (%p): %u, them value in thread: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key));

return NULL;
}

int main(void)
{
pthread_t new;
int err;

pthread_key_create(&me_key, NULL);
pthread_key_create(&you_key, NULL);
pthread_key_create(&them_key, NULL);

pthread_setspecific(me_key, (const void *) 100);
pthread_setspecific(you_key, (const void *) 999);
pthread_setspecific(them_key, (const void *) 3);
printf("me_key before create (%p): %u, me value before create: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key));
printf("you_key before create (%p): %u, me value before create: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key));
printf("them_key before create (%p): %u, me value before create: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key));

err = pthread_create(&new, NULL, tf, NULL);
if (err < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}

printf("me_key after create before join (%p): %u, me value after create before join: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key));
printf("you_key after create before join (%p): %u, you value after create before join: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key));
printf("them_key after create before join (%p): %u, them value beafter create before join: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key));
pthread_join(new, NULL);
printf("me_key after join (%p): %u, me value after join: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key));
printf("you_key after join (%p): %u, you value after join: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key));
printf("them_key after join (%p): %u, them value after join: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key));

/* This is really not required, but we call it for API completeness. */
pthread_key_delete(me_key);
pthread_key_delete(you_key);
pthread_key_delete(them_key);

return 0;
}