Добрый день!
Допустим я использую /NODEFAULTLIB. И допустим написал startup код вызывающий статические конструкторы и вызывающий деструкторы при выходе из программы.
Проблема с _tls_array. Компилятор (vs2015) создает ссылки на него при обращении к переменным использующим _declsec(thread) и при компиляции тестового проекта сообщает об ошибке:
Unresolved external __tls_array
Если же объявить эту переменную в стиле:
extern "C" unsigned long _tls_array = 0;
то ошибка возникает уже на этапе выполнения. Суть ее в том что при обращении к _declsec(thread) переменной генерируется примерно такой код
где вместо _tls_array при использовании стандартной библиотеки появляется (0x2C).
Вообщем вопрос следующий: как правильно объявить внешний символ _tls_array чтобы компоновщик разместил его по абсолютному адресу 0x2C, а не по относительному адресу (как из примера 0F5A19С) ?
Здравствуйте, PavelCH, Вы писали:
PCH>Вообщем вопрос следующий: как правильно объявить внешний символ _tls_array чтобы компоновщик разместил его по абсолютному адресу 0x2C, а не по относительному адресу (как из примера 0F5A19С) ?
.386
.model flat,stdcall
public _tls_array
_tls_array equ 2Ch
end
Но там есть ещё thread safe statics (/Zc:threadSafeInit) и прочее. Впрочем, сорцы crt открыты.
Нет. Код будет генерироваться тот же что я написал в первом посте. Просто значение по адресу будет другое. Но это значение даже невозможно будет получить, потому что там сегмент FS и по такому смещению будет ошибка чтения памяти.
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 колбэков.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, 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.
Здравствуйте, PavelCH, Вы писали:
F>>public _tls_array F>>_tls_array equ 2Ch
PCH>А такой вопрос — неужели можно только через ассемблер? А в языке с++ нельзя объявить так переменную?
Чёрт его знает. Переменная — это адрес памяти, а тут публичная константа просто.
В С++ константы — это тоже переменные, разве что enum { _tls_array = 0x2C } помог бы, но вряд ли так можно.