2015-11-14 4 views
0

Я прочел еще discussion.О доступе% 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 
    ... 

Я отлаживать с 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 is 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 устанавливается только один раз.

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

ответ

0

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

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

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

[1] Это может означать, что ОС просто делает виртуальный адрес доступным для TLS, но фактическое распределение памяти PHYSICAL происходит «по мере необходимости», так же, как исполняемый файл, общая библиотека или большое выделение памяти

+0

Я ошибался в своем описании;). Значение% gs равно 0x63. Я считаю, что это число является номером дескриптора сегмента, и этот дескриптор указывает на 0x080fd840. Обратите внимание, что число% gs n когда-либо меняются в моем случае, он всегда равен 0x63 (даже произошел конфликт контекста потока). По вашему отвечу, [OS поддерживает и то, что% gs обновляется при загрузке следующего потока], я думаю, что ОС изменила «content» дескриптора (0x63) при загрузке нового потока. Поэтому '0x080fd810' не равно% gs: 0xffffffd0. Все идет нормально? – hwliu

+0

Да, то, что ОС фактически делает, это обновление базового адреса '% gs'. –

+0

На самом деле вы могли бы добавить код для печати адреса 'Sum' в своем коде, и вы заметили бы, что он по разному адресу в каждом потоке. –

 Смежные вопросы

  • Нет связанных вопросов^_^