Можно ли использовать компилятор Visual Studio 2010 C++ с библиотекой времени выполнения C++ Visual Studio 2008?

У меня есть приложение, которое должно работать в Windows 2000. Я также хотел бы использовать Visual Studio 2010 (в основном из-за изменения в определении auto ключевое слово). Однако я немного затруднен, потому что мне нужно, чтобы приложение могло работать на старых ОС, а именно:

  • Windows 2000
  • Windows XP RTM
  • Windows XP SP1

Библиотека времени выполнения Visual Studio 2010 зависит от EncodePointer / DecodePointer API, который был представлен в Windows XP SP2.

Если возможно использование альтернативной библиотеки времени выполнения, будет ли этот код разрыва, основанный на функциях C++0x, добавлен в VS2010, например std::regex?

8 ответов

Решение

Решение Suma выглядело многообещающе, но оно не работает: __imp__*@4 символы должны быть указателями на функции, а не на сами функции. К сожалению, я не знаю, как заставить Visual C++ выплевывать указатель с таким типом генерации имен... (ну, __declspec(naked) в сочетании с __stdcall делает трюк, но тогда я не знаю, как испустить указатель).

Если использование ассемблера во время сборки в порядке, решение довольно тривиально - собрать следующий код с FASM и связать его с созданным объектным файлом, а затем - без ссылок EncodePointer/DecodePointer в exe:

use32
format ms coff

section ".data" data
public __imp__DecodePointer@4
__imp__DecodePointer@4 dd dummy

public __imp__EncodePointer@4
__imp__EncodePointer@4 dd dummy

section ".text" code
dummy:
mov eax, [esp+4]
retn 4

Самое простое решение - просто установить набор инструментов платформы в настройках проекта в VS2010 на v900, который будет использовать библиотеки Visual Studio 2008 и компилятор. Это также означает, что вы теряете функции C++0x, такие как auto, но, если честно, обойти это с некоторыми typedefВозможно, это проще, чем создавать собственную версию CRT или другие более сложные решения. В качестве альтернативы, просто используйте VS2008! Я не знаю, есть ли другие функции C++0x, которые важны для вашего приложения, хотя, вы не упомянули - кроме std::regexкоторый, я думаю, все еще находится в наборе инструментов v900 под пространством имен технического отчета 1 (std::tr1::regex).

Исходя из того впечатления, которое я получаю, я могу предсказать, что неудобство запуска библиотек VS2010 на XP SP1 больше, чем удобство функций C++0x, так что в целом оно того не стоит.

Вы не можете использовать CRT 2008, но можете запретить связывание новых функций DecodePointer/EncodePointer из ядра. Заменить новые функции на заглушки довольно просто.

Можно попытаться сделать следующее: Поместите такой код в исходный код main.cpp:

extern "C" {

  void *__stdcall _imp__DecodePointer(void *x) {return x;}
  void *__stdcall _imp__EncodePointer(void *x) {return x;}

};

Выше не работает. В то время как основная идея - это звук, исполнение должно быть немного другим. Как описано snemarch в комментарии и другой ответ, __imp__ не может быть вызовом функции, только указатель на нее. Поскольку кажется невозможным сгенерировать указатель непосредственно компилятором, вам нужно собрать следующий код с помощью MASM и связать его с созданным объектным файлом.

.model flat

.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD

.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp

end

Символы из проекта имеют преимущество перед любыми символами из библиотек. Библиотеки DLL связаны с использованием частей.lib, которые содержат только __imp__ "векторы" прыгают в реальные функции. Заменяя __imp__ "векторы" вы не трогаете связью DLL, вы заменяете часть.lib. Я убедился, что больше нет никакой зависимости exe-файла от DecodePointer / EncodePointer.

Фон

Статически связанная библиотека вносит в приложение только используемые функции. Можно найти, какую конкретную функцию CRT привнести в этот новый API, используя подробный вывод прогресса компоновщика:

Found __imp__EncodePointer@4
  Referenced in LIBCMT.lib(crtmboxw.obj)
  Referenced in LIBCMT.lib(invarg.obj)
  Referenced in LIBCMT.lib(handler.obj)
  Referenced in LIBCMT.lib(onexit.obj)
  Referenced in LIBCMT.lib(cmiscdat.obj)
  Referenced in LIBCMT.lib(tidtable.obj)
  Referenced in LIBCMT.lib(hooks.obj)
  Referenced in LIBCMT.lib(winsig.obj)
  Referenced in LIBCMT.lib(rand_s.obj)

Found __imp__DecodePointer@4
  // ... same list, only order differs ... 

Это показывает, что новые API используются в некоторых CRT для обеспечения большей безопасности для некоторых функций, которые, как считается, предоставляют частые векторы атак.

