c++ - tutorial - visual studio code kompilieren




Kann ich den C++-Compiler von Visual Studio 2010 mit der C++-Laufzeitbibliothek von Visual Studio 2008 verwenden? (6)

Ich habe eine Anwendung, die unter Windows 2000 ausgeführt werden muss. Ich möchte auch Visual Studio 2010 verwenden (hauptsächlich wegen der Änderung der Definition des auto Schlüsselworts). Ich bin jedoch etwas in der Klemme, weil ich die App brauche, um auf älteren Betriebssystemen arbeiten zu können, nämlich:

  • Windows 2000
  • Windows XP RTM
  • Windows XP SP1

Die Laufzeitbibliothek von Visual Studio 2010 hängt von der EncodePointer / DecodePointer API ab, die in Windows XP SP2 eingeführt wurde.

Wenn die Verwendung der alternativen Laufzeitbibliothek möglich ist, wird dieser Code, der auf C ++ 0x-Features basiert, die in VS2010 hinzugefügt wurden, wie std::regex ?


Da Visual Studio MASM unterstützt (siehe Projekteigenschaften -> Build-Anpassungen ...), könnte die folgende Übersetzung von snemarchs Code in MASM nützlich sein:

.model flat

.data
[email protected] dd dummy
[email protected] dd dummy
EXTERNDEF [email protected] : DWORD
EXTERNDEF [email protected] : DWORD

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

end

Und denken Sie daran, Linker-> System-> Minimum Required Version auf 5.0 zu setzen (Standard ist 5.1), um unter Windows 2000 zu laufen.


