VS2015 и _tls_array
От: PavelCH  
Дата: 27.07.16 12:43
Оценка:
Добрый день!
Допустим я использую /NODEFAULTLIB. И допустим написал startup код вызывающий статические конструкторы и вызывающий деструкторы при выходе из программы.
Проблема с _tls_array. Компилятор (vs2015) создает ссылки на него при обращении к переменным использующим _declsec(thread) и при компиляции тестового проекта сообщает об ошибке:

Unresolved external __tls_array

Если же объявить эту переменную в стиле:
extern "C" unsigned long _tls_array = 0;

то ошибка возникает уже на этапе выполнения. Суть ее в том что при обращении к _declsec(thread) переменной генерируется примерно такой код
00F55D83  mov eax,dword ptr [_tls_index (0F5A198h)]  
00F55D88  mov ecx,dword ptr fs:[_tls_array (0F5A19Сh)]
00F55D8F  mov edx,dword ptr [ecx+eax*4]

где вместо _tls_array при использовании стандартной библиотеки появляется (0x2C).

Вообщем вопрос следующий: как правильно объявить внешний символ _tls_array чтобы компоновщик разместил его по абсолютному адресу 0x2C, а не по относительному адресу (как из примера 0F5A19С) ?
Нехай щастить
Re: VS2015 и _tls_array
От: rm822 Россия  
Дата: 27.07.16 16:21
Оценка:
что-то мне кажется что должно быть тупо
[сcode]
extern "C" unsigned long _tls_array = 0x2c;
[/сcode]
Re: VS2015 и _tls_array
От: flаt  
Дата: 27.07.16 16:50
Оценка: 3 (1)
Здравствуйте, PavelCH, Вы писали:

PCH>Вообщем вопрос следующий: как правильно объявить внешний символ _tls_array чтобы компоновщик разместил его по абсолютному адресу 0x2C, а не по относительному адресу (как из примера 0F5A19С) ?


.386
.model flat,stdcall

public _tls_array
_tls_array     equ    2Ch
end


Но там есть ещё thread safe statics (/Zc:threadSafeInit) и прочее. Впрочем, сорцы crt открыты.
Re[2]: VS2015 и _tls_array
От: PavelCH  
Дата: 27.07.16 18:22
Оценка:
Здравствуйте, rm822, Вы писали:

Нет. Код будет генерироваться тот же что я написал в первом посте. Просто значение по адресу будет другое. Но это значение даже невозможно будет получить, потому что там сегмент FS и по такому смещению будет ошибка чтения памяти.
Нехай щастить
Re[2]: VS2015 и _tls_array
От: PavelCH  
Дата: 27.07.16 18:55
Оценка:
F>
F>.386
F>.model flat,stdcall

F>public _tls_array
F>_tls_array     equ    2Ch
F>end
F>


Супер! Заработало.
А такой вопрос — неужели можно только через ассемблер? А в языке с++ нельзя объявить так переменную?
Нехай щастить
Re: VS2015 и _tls_array
От: ononim  
Дата: 27.07.16 19:01
Оценка:
PCH>Вообщем вопрос следующий: как правильно объявить внешний символ _tls_array чтобы компоновщик разместил его по абсолютному адресу 0x2C, а не по относительному адресу (как из примера 0F5A19С) ?
TLS получается не просто изза обращения к адресу 2Ch, а изза обращения к этому адресу с селектором fs. fs:[0] указывает на начало структуры TIB/TEB текущего потока. Соответственно FS:[2Ch] — указывает на ее поле ThreadLocalStoragePointer, в котором уже лежит адрес массива TLS текущего потока но в пространстве селекторов cs/ds. Массив этот ициниализируется кодом ntdll в начале работы потока, и инициализируется он согласно TLS секциям загруженных в процессе модулей, включая ехе-шник.
Обращение же к DS:[2Ch] — просто выдаст AV.
Почему компилятор без CRT не желает генерировать TLS секцию и код обслуживающий обращение к ее данным — отдельный вопрос. Возможно, это не лечится, и придется юзать TlsAlloc etc. Впрочем можно попробовать устроить закат Солнца вручную, создавая TLS секцию используя #pragma, стартовая точка для ресерча вот — там правда другая задача решается — декларация TLS колбэков.
Как много веселых ребят, и все делают велосипед...
Отредактировано 27.07.2016 19:06 ononim . Предыдущая версия .
Re[2]: VS2015 и _tls_array
От: PavelCH  
Дата: 27.07.16 19:26
Оценка:
Здравствуйте, ononim, Вы писали:

O>TLS получается не просто изза обращения к адресу 2Ch, а изза обращения к этому адресу с селектором fs. fs:[0] указывает на начало структуры TIB/TEB текущего потока. Соответственно FS:[2Ch] — указывает на ее поле ThreadLocalStoragePointer, в котором уже лежит адрес массива TLS текущего потока но в пространстве селекторов cs/ds. Массив этот ициниализируется кодом ntdll в начале работы потока, и инициализируется он согласно TLS секциям загруженных в процессе модулей, включая ехе-шник.

O>Обращение же к DS:[2Ch] — просто выдаст AV.
Именно так. Но компилятор сам генерит код с сегментом FS, поэтому тут все ОК.
O>Почему компилятор без CRT не желает генерировать TLS секцию и код обслуживающий обращение к ее данным — отдельный вопрос. Возможно, это не лечится, и придется юзать TlsAlloc etc. Впрочем можно попробовать устроить закат Солнца вручную, создавая TLS секцию используя #pragma, стартовая точка для ресерча вот — там правда другая задача решается — декларация TLS колбэков.
Да. Генерирую секцию вручную при помощи #pragma без вызова TlsAlloc.
Нехай щастить
Re[3]: VS2015 и _tls_array
От: flаt  
Дата: 28.07.16 05:39
Оценка:
Здравствуйте, PavelCH, Вы писали:

F>>public _tls_array

F>>_tls_array equ 2Ch

PCH>А такой вопрос — неужели можно только через ассемблер? А в языке с++ нельзя объявить так переменную?


Чёрт его знает. Переменная — это адрес памяти, а тут публичная константа просто.

В С++ константы — это тоже переменные, разве что enum { _tls_array = 0x2C } помог бы, но вряд ли так можно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.