KetilO,

I've been experimenting with your SpreadSheet tool, and it is just what I need for a project I'm working on. But I've run into a problem.

I'm running on Win95, using RadASM 2.0.2.1, with MASM32 V8. I wrote a stand alone masm program to do what I want, and it worked perfectly. When I incorporated the code into the main project I get an error if I try to type or press enter in any cell of the sheet. The spreadsheet opens fine, I programatically add text, numbers, and formulas into cells and then do a recalculate and everything works fine. At this point I can use the arrow keys, page up, page down, and navigate with the mouse. But as soon as press a number, letter, or the enter key I get the following error:

SEED(TRACK) caused an invalid page fault in
module SPRSHT.DLL at 0137:00fd7ae3.
Registers:
EAX=00000000 CS=0137 EIP=00fd7ae3 EFLGS=00010203
EBX=0069d7d2 SS=013f ESP=0069bf70 EBP=0069d780
ECX=00000000 DS=013f ESI=000087f6 FS=5977
EDX=00008812 ES=013f EDI=0069d788 GS=12bf
Bytes at CS:EIP:
53 56 8b 45 0c 83 f8 08 75 28 e8 7a 00 00 00 e8
Stack dump:


Do you have any idea why this might happen? I've examined the code and can't find any of the "usual suspects" and as I said it works fine as a stand alone program. I've tried to use OllyDbg but was unable to trace into the SPRSHT.dll program.

Thanks for our help!

Thanks for RadASM!

Thanks for the SpreadSheet Tool!

farrier

Answering my own question:

This is the code where it crashes:


10007ADA 55 push ebp
10007ADB 8BEC mov ebp,esp
10007ADD 81C4F0E7FFFF add esp,0FFFFE7F0h
10007AE3 53 push ebx
10007AE4 56 push esi
10007AE5 8B450C mov eax,[ebp+0Ch]
10007AE8 83F808 cmp eax,8
10007AEB 7528 jnz loc_10007B15
10007AED E87A000000 call fn_10007B6C


the offending instruction is push ebx, right after adding 6160 to the stack pointer. So I'm going to assume I've gone past my allotted stack space. Now I need to discover how to increase the stack space! Using the search button, now!

farrier
Posted on 2003-05-26 02:02:15 by farrier
Hi farrier

Only thing I can think of. Are you using WM_NOTIFY in your project?
Also the spread sheet allocates a fixed chunk of memory. Are you having a lot of data in your sheet?

KetilO
Posted on 2003-05-26 03:04:44 by KetilO
Thanks KetilO,

It was a problem with not enough stack space. Thanks to posts from f0dder and
donkey I was able to determine what the stack size is and how to set it in RadASM.

In f0dder ' s post from http://www.asmcommunity.net/board/index.php?topic=1462&highlight=link+stack
I used:



assume FS:nothing
push dword ptr FS:08
pop eax
PrintDec eax
;Address limit for stack
push dword ptr FS:04
pop eax
PrintDec eax
;Beginning stack address


And using donkey ' s suggestions from http://www.asmcommunity.net/board/showthread.php?s=&postid=104265.msg104265
I changed the Project/Project Options/Link options to include:

/Stack:65536|65536

Both values /Stack:Reserve,Commit were required, and the comma had to be replaced with the pipe '|' symbol to make it through RadASM.

By the way the default value for committed stack was 8192

farrier
Posted on 2003-05-26 05:36:28 by farrier
Farrier,

You don't add to the stack, you substract from the stack.
Even local variables are accessed by allocating a portion on the stack for them (notice the sub esp,xxx at the start of the proc which you have local variables).
If you need to allocate 2048bytes you do soemthing like



sub esp,2048
mov esi,esp
...
add esp,2048;clear up the stack
Posted on 2003-06-01 04:46:08 by roticv
roticv,

Thanks for the reply! I'm familiar with how the stack works. What I meant to say was "right after adding -6160 to the stack pointer."

10007ADD 81C4F0E7FFFF           add     esp,0FFFFE7F0h


This is the original asm code from KetilO's SpreadSheet DLL code, from the file SprSht.asm:



EditProc proc uses ebx esi,hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL buffer[2048]:BYTE
LOCAL buffer1[4096]:BYTE
LOCAL spredt:SPR_EDIT

mov eax,uMsg
.if eax==WM_KILLFOCUS
...


My problem seems to be with the default stack size in my program, on my machine. The default size came out to be just 8K. When the 6160 byte "adjustment" was made to the stack pointer, it appears the next push "crossed the line" into memory I was not authorized to use. f0dder mentioned "touching" the reserved stack memory, in order to use it. I'm not sure what he meant, or how to do it. Does anyone know what he meant?

farrier
Posted on 2003-06-01 05:08:37 by farrier
What about try emailing him? Or maybe finding him on #win32asm EFnet.
Posted on 2003-06-01 05:31:17 by roticv
The only place I have seen pre-touching is in discussions about processor architecture (closely allied to pre-fetch), it involves moving data into the cache without tying up registers. Can't say that I really understood the concept though. Best bet is to do what roticv said and email f0dder, he has said that he will reply to email questions.
Posted on 2003-06-01 05:41:11 by donkey
This was in an MMX paper I got from intel a while back, it defines pre-touching data:
Pre-fetching data several clocks before the instructions that actually use it. By putting one MOV reg, mem instruction in a loop, and incrementing the memory address by 32 every time, entire 32-byte cache lines will be loaded into the cache. Then subsequent uses of that data within the loop or in the next code sequence get cache hits. Of course, this technique of data "pre-touching" works well only if the algorithm can find something useful for the CPU to do during the prefetching time, which does not involve writes to memory, such as shifts or multiplies. One experiment showed a simple loop of loads and stores (using MOVQ) got only 58 MBytes/sec in a naive implementation. But with pre-touching, it increased to 96 MBytes/sec.
How this is related to f0dders stuff I don't know.
Posted on 2003-06-01 06:17:42 by donkey
A guard page is set-up to notify the operating system that more memory is needed for the stack - when an access to this 4K page is made a signal is sent. Search the API for gaurd pages, or look under the memory management functions.

