glibc TLS init macro

크리에이티브 커먼즈 라이선스
Creative Commons License
set_thread_area 시스템콜을 호출함
# define TLS_INIT_TP(thrdescr, secondcall) \
  ({ void *_thrdescr = (thrdescr);					      \
     tcbhead_t *_head = _thrdescr;					      \
     union user_desc_init _segdescr;					      \
     int _result;							      \
									      \
     _head->tcb = _thrdescr;						      \
     /* For now the thread descriptor is at the same address.  */	      \
     _head->self = _thrdescr;						      \
     /* New syscall handling support.  */				      \
     INIT_SYSINFO;							      \
									      \
     /* The 'entry_number' field.  Let the kernel pick a value.  */	      \
     if (secondcall)							      \
       _segdescr.vals[0] = TLS_GET_GS () >> 3;				      \
     else								      \
       _segdescr.vals[0] = -1;						      \
     /* The 'base_addr' field.  Pointer to the TCB.  */			      \
     _segdescr.vals[1] = (unsigned long int) _thrdescr;			      \
     /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */	      \
     _segdescr.vals[2] = 0xfffff;					      \
     /* Collapsed value of the bitfield:				      \
	  .seg_32bit = 1						      \
	  .contents = 0							      \
	  .read_exec_only = 0						      \
	  .limit_in_pages = 1						      \
	  .seg_not_present = 0						      \
	  .useable = 1 */						      \
     _segdescr.vals[3] = 0x51;						      \
									      \
     /* Install the TLS.  */						      \
     asm volatile (TLS_LOAD_EBX						      \
		   "int $0x80\n\t"					      \
		   TLS_LOAD_EBX						      \
		   : "=a" (_result), "=m" (_segdescr.desc.entry_number)	      \
		   : "0" (__NR_set_thread_area),			      \
		     TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc));    \
									      \
     if (_result == 0)							      \
       /* We know the index in the GDT, now load the segment register.	      \
	  The use of the GDT is described by the value 3 in the lower	      \
	  three bits of the segment descriptor value.			      \
									      \
	  Note that we have to do this even if the numeric value of	      \
	  the descriptor does not change.  Loading the segment register	      \
	  causes the segment information from the GDT to be loaded	      \
	  which is necessary since we have changed it.   */		      \
       TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3);		      \
									      \
     _result == 0 ? NULL						      \
     : "set_thread_area failed when setting up thread-local storage\n"; })

신고

설정

트랙백

댓글

linux에서 gs 세그멘트 셀렉터가 가르키는 값들의 용도

크리에이티브 커먼즈 라이선스
Creative Commons License

glibc-2.19기준으로

glibc-2.19/nptl/sysdeps/i386/tls.h 에 정의돼있습니다

 

typedef struct
{
  void *tcb;  /* Pointer to the TCB.  Not necessarily the
      thread descriptor used by libpthread.  */
  dtv_t *dtv;
  void *self;  /* Pointer to the thread descriptor.  */
  int multiple_threads;
  uintptr_t sysinfo;
  uintptr_t stack_guard;
  uintptr_t pointer_guard;
  int gscope_flag;
#ifndef __ASSUME_PRIVATE_FUTEX
  int private_futex;
#else
  int __glibc_reserved1;
#endif
  /* Reservation of some values for the TM ABI.  */
  void *__private_tm[4];
  /* GCC split stack support.  */
  void *__private_ss;
} tcbhead_t; 

 

제일 많이 쓰이는 예로 %gs:0x14는 stack_guard에 해당하는 부분이고

setjmp, longjmp에서 사용하는 pointer_guard도 있습니다

신고

설정

트랙백

댓글


티스토리 툴바