return(STATUS_SUCCESS);
}
-
-static NTSTATUS
-LdrpCreateStack(HANDLE ProcessHandle,
- PINITIAL_TEB InitialTeb)
+/*
+ FIXME: this sucks. Sucks sucks sucks. This code was duplicated, if you can
+ believe it, in four different places - excluding this, and twice in the two
+ DLLs that contained it (kernel32.dll and ntdll.dll). As much as I'd like to
+ rip the whole RTL out of ntdll.dll and ntoskrnl.exe and into its own static
+ library, ntoskrnl.exe is built separatedly from the rest of ReactOS, coming
+ with its own linker scripts and specifications, and, save for changes and fixes
+ to make it at least compile, I'm not going to touch any of it. If you feel
+ brave enough, you're welcome [KJK::Hyperion]
+*/
+static NTSTATUS LdrpCreateStack
+(
+ HANDLE ProcessHandle,
+ PUSER_STACK UserStack,
+ PULONG_PTR StackReserve,
+ PULONG_PTR StackCommit
+)
{
- ULONG OldPageProtection;
- NTSTATUS Status;
-
- InitialTeb->StackAllocate = NULL;
-
- /* Allocate the reserved stack space */
- Status = NtAllocateVirtualMemory(ProcessHandle,
- &InitialTeb->StackAllocate,
- 0,
- &InitialTeb->StackReserve,
- MEM_RESERVE,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Stack allocation failed (Status %x)", Status);
- return(Status);
- }
-
- DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
- InitialTeb->StackAllocate, InitialTeb->StackReserve);
-
- InitialTeb->StackBase = (PVOID)((ULONG)InitialTeb->StackAllocate + InitialTeb->StackReserve);
- InitialTeb->StackLimit = (PVOID)((ULONG)InitialTeb->StackBase - InitialTeb->StackCommit);
-
- DPRINT("StackBase: %p StackCommit: 0x%lX\n",
- InitialTeb->StackBase, InitialTeb->StackCommit);
-
- /* Commit stack */
- Status = NtAllocateVirtualMemory(ProcessHandle,
- &InitialTeb->StackLimit,
- 0,
- &InitialTeb->StackCommit,
- MEM_COMMIT,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Error comitting stack page!\n");
- /* release the stack space */
- NtFreeVirtualMemory(ProcessHandle,
- InitialTeb->StackAllocate,
- &InitialTeb->StackReserve,
- MEM_RELEASE);
- return(Status);
- }
-
- DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
- InitialTeb->StackLimit,
- InitialTeb->StackCommit);
-
- /* Protect guard page */
- Status = NtProtectVirtualMemory(ProcessHandle,
- InitialTeb->StackLimit,
- PAGE_SIZE,
- PAGE_GUARD | PAGE_READWRITE,
- &OldPageProtection);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Error protecting guard page!\n");
-
- /* release the stack space */
- NtFreeVirtualMemory(ProcessHandle,
- InitialTeb->StackAllocate,
- &InitialTeb->StackReserve,
- MEM_RELEASE);
- return(Status);
- }
-
- return(STATUS_SUCCESS);
+ PVOID pStackLowest = NULL;
+ ULONG_PTR nSize = 0;
+ NTSTATUS nErrCode;
+
+ if(StackReserve == NULL || StackCommit == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ /* FIXME: no SEH, no guard pages */
+ *StackCommit = *StackReserve;
+
+ UserStack->FixedStackBase = NULL;
+ UserStack->FixedStackLimit = NULL;
+ UserStack->ExpandableStackBase = NULL;
+ UserStack->ExpandableStackLimit = NULL;
+ UserStack->ExpandableStackBottom = NULL;
+
+ /* FIXME: this code assumes a stack growing downwards */
+ /* fixed stack */
+ if(*StackCommit == *StackReserve)
+ {
+ DPRINT("Fixed stack\n");
+
+ UserStack->FixedStackLimit = NULL;
+
+ /* allocate the stack */
+ nErrCode = NtAllocateVirtualMemory
+ (
+ ProcessHandle,
+ &(UserStack->FixedStackLimit),
+ 0,
+ StackReserve,
+ MEM_RESERVE | MEM_COMMIT,
+ PAGE_READWRITE
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) return nErrCode;
+
+ /* store the highest (first) address of the stack */
+ UserStack->FixedStackBase =
+ (PUCHAR)(UserStack->FixedStackLimit) + *StackReserve;
+ }
+ /* expandable stack */
+ else
+ {
+ ULONG_PTR nGuardSize = PAGE_SIZE;
+ PVOID pGuardBase;
+
+ DPRINT("Expandable stack\n");
+
+ UserStack->FixedStackLimit = NULL;
+ UserStack->FixedStackBase = NULL;
+ UserStack->ExpandableStackBottom = NULL;
+
+ /* reserve the stack */
+ nErrCode = NtAllocateVirtualMemory
+ (
+ ProcessHandle,
+ &(UserStack->ExpandableStackBottom),
+ 0,
+ StackReserve,
+ MEM_RESERVE,
+ PAGE_READWRITE
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) return nErrCode;
+
+ DPRINT("Reserved %08X bytes\n", *StackReserve);
+
+ /* expandable stack base - the highest address of the stack */
+ UserStack->ExpandableStackBase =
+ (PUCHAR)(UserStack->ExpandableStackBottom) + *StackReserve;
+
+ /* expandable stack limit - the lowest committed address of the stack */
+ UserStack->ExpandableStackLimit =
+ (PUCHAR)(UserStack->ExpandableStackBase) - *StackCommit;
+
+ DPRINT("Stack base %p\n", UserStack->ExpandableStackBase);
+ DPRINT("Stack limit %p\n", UserStack->ExpandableStackLimit);
+
+ /* commit as much stack as requested */
+ nErrCode = NtAllocateVirtualMemory
+ (
+ ProcessHandle,
+ &(UserStack->ExpandableStackLimit),
+ 0,
+ StackCommit,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
+
+ DPRINT("Stack limit %p\n", UserStack->ExpandableStackLimit);
+
+ pGuardBase = (PUCHAR)(UserStack->ExpandableStackLimit) - PAGE_SIZE;
+
+ DPRINT("Guard base %p\n", UserStack->ExpandableStackBase);
+
+ /* set up the guard page */
+ nErrCode = NtAllocateVirtualMemory
+ (
+ ProcessHandle,
+ &pGuardBase,
+ 0,
+ &nGuardSize,
+ MEM_COMMIT,
+ PAGE_READWRITE | PAGE_GUARD
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
+
+ DPRINT("Guard base %p\n", UserStack->ExpandableStackBase);
+ }
+
+ return STATUS_SUCCESS;
+
+ /* cleanup in case of failure */
+l_Cleanup:
+ if(UserStack->FixedStackLimit)
+ pStackLowest = UserStack->FixedStackLimit;
+ else if(UserStack->ExpandableStackBottom)
+ pStackLowest = UserStack->ExpandableStackBottom;
+
+ /* free the stack, if it was allocated */
+ if(pStackLowest != NULL)
+ NtFreeVirtualMemory(ProcessHandle, &pStackLowest, &nSize, MEM_RELEASE);
+
+ return nErrCode;
}
UNICODE_STRING ImagePath;
HANDLE SectionHandle;
CONTEXT Context;
- INITIAL_TEB InitialTeb;
+ USER_STACK UserStack;
+ ULONG_PTR nStackReserve = 0;
+ ULONG_PTR nStackCommit = 0;
+ PVOID pStackLowest;
+ PVOID pStackBase;
ULONG ResultLength;
PVOID ImageBaseAddress;
ULONG InitialStack[5];
/* Calculate initial stack sizes */
if (Sii.StackReserve > 0x100000)
- InitialTeb.StackReserve = Sii.StackReserve;
+ nStackReserve = Sii.StackReserve;
else
- InitialTeb.StackReserve = 0x100000; /* 1MByte */
+ nStackReserve = 0x100000; /* 1MByte */
/* FIXME */
#if 0
if (Sii.StackCommit > PAGE_SIZE)
- InitialTeb.StackCommit = Sii.StackCommit;
+ nStackCommit = Sii.StackCommit;
else
- InitialTeb.StackCommit = PAGE_SIZE;
+ nStackCommit = PAGE_SIZE;
#endif
- InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
+ nStackCommit = nStackReserve - PAGE_SIZE;
- /* add guard page size */
- InitialTeb.StackCommit += PAGE_SIZE;
DPRINT("StackReserve 0x%lX StackCommit 0x%lX\n",
- InitialTeb.StackReserve, InitialTeb.StackCommit);
+ nStackReserve, nStackCommit);
/* Create the process stack */
- Status = LdrpCreateStack(*ProcessHandle,
- &InitialTeb);
+ Status = LdrpCreateStack
+ (
+ *ProcessHandle,
+ &UserStack,
+ &nStackReserve,
+ &nStackCommit
+ );
+
if (!NT_SUCCESS(Status))
{
DPRINT("Failed to write initial stack.\n");
return(Status);
}
+ if(UserStack.FixedStackBase && UserStack.FixedStackLimit)
+ {
+ pStackBase = UserStack.FixedStackBase;
+ pStackLowest = UserStack.FixedStackLimit;
+ }
+ else
+ {
+ pStackBase = UserStack.ExpandableStackBase;
+ pStackLowest = UserStack.ExpandableStackBottom;
+ }
+
+ DPRINT("pStackBase = %p\n", pStackBase);
+ DPRINT("pStackLowest = %p\n", pStackLowest);
/*
* Initialize context to point to LdrStartup
*/
+#if defined(_M_IX86)
memset(&Context,0,sizeof(CONTEXT));
- Context.Eip = (ULONG)(ImageBaseAddress + (ULONG)Sii.EntryPoint);
+ Context.ContextFlags = CONTEXT_FULL;
+ Context.FloatSave.ControlWord = 0xffff037f;
+ Context.FloatSave.StatusWord = 0xffff0000;
+ Context.FloatSave.TagWord = 0xffffffff;
+ Context.FloatSave.DataSelector = 0xffff0000;
+ Context.Eip = (ULONG_PTR)(ImageBaseAddress + (ULONG_PTR)Sii.EntryPoint);
Context.SegCs = USER_CS;
Context.SegDs = USER_DS;
Context.SegEs = USER_DS;
Context.SegGs = USER_DS;
Context.SegSs = USER_DS;
Context.EFlags = 0x202;
- Context.Esp = (ULONG)InitialTeb.StackBase - 20;
+ Context.Esp = (ULONG_PTR)pStackBase - 20;
+#else
+#error Unsupported architecture
+#endif
/*
* Write in the initial stack.
&ResultLength);
if (!NT_SUCCESS(Status))
{
+ ULONG_PTR nSize = 0;
+
DPRINT("Failed to write initial stack.\n");
NtFreeVirtualMemory(*ProcessHandle,
- InitialTeb.StackAllocate,
- &InitialTeb.StackReserve,
+ pStackLowest,
+ &nSize,
MEM_RELEASE);
NtClose(*ProcessHandle);
return(Status);
*ProcessHandle,
NULL,
&Context,
- &InitialTeb,
+ &UserStack,
FALSE);
if (!NT_SUCCESS(Status))
{
+ ULONG_PTR nSize = 0;
+
DPRINT("NtCreateThread() failed (Status %lx)\n", Status);
NtFreeVirtualMemory(*ProcessHandle,
- InitialTeb.StackAllocate,
- &InitialTeb.StackReserve,
+ pStackLowest,
+ &nSize,
MEM_RELEASE);
NtClose(*ProcessHandle);