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