linuxglibcnptl

What is the purpose of this code segment from glibc


I am trying to understand what the following code segment from tls.h in glibc is doing and why:

/* Macros to load from and store into segment registers.  */
# define TLS_GET_FS() \
  ({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; })

I think I understand the basic operation it is moving the value stored in the fs register to __seg. However, I have some questions:

  1. My understanding is the fs is only 16-bits. Is this correct? What happens when the value gets moved to a quadword memory location? Does this mean the upper bits get set to 0?

  2. More importantly I think that the scope of the variable __seg that gets declared at the start of the segment is limited to this segment. So how is __seg useful? I'm sure that the authors of glibc have a good reason for doing this but I can't figure out what it is from looking at the source code.

I tried generating assembly for this code and I got the following?

 #APP
 # 13 "fs-test.cpp" 1
 movl %fs, %eax
 # 0 "" 2
 #NO_APP

So in my case it looks like eax was used for __seg. But I don't know if that is always what happens or if it was just what happened in the small test file that I compiled. If it is always going to use eax why wouldn't the assembly be written that way? If the compiler might pick other registers then how will the programmer know which one to access since __seg goes out of scope at the end of the macro? Finally I did not see this macro used anywhere when I grepped for it in the glibc source code, so that further adds to my confusion about what its purpose is. Any explanation about what the code is doing and why is appreciated.


Solution

  • My understanding is the fs is only 16-bits. Is this correct? What happens when the value gets moved to a quadword memory location? Does this mean the upper bits get set to 0?

    Yes.

    the variable __seg that gets declared at the start of the segment is limited to this segment. So how is __seg useful?

    You have to read about GCC statement-expression extension. The value of statement expression is the value of the last expression in it. The __seg; at the end would be useless, unless one assigns it to something else, like this:

    int foo = TLS_GET_FS();
    

    Finally I did not see this macro used anywhere when I grepped for it in the glibc source code

    The TLS_{GET,SET}_FS in fact do not appear to be used. They probably were used in some version, then accidentally left over when the code referencing them was removed.