// Normalerweise wäre _alloca(size_t) ein simples "sub esp,eax".
// Aber das Win32-Speicherlayout macht einen Strich durch die Rechnung und verlangt,
// dass der Stack Seite für Seite abwärts belegt wird.
// Sonst kommt eine Schutzverletzung.
// Oder man legt per Linker-Schalter ein reichliches Commit für den Stack fest. (Geht das??)
// Daher generiert der Compiler für _alloca() sowie für Funktionen mit mehr als 4 KByte
// lokale Variablen einen Aufruf dieser Funktion.
// Prinzipiell könnte diese eax/4 push-Befehle ausführen …
// PE: eax = Zu reservierende Bytes
// PA: esp = Anfang des Speicherbereiches
// VR: eax
#define PROC void _declspec(naked) _cdecl
void _cdecl _chkstk();
#if _MSC_VER >= 1400
// Umstandskasten MSVC2008: Unpassende stdio.h, unpassend zu msvcrt.dll
#include <stdio.h>
_CRTIMP extern FILE _iob[]; // msvcrt.dll bietet Datenexport: Zeiger auf 3× FILE-struct
static FILE*_cdecl my_iob() {return _iob;} // stdio.h erwartet dito als Funktionsesport
// Einen Zeiger auf _iob_func() anbieten, Zeiger weil DLL-Bindung
const FILE*(_cdecl*_imp____iob_func)() = my_iob;
PROC _alloca_probe_16() {_asm{ // außerdem heißt's nicht _alloca_probe sondern _alloca_probe_16
jmp _chkstk // und der Compiler generiert INT3 statt nichts
}}
#else
PROC _alloca_probe() {_asm{ // MSVC6 läuft ohne weiteren Opcode hinein? Nicht ohne /debug!
jmp _chkstk
}}
#endif
PROC _chkstk() {_asm{
add eax,3
and al,~3 // Teilbarkeit durch 4 sicherstellen
push ecx
lea ecx,[esp]+8 // ecx = Endadresse auf Stack
jmp short testpg
onepg: sub ecx,4096
sub eax,4096
test dword ptr [ecx],eax // seitenweise Speicherlesezyklus anstoßen
testpg: cmp eax,4096
jae short onepg
sub ecx,eax // ecx = Startadresse auf Stack
mov eax,esp // eax = Zeiger auf ursprüngliches ecx
test dword ptr [ecx],eax // nochmal Speicherlesezyklus
mov esp,ecx // esp = Startadresse (Rückgabewert)
mov ecx,[eax] // ecx restaurieren
jmp dword ptr[eax+4]// Rücksprung zum Aufrufer
}}
PROC _aullshr() {_asm{
btr ecx,5
jc short l1 // Für Schiebelängen >= 32 ohne shrd
shrd eax,edx,cl
shr edx,cl
ret
l1: mov eax,edx
xor edx,edx
shr eax,cl
ret
}}
PROC _allshl() {_asm{
btr ecx,5
jc short l1 // Für Schiebelängen >= 32 ohne shld
shld edx,eax,cl
shl eax,cl
ret
l1: mov edx,eax
xor eax,eax
shl edx,cl
ret
}}
PROC _allmul() {_asm{
mov eax,[esp+8] // hi(f1)
mov ecx,[esp+16] // hi(f2)
or ecx,eax
mov ecx,[esp+12] // lo(f2)
jnz short l1
mov eax,[esp+4] // lo(f1)
mul ecx // edx:eax = lo(f2)×lo(f1)
ret 16
l1: push ebx
mul ecx // (edx:)eax = lo(f2)×hi(f1)
mov ebx,eax
mov eax,[esp+8] // lo(f1)
mul dword ptr[esp+20]// (edx:)eax = lo(f1)×hi(f2)
add ebx,eax
mov eax,[esp+8]
mul ecx // edx:eax = lo(f2)×lo(f1)
add edx,ebx
pop ebx
ret 16
}}
// Hier: Nur für DWORD-Divisor!
PROC _aulldiv() {_asm{
mov eax,[esp+8] //High-Teil Zähler
mov ecx,[esp+12] //Nenner
xor edx,edx
div ecx //EAX=Ergebnis, EDX=Rest
push eax
mov eax,[esp+8] //Low-Teil Zähler
div ecx //EAX=Ergebnis, EDX=Rest
pop edx //Rest durch High-Teil ersetzen
ret 16
}}
Detected encoding: UTF-8 | 0
|