2011-07-07 11 views
23

En la arquitectura x86-64, dos registros tienen un propósito especial: FS y GS. En Linux 2.6. *, El registro FS parece usarse para almacenar información local de subprocesos.¿Cómo se usan los registros fs/gs en Linux AMD64?

  • ¿Es correcto?
  • ¿Qué se almacena en fs: 0? ¿Hay alguna estructura C que describa este contenido?
  • ¿Cuál es entonces el uso de GS?

Respuesta

28

En x86-64 hay 3 TLS entries, dos de ellos accesible a través de FS and GS, FS se utiliza internamente por glibc (en IA32 parecer FS is used by Wine and GS by glibc).

Glibc hace que su punto de entrada TLS sea un struct pthread que contiene algunas estructuras internas para enhebrar. Glibc generalmente se refiere a una variable struct pthread como pd, presumiblemente para pthread descriptor.

en x86-64, struct pthread comienza con una tcbhead_t (esto depende de la arquitectura, ver las macros TLS_DTV_AT_TP y TLS_TCB_AT_TP). Este encabezado del bloque de control de subprocesos, AFAIU, contiene algunos campos que se necesitan incluso cuando hay un solo subproceso. El DTV es el Dynamic Thread Vector y contiene punteros a bloques TLS para DSO cargados a través de dlopen(). Antes o después del TCB hay un bloque estático TLS para el ejecutable y DSO vinculados al tiempo de carga (del programa). El TCB y el DTV se explican bastante bien en Ulrich Drepper's TLS document (busque los diagramas en el capítulo 3).

+1

FS es utilizado por win32 en x86 para apuntar a la información del hilo de la ventana - el vino simplemente lo está igualando. –

10

Para responder a su pregunta en realidad fs:0: El x86_64 ABI requiere que fs:0 contiene la dirección "señaló que" por fs sí. Es decir, fs:-4 carga el valor almacenado en fs:0 - 4. Esta función es necesaria porque no puede obtener fácilmente la dirección apuntada por fs sin pasar por el código del kernel. Tener la dirección almacenada en fs:0 hace que trabajar con el almacenamiento local de subprocesos sea mucho más eficiente.

se puede ver esto en acción cuando se toma la dirección de una variable local de rosca:

static __thread int test = 0; 

int *f(void) { 
    return &test; 
} 

int g(void) { 
    return test; 
} 

compila a

f: 
    movq %fs:0, %rax 
    leaq -4(%rax), %rax 
    retq 

g: 
    movl %fs:-4, %eax 
    retq 

i686 hace lo mismo pero con %gs. En aarch64 esto no es necesario porque la dirección se puede leer desde el propio registro tls.

Cuestiones relacionadas