Pre-touching can be done in many ways - I like to use the ENTER instruction because it backs the stack up and accesses the memory.
enter	_STACK_TOUCH_INTERVAL_ - 4, 0
Here is the logic from one of my macros:
;; 'touch' the stack when locals are greaterthan _STACK_TOUCH_INTERVAL_


IF lbytes GE _STACK_TOUCH_INTERVAL_
y = lbytes
WHILE y GE _STACK_TOUCH_INTERVAL_
enter _STACK_TOUCH_INTERVAL_ - 4,0
y = y - _STACK_TOUCH_INTERVAL_
ENDM
IF y NE 0
sub esp,y
ENDIF
;; fix ebp to equal old esp
lea ebp,[esp + lbytes]
ELSE
enter lbytes,0
ENDIF
...it ensures that lbytes is availible on the stack.
Posted on 2003-06-01 09:17:45 by bitRAKE
Thanks!

bitRAKE,
donkey,
roticv,
KetilO

I'll look into these methods and report anything I find.

I'm still curious if 8K is the standard size for the Win95 stack and larger for other Win versions?

Thanks for the help!

farrier
Posted on 2003-06-02 00:05:35 by farrier
Hi farrier

A new version of the custom control has been uploaded to my web site.
The new version should avoid this problem.

KetilO
Posted on 2003-06-02 05:50:45 by KetilO
Hi all

Yet another new version of the custom control has been uploaded to my web site.
A cell calculation bug has been fixed.

KetilO
Posted on 2003-06-03 09:22:24 by KetilO
Thanks KetilO,

Thanks for all your help!!!

To follow-up on my original problem:

My program experienced a problem with the stack, when 6162 bytes worth of local variables were declared. That didn't seem like a lot to me, and made me wonder about the stack as I never had before--mainly because I never ran into a stack problem before.

Writing a simple program to determine the state of the stack:

	assume		FS:nothing


mov eax, dword ptr FS:08
mov ebx, dword ptr FS:04

PrintDec eax
PrintDec ebx

sub ebx, eax
invoke dwtoa, ebx, addr lpstacksize

invoke GetModuleHandle, NULL
mov hInstance,eax

invoke MessageBox, hInstance, addr lpstacksize, addr SS_caption, MB_OK

invoke ExitProcess,eax


The message box reported 8192 bytes between the starting point for the stack and the stack limit. This might explain why my program bombed when the local varialbles were declared, they crossed the 8192 byte limit. When I disassembled my program using the Dis-assemble EXE file option under the Tools menu in Hutch--'s Quick Editor program, I found the following values reported:

Size Of Stack Reserve 00100000
Size Of Stack Commit 00001000

1 MEG reserved stack
4 K commited stack

So it seems that the amount of stack commited was the cause of the error. I had tried to use the /STACK switch of the MASM linker to increase the reserved amount of stack, but that never helped. I included the commit option, /STACK:65535,65536 which actually reduced the amount of reserved stack, but increased the amount of commited stack. The increase in the amount of commited stack allowed the program to work.

I then wrote a procedure which allocated the same amount of stack space as KetilO's spreadsheet program and no error was generated. I created a proc which declared a LOCAL array of 6162 bytes--the original amount allocated--and increased the size of the array until the program bombed:


stack_check proc uses ebx esi
;the 'uses ebx esi' is where the program bombs,
;when it tries to save ebx with: push ebx
LOCAL buffer[11824]:BYTE
ret
stack_check endp


The size of the LOCAL array could be increased to 11824 bytes before the program bombed at 11825 bytes. The stack limit address was reported as 63e000h and the value of ESP when the program bombed was 63d000h which crossed a 4096 byte boundary.

NAN's stack test program:

	mov eax, esp

PrintHex eax, "Start ESP"
@@:
push eax
jmp @B


runs fine inline with the main program--or in a proc--until ESP differed from starting stack address by fd000h (1,036,288) not quite 1Meg. It appears that if the stack is approached 1 DWORD at a time you can use just about all of the 1 MEG reserved for the stack. According to Jeremy Gordon--of GoAsm fame--http://www.jorgon.freeserve.co.uk/GoasmHelp/usstack2.htm#enlarge, accesses to the stack cannot cross the current commited stack areas plus the page size--4096 bytes--without causing an exception. This may explain the program bombing when an attempt was made to allocate 11,825 bytes of local array, causing the stack limit to be exceeded by 4096 bytes.

Using ENTER and LEAVE within the procedure did not prevent the program from bombing, because we were still exceeding the commited stack space by more than 4096 bytes.

So now we have to "touch" the stack, to commit more stack memory. Using Jeremy's code:

	MOV	ECX,10

L0:
SUB ESP,1000h
MOV D[ESP],0 ;MOV DWORD ptr ESP, 0
LOOP L0

And adding:
ADD ESP, 0a000h

to correct the stack, ten 4K page of stack have been commited and allow the stack to grow in "large chunks" The code to "touch" the stack would be called just before the procedure requiring large chunks of local variables. As Jeremy says, it would be preferable to commit the stack at link time, but in my case the error occured within KetilO's DLL and I had no idea what sort of LOCAL variables were being declared. So maybe the solution here would be to "touch" two 4K pages in KetilO's DLL just before calling the proc requiring lots of LOCAL variables.

farrier
Posted on 2003-06-04 15:58:22 by farrier