Search code examples
cmultithreadinggccnm

gcc: Thread-local variable compiled as BSS


I am new to and testing the thread-local storage (TLS) class with gcc (version 4.8.2) on my Ubuntu 14.04 computer with i686/32 bit architecture.

In trying to find out whether the __thread keyword has the desired effect, I compile this minimalistic test program with gcc test.c (no errors or warnings):

#include <stdio.h>

__thread int i;

int main() {
  i = 7;
  printf("%d\n",i);
}

and use the tool nm to check the storage class of the symbol i in the object code:

nm a.out | grep ' i'

The result is

00000000 B i

which means that i is treated as a common global uninitialized variable (stored in the BSS section). According to man nm, thread local storage variables are denoted by the letter L, not B.

What's wrong here?

Is this an nm problem or a real problem?


Solution

  • There's no problem, it's just the way nm(1) writes output.

    nm(1)'s default output format (and information) is different among platforms (for example the manpage for nm(1) in my Linux desktop doesn't even mention L for thread-local storage).

    However, if you enable SysV output format with -fs, you get a more verbose output:

    $ nm -fs a.out
    Symbols from a.out:
    
    Name                  Value           Class        Type         Size             Line  Section
    
    ...
    
    i                   |0000000000000000|   B  |               TLS|0000000000000004|     |.tbss
    ...
    

    As you can see, using this output format i is identified as being thread local under the column Type, and it lives in .tbss.

    If the manpage for your distribution mentions the L flag for thread-local storage and you don't see it in the default output format, I'd say it's a bug in nm(1).