С некоторыми усилиями было бы возможно использовать LoadLibrary / GetProcAddress, чтобы обеспечить реальную функциональность, в которой находятся предложения ОС, но я не думаю, что это действительно что-то принесет. Функции времени выполнения, которые используют DecodePointer/EncodePointer, на самом деле не нуждаются в этом для обеспечения какой-либо кодировки, все, что им нужно, - это кодирование симметричным. Вам на самом деле не нужна повышенная безопасность (среда выполнения VS 2008 также не предоставит ее вам).

Надеюсь, вас больше не ждут другие препятствия - у меня нет доступа к системе Win2k или XP pre SP2, поэтому я не могу попробовать. Если есть какие-либо флаги заголовка exe, предотвращающие даже попытку запуска exe в таких системах, их легко изменить.

Поскольку Visual Studio поставляется с поддержкой MASM (см. Свойства проекта -> Настройки сборки...), может пригодиться следующий перевод кода snemarch в MASM:

.model flat

.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD

.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp

end

И не забудьте установить Linker->System->Minimum Required Version на 5.0 (по умолчанию 5.1) для работы в Windows 2000.

Обычное решение этой проблемы - создание собственной пользовательской версии CRT. Здесь есть инструкции для этого. Вам просто нужно отредактировать код, чтобы игнорировать EncodePointer а также DecodePointer, (Там уже должно быть #define для этого.)

Есть две другие незначительные вещи, которые вам нужно сделать:

  • Перейдите к настройке Linker-> Дополнительные каталоги библиотек и установите C:\Microsoft Visual Studio 9.0\VC\lib в качестве первого пути для поиска. (Я предполагаю, что вы использовали каталог установки по умолчанию, в противном случае измените соответствующим образом.)
  • Измените версию подсистемы в заголовке PE на 5.00 (используйте бесплатный CFF Explorer Suite, если у вас нет другого удобного инструмента для этого).

Это должно позволить вашей программе работать в Windows 2000, а также в более поздних версиях.

Вариант 1 - создать модифицированную версию среды выполнения 2010, которая перенаправляет вызовы API-проблемы в предоставленную вами DLL-библиотеку. Я не знаю, насколько это легко или сложно - надеюсь, просто незначительная настройка таблицы символов, но это зависит от формата файла - и вы, скорее всего, столкнетесь с пунктом обратного инжиниринга лицензии, конечно,

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

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

Вариант 4. Проверьте, можете ли вы использовать компилятор 2010 года, но более старый компоновщик, возможно, настроенный в ваших решениях в качестве пользовательского этапа сборки. Опять же, это зависит от того, имеют ли файлы obj и lib одинаковый формат файла, но вы можете написать небольшую утилиту для исправления простых различий, таких как номера версий, в заголовке. У старого компоновщика не должно быть проблем с компоновкой в ​​старшей среде выполнения - при условии совместимости с ним объектов нового компилятора.

Вариант 5 - сборка DLL в 2010 году, которые не нуждаются в собственном времени выполнения, но которые загружаются и размещаются приложением, созданным с использованием более старого компилятора. Достижение требования "без времени выполнения" для ваших DLL может означать, что многие из ваших библиотек должны быть встроены в хост-приложение, и вам может потребоваться предоставить свои собственные интерфейсы (через хост-приложение) для библиотечных функций, которые вам нужны для работы с - особенно вещи выделения памяти.

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

Это было бы намного проще, если бы вы могли использовать DLL. По сути, напишите EXE, который вообще не требует никаких функций времени исполнения C, используя функцию компоновщика /ENTRYPOINT. После того, как вы проверили, что ваши основные предварительные требования выполнены, и сообщили о любых проблемах пользователю с помощью только API-интерфейсов Windows, доступных на всех целевых ОС (например, MessageBox), затем вызовите LoadLibrary, чтобы запустить библиотеку DLL, которая содержит основную часть вашей логики., Эта DLL может использовать среду выполнения VS2010 как обычно. Вы даже можете избежать развертывания двух отдельных файлов, распаковывая DLL из ресурса, содержащегося в вашем главном.EXE при запуске. (Вы можете сделать это полностью в памяти, не записывая.DLL на диск, но не в том случае, если вы хотите воспользоваться загрузчиком Windows PE для исправления всех ваших операций импорта).

Создайте.LIB, который реализует отсутствующую функциональность, и свяжите его с KERNEL32.LIB.

Вам нужно будет использовать параметр компоновщика /NODEFAULTLIB:kernel32.lib, чтобы вы могли поставить свой w2kcompat.lib перед kernel32.lib.

Другие вопросы по тегам