Windows — Как назвать разделы / группы для трех объектов C ++ при использовании init_seg?

я использую init_seg управлять созданием трех объектов класса C ++. Каждый объект находится в отдельном исходном файле / модуле перевода. Отладка показывает, что объекты создаются должным образом во время инициализации CRT.

Объекты инициализируются в алфавитном порядке их исходного файла. Я хотел бы изменить это, потому что это не совсем правильно. Я посетил страницу MSDN на init_seg, и это заявляет, что использование:

#pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )

Похоже, использование lib а также section-name являются взаимоисключающими, поэтому мне не ясно, как использовать init_seg(lib) и укажите название раздела / группы, чтобы получить правильный алфавитный порядок.

Когда я пытаюсь использовать алфавитную строку для управления порядком:

#pragma init_seg(lib, "01")

Это приводит к предупреждению, которое, я предполагаю, означает, что все не будет работать так, как ожидалось:

warning C4081: expected ')'; found ','

Когда я пытаюсь вставить непосредственно в код запуска CRT непосредственно с помощью ".CRT$XCB", ".CRT$001", а также ".CRT$XCB001" (и другие варианты использования алфавитизации):

#pragma init_seg(".CRT$XCB")

Это приводит к другому предупреждению, которое, как я предполагаю, означает, что все не будет работать так, как ожидалось:

warning C4075: initializers put in unrecognized initialization area

Я нашел один вопрос о переполнении стека об этом, но ответ был предположение и он не охватывает несколько единиц перевода. Я также нашел архив KB104248 на Wayback Machine, но это не сильно помогает, потому что это показывает только использование compiler, lib а также user,

Итак, мой вопрос, как я могу использовать init_seg контролировать точный порядок создания моих трех объектов в трех разных исходных файлах?

0

Решение

Вот что я нашел в ходе тестирования на XP и VS2002 / VS2003, Vista и VS2005 / VS2008, Windows 7 и VS2008 / VS2010, Windows 8 и VS2010 / VS2012 / VS2013 и Windows 10 с использованием VS2015. #pragma_init(<name>) был доступен с VC ++ 1.0 дней. MS не публикует слишком много информации об этом, но мы знаем, что это документировано из VC ++ 1.0 (заархивировано KB104248) через VS2017.

  1. #pragma init_seg(lib) почти идеально. Однако в VS2008 и более ранних версиях объектные файлы расположены в алфавитном порядке, поэтому порядок инициализации a-b-c (нежелательный), а не c-b-a (По желанию). Его хорошо на VS2010 и выше. Что не очевидно, так это порядок, c-b-a в vcproj файлы.

  2. #pragma init_seg(".CRT$XCB-0NN") казалось, работает. наш std::strings STRING_A а также STRING_B были созданы рано (и объекты были в правильном порядке), но STRING_B вызвал аварию на suhutdown. Адрес был 0x0000000dи оказывается std::string (и его vtable) были уничтожены слишком рано.

  3. #pragma init_seg(".CRT$XCU-0NN") работал как положено во время запуска и выключения. Если я правильно прочитал, то U в названии группы XCU указывает определенные пользователем объекты. Это означает, что наши объекты были созданы где-то между #pragma init_seg(lib) а также #pragma init_seg(user) обеспечивает.

Итак, вот как инициализировать объект C, затем объект B, затем объект A из исходных файлов. a.cpp, b.cpp а также c.cpp,

Исходный файл a.cpp:

class A
{
...
};

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-030")
A a;    // created 3rd
#pragma warning(default: 4075)

Исходный файл b.cpp:

class B
{
...
};

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-020")
const B b;    // created 2nd
#pragma warning(default: 4075)

Исходный файл c.cpp:

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-010")
const std::string c;    // created 1st
const std::string d;    // created 1st
#pragma warning(default: 4075)

Наш вариант использования состоял в том, чтобы создать три объекта только для чтения и избежать проблем с C ++ статический порядок инициализации фиаско и Microsoft поток локального хранилища.

Техника позволяет избежать отсутствия динамических инициализаторов C ++ в C ++ 03. Это также побочные шаги неспособности Microsoft предоставить C ++ 11 Динамическая инициализация и разрушение с параллелизмом (или, точнее, отказ Microsoft от предоставления основной языковой функции в течение 10 лет).

Вот ссылка на проблему на Локальное хранилище потоков (TLS) на MSDN:

В операционных системах Windows до Windows Vista __declspec (поток) имеет некоторые ограничения. Если DLL объявляет какие-либо данные или объект как __declspec (поток), это может вызвать сбой защиты при динамической загрузке. После загрузки библиотеки DLL с помощью LoadLibrary она вызывает системный сбой всякий раз, когда код ссылается на данные __declspec (thread). Поскольку пространство глобальных переменных для потока выделяется во время выполнения, размер этого пространства основан на расчете требований приложения плюс требований всех статически связанных библиотек DLL. Когда вы используете LoadLibrary, вы не можете расширить это пространство, чтобы разрешить локальные переменные потока, объявленные с помощью __declspec (thread). Используйте API-интерфейсы TLS, такие как TlsAlloc, в вашей DLL для выделения TLS, если библиотека DLL может быть загружена с помощью LoadLibrary.

Также стоит упомянуть, что есть не представляется ограничением на количество символов в названии раздела или группы. В архиве KB 104248 использует имя "user_defined_segment_name" с 26 символами.

2

Другие решения

Вам нужно использовать #pragma section (https://msdn.microsoft.com/en-us/library/50bewfwa.aspx) указать атрибуты раздела, если вы используете произвольное имя раздела

#pragma section("foo",long,read,write)
#pragma init_seg("foo")

Вы можете убедиться, что пользовательские сегменты из нескольких файлов упорядочены путем добавления суффикса после знака доллара.

// tu1.cpp
#pragma section("foo$1",long,read,write)
#pragma init_seg("foo$1")

// tu2.cpp
#pragma section("foo$2",long,read,write)
#pragma init_seg("foo$2")

Данные из tu1.cpp теперь будут до этого из tu2.cpp

Вы можете упорядочить вещи относительно библиотеки времени выполнения C, добавив суффикс к сегментам CRT

// tu1.cpp
#pragma section(".CRT$XCU1",long,read,write)
#pragma init_seg("foo$1")

// tu2.cpp
#pragma section(".CRT$XCU2",long,read,write)
#pragma init_seg("foo$2")

TU1 теперь перед TU2 и сгруппирован с другими данными

1

По вопросам рекламы [email protected]