О доступе к%gs

Я прочитал другое обсуждение.

я знаю %gs регистр сегмента, он хранит дескриптор сегмента. ОС получает дескриптор сегмента и вычисляет физический адрес. В большинстве случаев дескриптор сегмента непрозрачен для программиста. Я могу сделать какой-то трюк, как перехват Systcall set_thread_area и получить значение% GS.

Но большая часть того, что они говорят, все еще слишком абстрактна для меня. Поэтому я пытаюсь создать простой код для выражения моего вопроса. Я надеюсь, что кто-то может сказать мне, что я делаю неправильно в моем примере.

Во-первых, я пишу код pthread следующим образом.

__thread int Sum = 123; // declare as __thread type. 123 = 0x7b

void *show_msg( void *ptr ) {
 for( int x = 5 ; x > 0 ; --x){
    printf("%d\n", Sum++ ); // print the value of Sum and plus 1
    sleep(1);
 }
 pthread_exit((void *)1234);
}

int main(){
   pthread_t thread1;
   pthread_t thread2;
   char *message1 = "Thread 1";
   char *message2 = "Thread 2";

   pthread_create(&thread1, NULL , show_msg , (void*) message1);
   pthread_create(&thread2, NULL , show_msg , (void*) message2);
   pthread_join( thread1, &ret);
   pthread_join( thread2, &ret);

   return 0;
}

Я собираю это с gcc test.cpp -lpthread -static -m32

Тогда я делаю objdump -D a.out, Я публикую только часть результата, которую не могу понять. Так как a.out это статический связанный двоичный файл, я могу получить код инициализации, например <__libc_setup_tls>

08052510 <__libc_setup_tls>:
  ...
805262c: mov $0xf3,%eax ; syscall number 0xf3 is set_thread_area
8052631: mov %ebx,0x24(%esp)
805262c: lea 0x20(%esp),%ebx ; %ebx stores a pointer to struct user_desc
  ...
8052651: int $0x80

  ...

080496d4<_Z8show_msgPv>:
  ...
80496f0: mov %gs:0xffffffd0,%eax
80496f6: lea 0x1(%eax),%edx
80496f9: mov %edx,%gs:0xffffffd0
  ...

Я запускаю gdb с помощью a.out и устанавливаю точку останова на 0x805262c и 0x80496f0.

805262c: lea 0x20(%esp),%ebx ; %ebx stores a pointer to struct user_desc

После того, как я выполню эту инструкцию, значение% ebx будет 0xffffccd0. Я знаю, что значение 0xffffccd0 является указателем user_descи память 0xffffccd4 хранит значение %gs, что составляет 0x080fd840.

Затем я продолжаю отладку.

80496f0: mov %gs:0xffffffd0,%eax

Я знаю ценность %gs 0x63, который является номером дескриптора сегмента и указывает на 0x080fd840. Так что я могу рассчитать стоимость %gs:0xffffffd0 является 0x080fd810, Память 0x080fd810 хранит 0x7b. Мне интересно, когда я получаю это значение, потому что 0x7b - это шестнадцатеричное значение 123, которое является начальным значением глобальной переменной. Sum,

Но что-то странное, когда я делаю следующие инструкции.

80496f6: lea 0x1(%eax),%edx ; yield %edx = 0x7c
80496f9: mov %edx,%gs:0xffffffd0 ; store 0x7c to %gs:0xffffffd0(????)

Результат сложения не сохраняется в 0x080fd810адрес памяти %gs:0xffffffd0, Но следующая итерация этого потока может получить 0x7c из %gs:0xffffffd0!!!

Я отслеживаю системный вызов с помощью strace -c ./a.out, Это показывает, что количество звонящих set_thread_area только 1. То есть %gs устанавливается только один раз.

Я думаю, что ОС делает некоторые изменения, когда происходит переключение контекста потока. Кто-нибудь может дать мне более подробную информацию и сказать, почему моя идея неверна в этом случае?

1 ответ

ОС будет обрабатывать память для локального потока (TLS) и поддерживать оба, что %gs [или его базовый адрес] обновляется при загрузке следующего потока, и эта память выделяется [1] при создании нового потока.

Компилятор и компоновщик отвечают за вычисление размера и соответствующих смещений в TLS - в этом случае может показаться, что реализация использует отрицательные смещения от базового адреса, поэтому ваша конкретная переменная имеет значение -0x30 от %gs,

[Когда вы говорите "Я знаю, %gs 0x080fd840, вы имеете в виду, что базовый адрес для сегмента это значение, верно? поскольку %gs будет 16-битный индекс в таблице дескрипторов x86]

[1] Это может означать, что ОС просто делает виртуальный адрес доступным для TLS, но фактическое выделение ФИЗИЧЕСКОЙ памяти происходит "по мере необходимости", так же, как выполняется исполняемый файл, разделяемая библиотека или большой объем памяти.,

Другие вопросы по тегам