Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

thread local storage in assembly

Tags:

c

gcc

assembly

I want to increment a TLS variable in assembly but is gives a segmentation fault in the assembly code. I don't want to let compiler change any other register or memory. Is there a way to do this without using gcc input and output syntax?

__thread unsigned val;
int main() {
  val = 0;
  asm("incl %gs:val");
  return 0;
}
like image 848
Yogi Avatar asked Nov 12 '12 20:11

Yogi


1 Answers

If you really really need to be able to do this for some reason, you should access a thread-local variable from assembly language by preloading its address in C, like this:

__thread unsigned val;
void incval(void)
{
  unsigned *vp = &val;
  asm ("incl\t%0" : "+m" (*vp));
}

This is because the code sequence required to access a thread-local variable is different for just about every OS and CPU combination supported by GCC, and also varies if you're compiling for a shared library rather than an executable (i.e. with -fPIC). The above construct allows the compiler to emit the correct code sequence for you. In cases where it is possible to access the thread-local variable without any extra instructions, the address generation will be folded into the assembly operation. By way of illustration, here is how gcc 4.7 for x86/Linux compiles the above in several different possible modes (I've stripped out a bunch of assembler directives in all cases, for clarity)...

# -S -O2 -m32 -fomit-frame-pointer
incval:
        incl    %gs:val@ntpoff
        ret

# -S -O2 -m64
incval:
        incl    %fs:val@tpoff
        ret

# -S -O2 -m32 -fomit-frame-pointer -fpic
incval:
        pushl   %ebx
        call    __x86.get_pc_thunk.bx
        addl    $_GLOBAL_OFFSET_TABLE_, %ebx
        leal    val@tlsgd(,%ebx,1), %eax
        call    ___tls_get_addr@PLT
        incl    (%eax)
        popl    %ebx
        ret

# -S -O2 -m64 -fpic
incval:
        .byte   0x66
        leaq    val@tlsgd(%rip), %rdi
        .value  0x6666
        rex64
        call    __tls_get_addr@PLT
        incl    (%rax)
        ret

Do realize that all four examples would be different if I'd compiled for x86/OSX, and different yet again for x86/Windows.

like image 113
zwol Avatar answered Sep 17 '22 17:09

zwol