Die übliche Lösung für dieses Problem besteht darin, eine eigene benutzerdefinierte Version des CRT zu erstellen. Es gibt Anweisungen dafür here . Sie müssen nur den Code bearbeiten, um EncodePointer und DecodePointer zu ignorieren. (Es sollte bereits ein #define dafür sein.)

Es gibt zwei andere kleinere Dinge, die Sie tun müssen:

  • Wechseln Sie zur Einstellung Linker-> Zusätzliche Bibliotheksverzeichnisse und legen Sie als ersten Pfad C:\Microsoft Visual Studio 9.0\VC\lib . (Ich nehme an, dass Sie das Standardinstallationsverzeichnis verwendet haben, ändern Sie es andernfalls entsprechend.)
  • Ändern Sie die Subsystemversion in der PE-Kopfzeile auf 5,00 (verwenden Sie die kostenlose CFF Explorer Suite, wenn Sie kein anderes Tool zur Hand haben).

Dadurch sollte Ihr Programm sowohl auf Windows 2000 als auch auf späteren Versionen ausgeführt werden können.


Dies wäre viel einfacher, wenn Sie eine DLL verwenden dürfen. Schreiben Sie eine EXE, die keine C-Laufzeitfunktionen überhaupt benötigt, indem Sie die Linker / ENTRYPOINT-Funktion verwenden. Sobald Sie getestet haben, dass Ihre grundlegenden Voraussetzungen erfüllt sind, und alle Probleme dem Benutzer über nur von Windows bereitgestellte APIs gemeldet wurden, die auf allen Zielsystemen (z. B. MessageBox) verfügbar sind, rufen Sie LoadLibrary auf, um die DLL mit dem Großteil Ihrer Logik zu starten . Diese DLL kann die VS2010-Laufzeit wie gewohnt verwenden. Sie können sogar die Bereitstellung von zwei separaten Dateien vermeiden, indem Sie die DLL beim Start aus einer Ressource in Ihrem Haupt-EXE dekomprimieren. (Sie können dies vollständig innerhalb des Arbeitsspeichers tun, ohne die .DLL auf die Festplatte zu schreiben, aber nicht, wenn Sie den Windows PE Loader nutzen möchten, um alle Ihre Importe zu reparieren).


Erstellen Sie eine LIB, die die fehlende Funktionalität implementiert, und verknüpfen Sie sie vor KERNEL32.LIB.

Sie müssen die Linker-Option /NODEFAULTLIB:kernel32.lib verwenden, damit Sie Ihre w2kcompat.lib vor kernel32.lib setzen können.


Sie können die CRT 2008 nicht verwenden, aber Sie können verhindern, dass die neuen Funktionen DecodePointer / EncodePointer vom Kernel aus verknüpft werden. Es ist ziemlich einfach, die neuen Funktionen durch Stubs zu ersetzen.

Man könnte folgendes versuchen: Platziere Code wie diesen in deiner main.cpp-Quelle:

extern "C" {

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

};

Das obige funktioniert nicht. Während die Grundidee solide ist, muss die Ausführung ein wenig anders sein. Wie von snemarch im Kommentar und einer anderen Antwort beschrieben , kann __imp__ nicht der Funktionsaufruf sein, __imp__ nur der Zeiger darauf. Da es nicht möglich ist, den Zeiger direkt vom Compiler zu generieren, müssen Sie den folgenden Code mit MASM zusammenstellen und mit der erzeugten Objektdatei verknüpfen.

.model flat

.data
[email protected] dd dummy
[email protected] dd dummy
EXTERNDEF [email protected] : DWORD
EXTERNDEF [email protected] : DWORD

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

end

Die Symbole aus einem Projekt haben Vorrang vor Symbolen aus Bibliotheken. DLL-Bibliotheken werden mithilfe von .lib-Teilen verknüpft, die nur __imp__ "Vektoren" enthalten, die in die echten Funktionen springen. Indem Sie __imp__ "Vektoren" ersetzen, berühren Sie nicht die DLL-Verknüpfung, sondern ersetzen den .lib-Teil. Ich habe überprüft, dass es keine Abhängigkeit der exe von DecodePointer / EncodePointer mehr gibt.

Hintergrund

Statisch verknüpfte Bibliothek bringt nur verwendete Funktionalität in die Anwendung. Es ist möglich zu finden, welche bestimmte CRT-Funktion diese neue API mithilfe der ausführbaren Linker-Fortschrittsausgabe einbringt:

Found [email protected]
  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 [email protected]
  // ... same list, only order differs ... 

Dies zeigt, dass die neuen APIs in einigen CRT verwendet werden, um mehr Sicherheit für einige Funktionen bereitzustellen, von denen angenommen wird, dass sie häufige Angriffsvektoren bereitstellen.

Mit einiger Mühe wäre es möglich, LoadLibrary / GetProcAddress zu verwenden, um die echte Funktionalität zu bieten, die OS bietet, aber ich denke nicht, dass es wirklich etwas bringen würde. Die Laufzeitfunktionen, die mit DecodePointer / EncodePointer arbeiten, benötigen sie eigentlich nicht, um eine Kodierung bereitzustellen, sie benötigen lediglich die Kodierung von symmetrisch. Sie brauchen die erweiterte Sicherheit nicht wirklich (die VS 2008 Runtime würde es Ihnen auch nicht geben).

Ich hoffe, es gibt keine anderen Hindernisse, die auf Sie warten - ich habe keinen Zugang zu Win2k oder XP vor SP2 System, daher kann ich es nicht versuchen. Wenn es Exe-Header-Flags gibt, die verhindern, dass die Exe selbst auf solchen Systemen gestartet wird, sollten sie einfach zu ändern sein.


Sumas Lösung sah ziemlich vielversprechend aus, aber es funktioniert nicht: Die __imp__*@4 Symbole müssen eher Zeiger auf Funktionen als auf die Funktionen selbst sein. Leider weiß ich nicht, wie man Visual C ++ dazu bringt, einen Zeiger mit dieser Art von Namensgenerierung auszuspucken ... ( __declspec(naked) , __declspec(naked) kombiniert mit __stdcall macht den Trick, aber dann weiß ich nicht, wie ich einen ausgeben soll Zeiger).

Wenn die Verwendung eines Assemblers zur Build-Zeit in Ordnung ist, ist die Lösung ziemlich trivial - den folgenden Code mit FASM kompilieren und mit der erzeugten Objektdatei verknüpfen, und presto - keine EncodePointer / DecodePointer-Referenzen in der EXE:

use32
format ms coff

section ".data" data
public [email protected]
[email protected] dd dummy

public [email protected]
[email protected] dd dummy

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






visual-studio-2008